Attempting to add bump sensor to bluetooth controlled tankbot

Greetings all, I hope this is in the right place.

I’m working on a basic tank style bot to demonstrate to a lunchtime robotics club. The general idea is for the robot to be controlled by keyboard input from a PC communicating with the bot by bluetooth.

So far, so good. I have the bluesmirf happily talking to the PC and passing serial info to/from the arduino.

At present I have 4 keyboard commands F, B, L & R (Forward, Back, Left and Right)

What I am struggling with is how code for a bump switch/sensor on the front of the bot. I’ve got the switch wired up to return a high value when open and go low when closed.

It’s an L293D based H-bridge setup, using code that’s heavily based on the excellent work from www.luckylarry.co.uk and the famous larrybot

Can anyone point me at a better way of making the damned thing stop when it runs into something?

Here are my efforts so far:

//Code based on the larrybot from www.luckylarry.co.uk - with eternal gratitude to Larry

int bumppin=0;                                   // Connect bumper switch here
int motor1Pin1 = 3;                             // pin 2 on L293D
int motor1Pin2 = 4;                             // pin 7 on L293D
int enable1Pin = 9;                             // pin 1 on L293D
int motor2Pin1 = 5;                             // pin 10 on L293D
int motor2Pin2 = 6;                             // pin  15 on L293D
int enable2Pin = 10;                            // pin 9 on L293D
int incomingByte = 0;	// for incoming serial data

// variable for steering void statements
int dist;
int bump =0;                                    //bump variable

void setup() {
  // set the motor pins as outputs:
  pinMode(motor1Pin1, OUTPUT);
  pinMode(motor1Pin2, OUTPUT);
  pinMode(enable1Pin, OUTPUT);
  pinMode(motor2Pin1, OUTPUT);
  pinMode(motor2Pin2, OUTPUT);
  pinMode(enable2Pin, OUTPUT);
  pinMode (bumppin, INPUT);

 Serial.begin(115200);		
}


void stop () 
{ 
 // stop : force both motor speeds to 0
analogWrite (enable1Pin, 0);
analogWrite (enable2Pin, 0);
digitalWrite (motor2Pin1,LOW);
digitalWrite (motor1Pin1,LOW);
digitalWrite (motor2Pin2,LOW);
digitalWrite (motor1Pin2,LOW);
}

void forward(int dist) 
{ 
  // forward : set both motors forward
    digitalWrite (enable1Pin, HIGH);
    digitalWrite (enable2Pin, HIGH);
    digitalWrite(motor1Pin1, LOW);
    digitalWrite(motor1Pin2, HIGH);
    digitalWrite(motor2Pin1, LOW);
    digitalWrite(motor2Pin2, HIGH);
delay (dist);

} 

void backward(int dist) 
{
  // forward : set both motors forward    
     digitalWrite (enable1Pin, HIGH);
    digitalWrite (enable2Pin, HIGH);
    digitalWrite(motor1Pin1, HIGH);
    digitalWrite(motor1Pin2, LOW);
    digitalWrite(motor2Pin1, HIGH);
    digitalWrite(motor2Pin2, LOW);
delay (dist);
}

void turnL (int dist)
{
      // turn left
    digitalWrite (enable1Pin, HIGH);
    digitalWrite (enable2Pin, HIGH);
    digitalWrite(motor1Pin1, HIGH);
    digitalWrite(motor1Pin2, LOW);
    digitalWrite(motor2Pin1, LOW);
    digitalWrite(motor2Pin2, HIGH);
delay (dist);

}

void turnR (int dist)
{
      // turn right
    digitalWrite (enable1Pin, HIGH);
    digitalWrite (enable2Pin, HIGH);
    digitalWrite(motor1Pin1, LOW);
    digitalWrite(motor1Pin2, HIGH);
    digitalWrite(motor2Pin1, HIGH);
    digitalWrite(motor2Pin2, LOW);
delay (dist);

}



