Project Arduino Sketch

Introduction

The Arduino sketch receives commands and returns data to the control program (written in Perl). The data returned is used by the control program to create displays, etc.

Note: See the comments in the sketch for documentation of the operations the sketch performs.

Sketch

// ================================================================
// Map a Grid using an ultrasonic Sensor
// ================================================================
//
// Respond to commands sent from a control program and return data
// if any.
//
// ----------------------------------------------------------------
//
// Commands:
//
// Spos1,pos2 -- Do a ping sweep from servo position 1 to servo
//               position 2 and return the resultant distances. 
//               A ping is done at each position including the
//               start and stop positions. The command format is
//               ['S' + starting servo position + "," +
//               servo end position]. For example, "S100,200".
//
//               The returned distances are in the format ['s'
//               + servo position + ',' + distance]. For example,
//               "s120,34".
// 
//               After the command ends, "x" is sent indicating
//               the end of the command.
//
// Mpos       -- Move the servo to a specified position.
//               The command format is ['M' + servo position].
//               For example, "M120".
//
//               After the command ends, "x" is sent indicating
//               the end of the command.
//
// P          -- Do a single ping for distance. The command format
//               is ['P']. The current servo position is used for
//               the ping.
//
//               The returned distance is in the format ['p'
//               + servo position + ',' + distance]. For example,
//               "p120,34".
//
//               After the command ends, "x" is sent indicating
//               the end of the command.
//
// C          -- Return the current position and distance.
//               The command format is ['C']. The returned
//               position and distance is in the format ['c' +
//               servo position + ',' + distance]. For example,
//               "c120,34".
//
//               After the command ends, "x" is sent indicating
//               the end of the command.
//
// Commands are an uppercase character + 0 or more parameters
// separated by commas. Responses (if any) are a lowercase
// character + 0 or more parameters separated by commas.
//
// ----------------------------------------------------------------
//
// Notes:
//
// 1. The distance zero (0) indicates no object was
//    detected within the range of the sensor.
//
// 2. The arduino "println" terminates each string sent to
//    the command program with a "\r\n". (See the Arduino
//    documentation for more information.)
//
// 3. Once a command has been recognized, it starts executing and
//    cannot be interrupted. After the command finishes executing
//    any characters in the input serial buffer are destroyed. 
//
// 4. If you do not have an LCD display, set LCDYES = 0 or remove
//    the LCD code.
//
// 5. This Arduino sketch does little to no error checking.
//    It is up to the command program to send the correct data
//    in the correct format.
//
// 6. If an unknown command is received, the control program is send
//    an error response. The error message format is
//    [the character 'e' + the command (character) in decimal
//    format]. For example, "e66".  Note: The command is in
//    decimal format because it may not be a printable character.
//
//    After the error response, the string "x" is sent indicating
//    the end of the command.
//
// ================================================================

#include <Servo.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#include <Ultrasonic.h>

// ================================================================
// housekeeping
//=================================================================

// ----------------------------------------------------------------
// defines
// ----------------------------------------------------------------

// serial port
// (300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400,
//  57600, 115200)

#define BAUDRATE      9600

// ultrasonic

#define  TRIG_PIN     12
#define  ECHO_PIN     13

// servo

#define SERVO_PIN     9

// LCD

#define I2C_ADDR      0x3F     // I2C Address
#define BACKLIGHT_PIN 3
#define RS_PIN        0
#define RW_PIN        1
#define EN_PIN        2
#define D4_PIN        4
#define D5_PIN        5
#define D6_PIN        6
#define D7_PIN        7
#define LCDYES        true     // LCD true/false flag

// ----------------------------------------------------------------
// objects and variables
// ----------------------------------------------------------------

Ultrasonic ultra(TRIG_PIN,ECHO_PIN);

LiquidCrystal_I2C lcd(I2C_ADDR,EN_PIN,RW_PIN,RS_PIN,
                      D4_PIN,D5_PIN,D6_PIN,D7_PIN);

Servo servo;

long dis      = 0;            // distance to object
int  pos      = 0;            // servo position
int  posStart = 0;            // servo start position
int  posEnd   = 0;            // servo end position
char cmd;                     // command

// ================================================================
// setup
//=================================================================

void setup()
{
   // initialize serial port

   Serial.begin(BAUDRATE);   

   // initialize servo

   servo.attach(SERVO_PIN);
   servo.write();

  // initialize LCD display

  if (LCDYES)
  {
     // initialize the lcd
     lcd.begin(2,4);  
     // Switch on the backlight
     lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
     lcd.setBacklight(HIGH);
     // set initial display
     lcd.home();
     lcd.print("Map a Grid");
     lcd.setCursor(,1);
     lcd.print("Dis ");
     lcd.setCursor(,2);
     lcd.print("Pos ");
     lcd.setCursor(,3);
     lcd.print("Cmd ");
   }
}

