Original NeuroRobot Code

Good day!

This is the original code that I inherited, and that I’ve been using as a reference as I write code for the neurorobot_reboot. In particular, I really wanted to simplify, simplify, simplify, and use shorter (clearer) variables along with comments so the code as a whole is easier to understand. I hadn’t really done much fancy stuff beyond methods before, though, so inheriting this has taught me some cool new techniques, like how to create classes in Arduino. 😀

So I’m just going to paste it in…

//NEUROROBOT_ORIGINAL_CODE

//#include <EnableInterrupt.h>
 // Serial: 0 (RX) and 1 (TX); Serial 1: 19 (RX) and 18 (TX);
 // Serial 2: 17 (RX) and 16 (TX); Serial 3: 15 (RX) and 14 (TX).
 // External Interrupts: 2 (interrupt 0), 3 (interrupt 1),
 // 18 (interrupt 5), 19 (interrupt 4), 20 (interrupt 3), and 21 (interrupt 2)
 // PWM: 2 to 13 and 44 to 46
 // SPI: 50 (MISO), 51 (MOSI), 52 (SCK), 53 (SS)
 // LED: 13
 // I2C: 20 (SDA) and 21 (SCL)



#define COMMAND_START '@'
 #define PARAMETER_SEPARATOR ':'

#define PIN_LED 13
 #define PIN_RIGHT_ENABLE 7
 #define PIN_RIGHT_FORWARD 5
 #define PIN_RIGHT_BACKWARD 6
 #define PIN_LEFT_ENABLE 2
 #define PIN_LEFT_FORWARD 3
 #define PIN_LEFT_BACKWARD 4
 //#define PIN_LEFT_ECHO 24
 //#define PIN_LEFT_PING 23
 //#define PIN_FRONT_ECHO 26
 //#define PIN_FRONT_PING 25
 //#define PIN_RIGHT_ECHO 28
 //#define PIN_RIGHT_PING 27
 #define PIN_RIGHT_ECHO 30
 #define PIN_RIGHT_PING 29
 #define PIN_FRONT_ECHO 32
 #define PIN_FRONT_PING 31
 #define PIN_LEFT_ECHO 33
 #define PIN_LEFT_PING 34

#define PIN_HALL_R_A 44
 #define PIN_HALL_R_B 45

#define PIN_HALL_L_A 46
 #define PIN_HALL_L_B 47

#define SPEED_LIMIT 60
 #define TURN_SPEED 120
 #define RANGE_SHORT 25
 #define RANGE_MED 35
 #define RANGE_LONG 45



boolean DEBUG = false;

class Command {
 public:
 int right_speed;
 int left_speed;
 Command() :right_speed(0), left_speed(0)
 {}
 void parseCommand() {
 while(char inchar = Serial.read() != COMMAND_START) {}
 right_speed = Serial.parseInt();
 left_speed = Serial.parseInt();
 Serial.read();//carriage return
 Serial.read();//newline
 }

};

class Motor {
 private:
 int pin_forward;
 int pin_backward;
 int pin_enable;
 int speed;
 public:
 Motor(int forward, int backward, int enable) :pin_forward(forward), pin_backward(backward), pin_enable(enable) {
 pinMode(pin_forward, OUTPUT);
 pinMode(pin_backward, OUTPUT);
 pinMode(pin_enable, OUTPUT);
 }
 void setSpeed(int speed) {
 if(speed > SPEED_LIMIT) speed = SPEED_LIMIT;
 if(speed < -SPEED_LIMIT) speed = -SPEED_LIMIT;
 if(speed > 0) {
 digitalWrite(pin_backward, LOW);
 digitalWrite(pin_forward, HIGH);
 analogWrite(pin_enable, speed);
 } else {
 digitalWrite(pin_forward, LOW);
 digitalWrite(pin_backward, HIGH);
 analogWrite(pin_enable, -speed);
 }
 this->speed = speed;
 }
 int getSpeed() {
 return speed;
 }
 };

class Robot {
 private:
 Motor motor_right;
 Motor motor_left;
 public:
 Robot(Motor right, Motor left) :motor_right(right), motor_left(left) {

}
 void setSpeed(int right, int left) {
 motor_right.setSpeed(right);
 motor_left.setSpeed(left);
 }
 };

