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; }