// ================================================================
// main loop
// ================================================================

void loop()
{
  // process serial input buffer ---------------------------------- 

  if (Serial.available())
  {
    // wait for the entire message to arrive ----------------------

    delay(20);           

    // get command ------------------------------------------------

    cmd = Serial.read();

    // ping sweep command -----------------------------------------

    if (cmd == 'S')
    {
      posStart = Serial.parseInt();
      posStart = constrain(posStart,0,179);
      posEnd   = Serial.parseInt();
      posEnd   = constrain(posEnd,0,179);
      lcdCommand(cmd);
      pingSweep(posStart,posEnd);
      Serial.println("x");
      Serial.flush();
    }

    // ping command -----------------------------------------------

    else if (cmd == 'P')
    {
      dis = pingDistance();
      lcdCommand(cmd); 
      lcdPingDistance(dis);
      Serial.print("p");
      Serial.print(pos,DEC);
      Serial.print(",");
      Serial.println(dis,DEC);
      Serial.println("x");
      Serial.flush();
    }    

    // move servo to a specified position command -----------------

    else if (cmd == 'M')
    {
      pos = Serial.parseInt();
      pos = constrain(pos,0,179);
      setServoPosition(pos);
      lcdCommand(cmd);
      lcdServoPosition(pos);
      Serial.print("m");
      Serial.println(pos,DEC);
      Serial.println("x");
      Serial.flush(); 
    }

    // current state command --------------------------------------

    else if (cmd == 'C')
    {
      lcdCommand(cmd); 
      Serial.print("c");
      Serial.print(pos,DEC);
      Serial.print(",");
      Serial.println(dis,DEC);
      Serial.println("x");
      Serial.flush();
    }

    // error ------------------------------------------------------

    else
    {
      Serial.print("e");
      Serial.println(cmd,DEC);
      Serial.println("x");
      Serial.flush();       
    }

    // remove the remaining characters in the buffer (if any) -----

    emptySerialInputBuffer();
  }

  // wait before checking for the next command --------------------

  delay(200);                  
}

// ================================================================
// subroutines
// ================================================================

// ----------------------------------------------------------------
// empty the serial input buffer
// ----------------------------------------------------------------

void emptySerialInputBuffer()
{
  while(Serial.read() != -1);
  return;
}

// ----------------------------------------------------------------
// get distance to an object (0 if no object)
// ----------------------------------------------------------------

long pingDistance()
{
  long d = ultra.Ranging(INC); // distance to object in inches
  d = constrain(d,0,255);      // constrain the distance
  delay(200);                  // let the echo dissipate
  return d;
}

// ----------------------------------------------------------------
// set the servo position
// ----------------------------------------------------------------

void setServoPosition(int pos)
{
  servo.write(pos);            // set servo position
  delay(200);                  // wait for servo to reach position
  return;
}


// ----------------------------------------------------------------
// ping sweep
// ----------------------------------------------------------------

void pingSweep(int start, int end)
{
  for(pos = start; pos <= end; pos++)
  {
    setServoPosition(pos);
    dis = pingDistance();
    lcdServoPosition(pos);
    lcdPingDistance(dis);
    Serial.print("s");
    Serial.print(pos,DEC);
    Serial.print(",");
    Serial.println(dis,DEC);
    Serial.flush();
  }
  return;
}

// ----------------------------------------------------------------
// display servo position
// ----------------------------------------------------------------

void lcdServoPosition(int pos)
{
  if (LCDYES)
  {
    lcd.setCursor(4,2);        // set cursor position
    lcd.print("     ");        // clear display
    lcd.setCursor(4,2);        // set cursor position
    lcd.print(pos,DEC);        // display servo position
  }
  return;
}

// ----------------------------------------------------------------
// display command
// ----------------------------------------------------------------

void lcdCommand(char cmd)
{
  if (LCDYES)
  {
    lcd.setCursor(4,3);        // set cursor position
    lcd.print("          ");   // clear display
    lcd.setCursor(4,3);        // set cursor position
    lcd.print(cmd);            // display command
  }
  return;
}

// ----------------------------------------------------------------
// display ping distance
// ----------------------------------------------------------------

void lcdPingDistance(long distance)
{
  if (LCDYES)
  {
    lcd.setCursor(4,1);        // set cursor position
    lcd.print("    ");         // clear display
    lcd.setCursor(4,1);        // set cursor position
    lcd.print(distance,DEC);   // display distance
  }
  return;
}