class PingSensor {
 private:

int pin_echo;
 long ping_time;
 int pin_ping;
 void trigger() {

digitalWrite(pin_ping, LOW);
 delayMicroseconds(1);
 digitalWrite(pin_ping, HIGH);
 delayMicroseconds(2);
 digitalWrite(pin_ping, LOW);

}

public:
 PingSensor(int ping, int echo) :pin_ping(ping), pin_echo(echo) {
 pinMode(pin_ping, OUTPUT);
 pinMode(pin_echo, INPUT);
 }
 void ping();
 int distance(void) {
 return ping_time/29/2;
 }
 };

void PingSensor::ping() {
 trigger();
 ping_time = pulseIn(pin_echo, HIGH, 3000);
 if(ping_time == 0) ping_time = 3000;
 }



Motor rightMotor(PIN_RIGHT_FORWARD, PIN_RIGHT_BACKWARD, PIN_RIGHT_ENABLE);
 Motor leftMotor(PIN_LEFT_FORWARD, PIN_LEFT_BACKWARD, PIN_LEFT_ENABLE);
 Robot myBot(rightMotor,leftMotor);
 Command incoming;
 PingSensor leftSensor(PIN_LEFT_PING, PIN_LEFT_ECHO);
 PingSensor rightSensor(PIN_RIGHT_PING, PIN_RIGHT_ECHO);
 PingSensor frontSensor(PIN_FRONT_PING, PIN_FRONT_ECHO);



//setup() runs once on powerup
 void setup() {

pinMode(PIN_LED, OUTPUT);
 pinMode(PIN_HALL_R_A, INPUT);
 pinMode(PIN_HALL_R_B, INPUT);
 attachInterrupt(digitalPinToInterrupt(PIN_HALL_R_A), rightup, RISING);
 attachInterrupt(digitalPinToInterrupt(PIN_HALL_R_A), rightdown, FALLING);

pinMode(PIN_HALL_L_A, INPUT);
 pinMode(PIN_HALL_L_B, INPUT);
 attachInterrupt(digitalPinToInterrupt(PIN_HALL_L_A), leftup, RISING);
 attachInterrupt(digitalPinToInterrupt(PIN_HALL_L_A), leftdown, FALLING);

//Begin serial communications
 Serial.begin(38400);
 Serial.println("Starting up...");
 Serial.setTimeout(3);//Set timeout to 1 ms so parseInt doesnt wait forever after the last digit

digitalWrite(13, HIGH);//Indicate we are running main loop by lighting onboard led
 delay(3000);

rightSensor.ping();
 leftSensor.ping();
 frontSensor.ping();
 //This will allow robot to move without Matlab sending commands,
 //by holding hand in front of left and front sensors during startup
 if(leftSensor.distance() < 10 && frontSensor.distance() < 10 && rightSensor.distance() > 20) {
 incoming.right_speed = 70;
 incoming.left_speed = 90;
 }
 }



// ToDo: Handle rollover
 uint32_t startTime;