void loop() 
{

stop ();  // Stop statement so that robot pauses between keyboard inputs.
// arduino would otherwise keep acting on last keypress until it received another one
// There has to be a better way to do that?

if (Serial.available() > 0) 
{
		// read the incoming byte:
		incomingByte = Serial.read();
bump=analogRead(bumppin); // read bump high = no bump, low=bump
 
//This sort of works but I am not convinced this is the best way 
if (bump <100)
  {
  backward (50);
  
}

else if (incomingByte ==102)
  {
  forward (500);
}


else if (incomingByte ==98)
{
  backward (500);
}

else if (incomingByte ==108)
{
  turnL (300);
}

else if (incomingByte ==114)
{
  turnR (300);
}

else if (incomingByte != 102 && incomingByte != 98 && incomingByte != 108 && incomingByte != 114)
{
stop ();
}

}

}

What are you using for a bump switch? Your robot is always going to need some amount of time to come to a stop, so your bump switch has to activate far enough ahead of time to give the robot time to stop. This is typically accomplished with a whisker switch.

If you are already using whisker switches and the robot still isn't stopping in time, then you may not be getting enough 'braking' action when issuing a stop command. Without seeing the L293 schematic you are using, it's tough to say for sure that your stop() command is actually braking the motors as opposed to putting them into 'freespin' mode, but your code does appear to be driving all the motor pins low, which should provide some braking. It still could be that the motors themselves don't have enough torque to provide good braking (this will be especially true if they aren't gear reduced, unlikely if they are gear reduced).

Why are you reading the bump switch only when there is serial data available? If the switch is digital, as you implied in the original post, why are you using analogRead to read the value?

PaulS: Why are you reading the bump switch only when there is serial data available? If the switch is digital, as you implied in the original post, why are you using analogRead to read the value?

Because, in essence, I don't 100% know what I'm doing. :) I kludged together the attempt to read the value from the switch without quite knowing how to make it work. I'm not sure the best way to arrange the void loop so as to have the switch stop the robot if someone hits the 'f' key repeatedly and sends the robot careering into the wall.

Move the code for reading the switch out of the if(Serial.available()) block. It should be the first thing that happens in loop.

If you have a pressure switch, that reads other than pressed/released, analogRead is the right function. If you have an tactile switch (pressed/released), digitalRead (and a digital pin set to INPUT) is the right function to use.

PaulS:
Move the code for reading the switch out of the if(Serial.available()) block. It should be the first thing that happens in loop.

If you have a pressure switch, that reads other than pressed/released, analogRead is the right function. If you have an tactile switch (pressed/released), digitalRead (and a digital pin set to INPUT) is the right function to use.

Thanks.
What I am trying to do is deal with the situation where someone hits ‘f’ repeatedly (or any of the movement keys) and fills the serial buffer with commands that sends the robot hurtling off into the wall or whatever. Ideally the bump sensor should trigger, stop the robot, move it back and then void all subsequent commands, resetting if you will.
I tried making the movement if statements conditional on the bump sensor not being triggered but then ran into (pardon the pun) the problem of the robot running into a wall, pressing the bump sensor and then refusing to move because the sensor was triggered.

I’ll have another look at things once I’ve superglued the track back together following an unsuccessful test of my last code :slight_smile:

Edited to add :

EUREKA !(I think)

Serial.flush()

//Code based on the larrybot from www.luckylarry.co.uk - with eternal gratitude to Larry

int bumppin=0;                                   // Connect bumper switch here
int motor1Pin1 = 3;                             // pin 2 on L293D
int motor1Pin2 = 4;                             // pin 7 on L293D
int enable1Pin = 9;                             // pin 1 on L293D
int motor2Pin1 = 5;                             // pin 10 on L293D
int motor2Pin2 = 6;                             // pin  15 on L293D
int enable2Pin = 10;                            // pin 9 on L293D
int incomingByte = 0;	// for incoming serial data

// variable for steering void statements
int dist;
int bump =0;                                    //bump variable
int gonogo=1;

