Saturday 14 April 2012

Going Remote

The Arduino IDE has been getting on my nerves and despite being cool, the chip itself isn't really powerful enough to do some of the things I want to do (like face recognition). Hence I'm going to take a quick step to turn my computer into the brain. This post is just code - it's about moving where the software runs.

We've already got all the sensors and SpeakJet connected so now I just add some utility functions to send and receive data over the serial interface:


void WaitForBytes(int count)
{
  while(Serial.available() < count) {}
}


int ReadWord()
{
  WaitForBytes(2);
  return Serial.read() | (Serial.read() << 8);
}


void WriteWord(int data)
{
    byte highbyte = data >> 8;
    byte lowbyte = data & 0xff;
    Serial.write(lowbyte);
    Serial.write(highbyte);
}


Create a list of potential commands:


enum ECommands
{
  COMMAND_KEEPALIVE,
  COMMAND_PING,
  COMMAND_MOTION,
  COMMAND_COMPASS,
  COMMAND_SAY,
  TOTAL_COMMANDS
};


Next I turn the loop into a switch statement that simply waits for a command id to be sent over remotely, acts on the command and finally sends a response:



/**
 */
void loop()

  if(Serial.available() > 0)
  {
    int command = Serial.read();
    switch(command)
    {
      case COMMAND_PING:
      {  
        int data = readUltraSound();
        WriteWord(data);
        break;
      }
      case COMMAND_MOTION:
      {  
        int data = readMotion();
        WriteWord(data);
        break;
      }
        //.............
        //Other commands here 
        //............
  }
}

Here you can see the ping test which takes an ultra sound reading then sends back a distance. The motion sensor does exactly the same thing, sending back a 1 if motion is detected, 0 if not. 

The speech command was a little more interesting, as the PC needed to be able to send what to say. My first version just takes a message length, followed by a series of bytes to send directly to the Speak Jet:

        int count = ReadWord();            //read byte count
        Serial.print("Say bytes: ");
        Serial.print(count);
        Serial.print(":");
        WaitForBytes(count);               //wait for message to arrive in full
        for(int i = 0; i < count; i++)
        {
          uint8_t data = Serial.read();    //read byte
          speakjet.AddByte(data);          //send directly to speak jet
          Serial.print(data);
          Serial.print(",");
        }
        speakjet.Wait();                   //wait for speech to finish
        Serial.println("");                //print newline to tell pc its done
        break;

Note that the final step is to wait until speech is complete and then a print a new line, which is allows the PC to block until speech is complete. If I need to get fancier I can add extra data, like whether to do the final wait and respond step.

The PC code is just communicating over a standard COM port. I decide to start with c# as it's quick and simple, and I don't have anything massively powerful in mind yet - it'll be easy to switch to C++ later though. (Will post a bit of code here soon). 

The advantage of this setup is that I can now easily write lots of prototype code on my PC, where the bulk of my robot's thinking will occur and I can monitor what's going on. The Arduino now acts as a slave to the PC, executing commands on demand. Algorithms that become time critical can be embedded as new commands.

That's about it for now. Eventually I'll connect via blu tooth, but some postal issues appear to have delayed my modem so we'll see. Next up, some motors.





 

No comments:

Post a Comment