// This is main code loop, this code runs after setup() and repeats forever
 void loop() {

digitalWrite(PIN_LED, !digitalRead(PIN_LED));//flash board led when signals are transceived

//Avoid obstacles while commands are not being recieved
 while(!Serial.available()) {

getRPS(); // Update RPS counters

//Keep it moving straight forward, after the obstical avoidance block is left
 myBot.setSpeed(incoming.right_speed,255);
 delay(4);
 myBot.setSpeed(incoming.right_speed, incoming.left_speed);
 delay(10);

///Get distance on all sensors
 leftSensor.ping();
 frontSensor.ping();
 rightSensor.ping();
 //#define RANGE_SHORT 20
 //#define RANGE_MED 25
 //#define RANGE_LONG 30



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //Obstacal avoidance
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 if(leftSensor.distance() < RANGE_SHORT && rightSensor.distance() > RANGE_SHORT && frontSensor.distance() > RANGE_MED) {
 myBot.setSpeed(-TURN_SPEED, TURN_SPEED);
 while(leftSensor.distance() < RANGE_SHORT && !Serial.available()) {
 leftSensor.ping();
 if(DEBUG) Serial.println("CASE1");
 }
 } else if (rightSensor.distance() < RANGE_SHORT && leftSensor.distance() > RANGE_SHORT && frontSensor.distance() > RANGE_MED) {
 myBot.setSpeed(TURN_SPEED, -TURN_SPEED);
 while(rightSensor.distance() < RANGE_SHORT && !Serial.available()) {
 rightSensor.ping();
 if(DEBUG) Serial.println("CASE2");
 }
 } else if (frontSensor.distance() < RANGE_MED && rightSensor.distance() > RANGE_SHORT && leftSensor.distance() > RANGE_SHORT) {
 myBot.setSpeed(0, -TURN_SPEED);
 while(frontSensor.distance() < RANGE_LONG && !Serial.available()) {
 frontSensor.ping();
 if(DEBUG) Serial.println("CASE3");
 }
 } else if(frontSensor.distance() < RANGE_MED && rightSensor.distance() < RANGE_SHORT && leftSensor.distance() > RANGE_SHORT) {
 myBot.setSpeed(TURN_SPEED, -TURN_SPEED);
 while((frontSensor.distance() < RANGE_LONG || rightSensor.distance() < RANGE_MED) && !Serial.available()) {
 frontSensor.ping();
 rightSensor.ping();
 if(DEBUG) Serial.println("CASE4");
 }
 } else if(frontSensor.distance() < RANGE_MED && leftSensor.distance() < RANGE_SHORT && rightSensor.distance() > RANGE_SHORT) {
 myBot.setSpeed(-TURN_SPEED, TURN_SPEED);
 while((frontSensor.distance() < RANGE_LONG || leftSensor.distance() < RANGE_MED) && !Serial.available()) {
 frontSensor.ping();
 leftSensor.ping();
 if(DEBUG) Serial.println("CASE5");
 }
 } else if(frontSensor.distance() < RANGE_LONG && leftSensor.distance() < RANGE_MED && rightSensor.distance() < RANGE_MED) {
 myBot.setSpeed(-(TURN_SPEED-30), -TURN_SPEED);
 while((frontSensor.distance() < RANGE_LONG || leftSensor.distance() < RANGE_LONG || rightSensor.distance() < RANGE_LONG) && !Serial.available()) {
 leftSensor.ping();
 frontSensor.ping();
 rightSensor.ping();
 if(DEBUG) Serial.println("CASE6");
 }
 }
 if(DEBUG) {
 printSensors();
 printSpeed();
 }
 }//end while Serial!Avail

//Communicate with Matlab
 incoming.parseCommand();//Get command

//Carry out command
 myBot.setSpeed(255, 255);
 delay(3);
 myBot.setSpeed(incoming.right_speed, incoming.left_speed);
 delay(10);

//Send response
 printSensors();

//Refresh distances, in case a command immediately follows
 leftSensor.ping();
 rightSensor.ping();
 frontSensor.ping();

}

// Count hits on the hall sensor
 // Must be declared volatile, as they are modified in interrupt service routine (ISR)
 // ToDo: Handle rollover
 volatile int32_t count_right = 0;
 volatile int32_t count_left = 0;

// Called on rising edge of PIN_HALL_R_A
 void rightup() {
 if(digitalRead(PIN_HALL_R_B)) // Work out direction of rotation
 count_right--;
 else
 count_right++;
 }

// Called on rising edge of PIN_HALL_R_A
 void rightdown() {
 if(digitalRead(PIN_HALL_R_B)) // Work out direction of rotation
 count_right++;
 else
 count_right--;
 }

// Called on rising edge of PIN_HALL_L_A
 void leftup() {
 if(digitalRead(PIN_HALL_L_B)) // Work out direction of rotation
 count_left--;
 else
 count_left++;
 }

// Called on falling edge of PIN_HALL_L_A
 void leftdown() {
 if(digitalRead(PIN_HALL_L_B)) // Work out direction of rotation
 count_right++;
 else
 count_left--;
 }

uint32_t lastCount_r = 0, lastCount_l = 0;
 int16_t rps_r = 0, rps_l = 0;
 uint32_t lastTime = 0;

void getRPS() {
 uint32_t currentTime = micros();

// Update at 5Hz
 if(currentTime - lastTime < 200000) { // 200ms
 return;
 }

// Calculate counts per second on hall sensor
 float cps_r = ((float)(count_right - lastCount_r)) / ((float)(currentTime - lastTime) / 1000000);
 float cps_l = ((float)(count_left - lastCount_l)) / ((float)(currentTime - lastTime) / 1000000);

// Calculate rotations per second on output shaft
 rps_r = cps_r/480;
 rps_l = cps_l/480;

lastTime = currentTime;
 lastCount_r = count_right;
 lastCount_l = count_left;
 }

void printSensors() {
 Serial.print("Dist: [ ");
 Serial.print(leftSensor.distance());
 Serial.print(" ");
 Serial.print(frontSensor.distance());
 Serial.print(" ");
 Serial.print(rightSensor.distance());
 Serial.println(" ]");
 }

void printSpeed() {
 Serial.print("RPS: < ");
 Serial.print(rps_l);
 Serial.print(" ");
 Serial.print(rps_r);
 Serial.println(" >");
 }

Leave a Reply

Your email address will not be published. Required fields are marked *