Jump to content


Arduious Arduino


Recommended Posts

I got my Arduino last week so last night I started on programming it to control my Nikon DSLR via an IR LED rather than the shutter port as I have 3 cameras and only 1 has the port.

My my C is rusty! I do VB.NET every day for work and I suddenly realise how spoilt I am with the framework to do anything!  

I haven't had to manage my own buffers or null terminate a strings (well char arrays) for years.  All I achieved was a method to read in a command from serial into a buffer.  Now I am stuck at how to parse it, maybe I will have to crack out my old C programming book from uni that's held together with duct tape...

Hopefully this evening will be more productive.

Link to comment
Share on other sites

I am sure I can work it out just it was late and it's been about 10 years since I've done any C, as I said I use .NET for work so I am used to having things like the String class to hand.

Looks like strtok might do what I want but I'll probably have a read up on what the "correct" way to do this is in C.  In .net I'd just call String.Split  :grin:

Link to comment
Share on other sites

per I would be interested in seeing the protocol definition.  Right now I'm not sure how to structure it.  I know I want to send a exposure length, the gap between exposures, mirror lock up mode enable bit, number of iterations.  Right now it's just a string starting # ending ; with a , separated list of values in the middle.  I was thinking passing raw bytes but this may be more complicated than is actually needed.

Link to comment
Share on other sites

 In case you are interested, this is a simplified version of a Serial parser that I wrote to decode the Synta protocol. It is C++ which runs on an Arduino. I've put in a load of comments and some empty functions which you could build upon.

#define MAX_COMMAND_LENGTH (10 + 1) //number of characters + null.void loop(){  char decodedPacket[MAX_COMMAND_LENGTH]; //temporary store for completed command ready to be processed  if (Serial.available()) { //is there a byte in buffer    char recievedChar = Serial.read(); //get the next character in buffer    char decoded = recieveCommand(decodedPacket,recievedChar); //once full command packet recieved    if (decoded == 1){ //Valid Packet      decodeCommand(decodedPacket,strlen(decodedPacket)); //decode the valid packet    } else if (decoded == -1){ //Error      /* //Optional error response:      Serial.print(decodedPacket); //send the error packet (recieveCommand() already generated the error packet      */    } //otherwise command not yet fully recieved, so wait for next byte  }}void decodeCommand(char* dataPacket, unsigned int length){  //do something with the data. You could use STRTOK for comma seperated values. Google       /*   //Optional: simple packet to say response received?  char response[3]; //generated response string  assembleResponse(response); //generate correct response  Serial.print(response); //send response to the serial port   */}const char startInChar = '#'; //start of recieved packet markerconst char startOutChar = '='; //start of response packet marker if neededconst char errorChar = '!'; //start of error packet markerconst char endChar = ';'; //end of packet markerboolean validPacket = false; //stores whether we are currently decoding a packetchar commandString[MAX_COMMAND_LENGTH] = {0}; //stores the string being recievedbyte commandIndex = 0; //stores the current index in the commandString./* void assembleResponse (char* resp){ //optional function to generate response.  resp[0] = startOutChar;  resp[0] = endChar;  resp[0] = '\0';} */void error(char* buf){ //This generates a packet that says that an error in decoding occurred  buf[0] = errorChar;  buf[1] = endChar;  buf[2] = 0;}void clearBuffer(char* buf, byte len){  strncpy(buf,"",len); //fills entire buffer with '\0'}char recieveCommand(char* dataPacket, char character){  if(validPacket){    if (character == startInChar){      goto error; //new command without old finishing! (dataPacket will be made to contain error message)    }        commandString[commandIndex++] = character; //Add character to current string and increment index        if(character == endChar){ //reached the end of the incoming packet.      if(validateCommand(commandIndex)){ //make sure the command is valid        strcpy(dataPacket,commandString); //Return decoded packet        validPacket = false; //finished decoding packet.        return 1; //Successful decode (dataPacket contains decoded packet)      } else {        goto error; //Decode Failed (dataPacket will be made to contain error message)      }    } else if (commandIndex == MAX_COMMAND_LENGTH){      goto error; //Message too long! (dataPacket will be made to contain error message)    }  } else if (character == startInChar){    //Begin new command    commandIndex = 0; //back to start of command buffer (note: start character is not stored in buffer!)    validPacket = true;    clearBuffer(commandString,MAX_COMMAND_LENGTH); //clear the buffer  }  return 0; //Decode not finished (dataPacket unchanged)error:  error(dataPacket);  validPacket = false;  return -1;}boolean validateCommand(byte len){    //Check that command is valid? Packet the correct length    if(     ){ //If invalid command. E.g. is len < required Length.    return false; //invalid  }    //Extract data from command, e.g:  /*  //in this example, the first two bytes identified the type  //of command recieved.  byte i;   for(i = 0;i < commandLength(commandString[0]);i++){    commandString[i] = commandString[i + 2]; //so we only need the bytes after the command id.  }  commandString[i] = '\0' ; //Append Null */      //If you are just using comma seperated values, then this isn't needed, and you can simply do:    //commandString[len-1] = '\0' ; //Replace endChar with NULL.    return true; //valid}
  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