void setup() {
  // set the motor pins as outputs:
  pinMode(motor1Pin1, OUTPUT);
  pinMode(motor1Pin2, OUTPUT);
  pinMode(enable1Pin, OUTPUT);
  pinMode(motor2Pin1, OUTPUT);
  pinMode(motor2Pin2, OUTPUT);
  pinMode(enable2Pin, OUTPUT);
  pinMode (bumppin, INPUT);

		
}


void stop () 
{ 
 // stop : force both motor speeds to 0
analogWrite (enable1Pin, 0);
analogWrite (enable2Pin, 0);
digitalWrite (motor2Pin1,LOW);
digitalWrite (motor1Pin1,LOW);
digitalWrite (motor2Pin2,LOW);
digitalWrite (motor1Pin2,LOW);
}

void forward(int dist) 
{ 
  // forward : set both motors forward
    digitalWrite (enable1Pin, HIGH);
    digitalWrite (enable2Pin, HIGH);
    digitalWrite(motor1Pin1, LOW);
    digitalWrite(motor1Pin2, HIGH);
    digitalWrite(motor2Pin1, LOW);
    digitalWrite(motor2Pin2, HIGH);
delay (dist);

} 

void backward(int dist) 
{
  // forward : set both motors forward    
     digitalWrite (enable1Pin, HIGH);
    digitalWrite (enable2Pin, HIGH);
    digitalWrite(motor1Pin1, HIGH);
    digitalWrite(motor1Pin2, LOW);
    digitalWrite(motor2Pin1, HIGH);
    digitalWrite(motor2Pin2, LOW);
delay (dist);
}

void turnL (int dist)
{
      // turn left
    digitalWrite (enable1Pin, HIGH);
    digitalWrite (enable2Pin, HIGH);
    digitalWrite(motor1Pin1, HIGH);
    digitalWrite(motor1Pin2, LOW);
    digitalWrite(motor2Pin1, LOW);
    digitalWrite(motor2Pin2, HIGH);
delay (dist);

}

void turnR (int dist)
{
      // turn right
    digitalWrite (enable1Pin, HIGH);
    digitalWrite (enable2Pin, HIGH);
    digitalWrite(motor1Pin1, LOW);
    digitalWrite(motor1Pin2, HIGH);
    digitalWrite(motor2Pin1, HIGH);
    digitalWrite(motor2Pin2, LOW);
delay (dist);

}



void loop() 
{
   Serial.begin(115200);
  

//incomingByte=0;
bump=analogRead(bumppin); // read bump high = no bump, low=bump
 Serial.println(bump);
if (bump <100)
  {
  backward (50);
  Serial.flush();
}


if (Serial.available() > 0) 
{
// read the incoming byte:
incomingByte = Serial.read();
}


if (incomingByte ==102)
  {
  forward (500);
  incomingByte=0;
}



if (incomingByte ==98)
{
  backward (500);
  
incomingByte=0;
}

if (incomingByte ==108)
{
  turnL (300);
 
 incomingByte=0;
}

if (incomingByte ==114)
{
  turnR (300);

  incomingByte=0;
}

if (incomingByte != 102 && incomingByte != 98 && incomingByte != 108 && incomingByte != 114)
{
 stop();
  incomingByte=0;
}

}

incomingByte ==102

Very few of us, I suspect, can remember the ASCII table in decimal (hex maybe), so it makes sense when writing stuff related to characters to use the character values themselves:

incomingByte == 'f'

(note the single quote / apostrophe)

AWOL:

incomingByte ==102

Very few of us, I suspect, can remember the ASCII table in decimal (hex maybe), so it makes sense when writing stuff related to characters to use the character values themselves:

incomingByte == 'f'

(note the single quote / apostrophe)

Duly noted :) I shall amend accordingly. Much appreciated, thanks!

Another thing I should have mentioned: it is a useful habit to acquire when performing comparisons to put the constant on the left-hand side.

if ('f' == incomingByte)

The reason for this is that the compiler will complain about this: if ('f' = incomingByte), but not about this:if (incomingByte = 'f') This helps avoid a major cause of hair-loss among C programmers.