Spent some more time on this last night. I now have a sketch that can cleanly (and without blocking) read the serial input and act in a basic way on it. I also have a mac app to control it with which is half done, just need to add the serial commands to it (might be a basic popen() terminal command to start)

I will be ordering a nano, perf board and a case for it all on pay day to allow me to build a final device.

Link to comment
Share on other sites

Phidgets and TinkerForge boards support VB.NET so you may look at them too.

There's also NETduino but all the .Net boards are rather pricey and way over the top for the needs of this project.  

Did manage to get somewhere Saturday evening.  I have a decode routine in place now but there's a couple of bugs in there which mean the initialisation is wrong which causes odd results.  I was starting to debug this on Sunday morning but the wife had better ideas and decided we needed to completely reorganise upstairs (twins on the way and they need some where to sleep).  Will have another bash at this this evening.

I started a github repo as a back up of the code here: https://github.com/themaninthesuitcase/IRCameraController It's not completely up to date but has the beginnings are there (ie non of the decode is there).  I will update this better once the code is completed and working, I will also add a bit of documentation. 

Link to comment
Share on other sites

If you're still stuck on ways to parse serial data and want to send raw comma-separated data then try the TextFinder library, by Michael Margolis (get it here: http://forum.arduino.cc/index.php?topic=39384.0). I wrote a desktop application (in BBC Basic!) which sends a 7-item string to an Arduino, which then assigns variables to each item. The pertinent bits of code look like this:

Before Setup:

#include <TextFinder.h>

int (YourVariable1) = 0;

int (YourVariable2) = 0;

int (YourVariable3) = 0;

int (YourVariable4) = 0;

int (YourVariable5) = 0;

int (YourVariable6) = 0;

int (YourVariable7) = 0;

TextFinder finder(Serial);
const int NUMBER_OF_FIELDS = 7; // how many comma-separated fields we expect
int fieldIndex = 0; // the current field being received
int values[NUMBER_OF_FIELDS]; // array holding values for all the fields

... and in the main loop:

  for(fieldIndex = 0; fieldIndex < 7; fieldIndex ++)
    values[fieldIndex] = finder.getValue(); // get a numeric value


  for(int h=0; h < fieldIndex; h++)
    if (h == 0) YourVariable1 = (values[h]);
    if (h == 1) YourVariable2 = (values[h]);
    if (h == 2) YourVariable3 = (values[h]);
    if (h == 3) YourVariable4 = (values[h]);
    if (h == 4) YourVariable5 = (values[h]);
    if (h == 5) YourVariable6 = (values[h]);
    if (h == 6) YourVariable7 = (values[h]);

... then at the end of the main loop:

fieldIndex = 0;

My project operates the camera shutter too, and I use a Nikon dSLR with an IR remote. I found it more convenient to set and control the timing from the desktop app, just sending a single command to operate the shutter and a second one to close it (I hacked a cheapo Nikon IR control to do this, closing the circuit using a relay). It turns out that it's even easier to trip the shutter, using another library: MultiCameraIRControl, by Sebastian Setz (get it, and instructions, here: http://sebastian.setz.name/arduino/my-libraries/multi-camera-ir-control/). You'll need an IR LED and a resistor, but it enables you to build your own IR remote for many popular dSLR cameras.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. By using this site, you agree to our Terms of Use.