Bot Following Human

I am doing a project which concentrates on a bot/cart following a human using ultrasonic sensors, two motors and a free wheel.

I managed to get the distance between an ultrasonic transmitter and 2 ultrasonic receivers, credits to Mr.Mark on the codes he sent on this thread right here.

Having the data on the 2 sensors, what I did was subtract the distance between them and find the direction using the sign I acquired. (If it's positive bot goes right, otherwise left.) Next I did was to get the average distance to control speed.

Problem is, the motors doesn't do what I've coded. Can you spot what I'm missing? Here is my code.

Transmitter:

/*
  Transmit side of one way ultrasonic ranging using HC-SR04.
  Node sync is performed with 433 MHz OOK transmit receive pair via a sync sequence

  HC-SR04 Ping distance sensor:
  VCC to arduino 5v
  GND to arduino GND
  Echo to Arduino pin 7
  Trig to Arduino pin 8

  433 MHz Transmitter:
  Data to Arduino pin 9

  HC-SR04 technique from here: http://arduinobasics.blogspot.com.au/2012/11/arduinobasics-hc-sr04-ultrasonic-sensor.html
*/


#define echoPin 7 // Echo Pin
#define trigPin 8 // Trigger Pin
#define rfTxPin 9 // rf Transmit enable
#define LEDPin 13 // Onboard LED
#define BitPeriod 500   // Bit period for RF sync bits in microseconds

boolean syncSeq[16] = {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1} ; // Bit sequence for synchronization

int maximumRange = 2000; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long duration, distance; // Duration used to calculate distance

void setup() {
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(rfTxPin, OUTPUT);
  pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)
  digitalWrite(trigPin, LOW) ;
  digitalWrite(rfTxPin, LOW) ;
}

void loop() {
  digitalWrite(LEDPin, HIGH);
  TxRFSync() ;        // Send RF synchronization sequence
  digitalWrite(trigPin, HIGH);      // Start ping sequence
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  digitalWrite(LEDPin, LOW);

  //Calculate the distance (in cm) based on the speed of sound.
  distance = duration / 58.2;

  if (distance >= maximumRange || distance <= minimumRange) {
    /* Send a negative number to computer */
    Serial.println("-1");
  }
  else {
    /* Send the distance to the computer using Serial protocol. */
    Serial.println(distance);
  }

  //Delay 100ms before next reading.
  delay(1);
}

// Function to write "syncSeq" bit sequence to RF transmit port
void TxRFSync()
{
  for (int k = 0; k < sizeof(syncSeq) ; k++)
  {
    digitalWrite(rfTxPin, syncSeq[k]) ;
    delayMicroseconds(BitPeriod) ;
  }
  digitalWrite(rfTxPin, LOW) ;      // Turn off transmit at end of sequence
}

Receiver:

/*
  Receive side of one way ultrasonic ranging using HC-SR04.
  Node sync is performed with 433 MHz OOK transmit receive pair via a sync sequence

  HC-SR04 Ping distance sensor:
  VCC to arduino 5v
  GND to arduino GND
  Echo to Arduino pin 7
  Trig to Arduino pin 8

  433 MHz Receiver:
  Data to Arduino pin 9

  HC-SR04 scheme from here: http://arduinobasics.blogspot.com.au/2012/11/arduinobasics-hc-sr04-ultrasonic-sensor.html
*/
#define syncStateA 10
#define syncStateB 11
#define debugPinC 12

#define echoPin2 3 // Echo Pin2
#define trigPin2 4 // Trigger Pin2
#define echoPin 5 // Echo Pin
#define trigPin 6 // Trigger Pin
#define rfRxPin 7 // rf Receive input pin
#define LEDPin 2 // Onboard LED
#define Forward1 13 //Forward right wheel
#define Back1 12 //Backward right wheel
#define PWM1 11 //Control right
#define PWM2 10 //Control left
#define Forward2 9 //Forward left wheel
#define Back2 8 //Backward left wheel

 
// Parameters for sync detection
#define minBitPeriod 450  // Low threshold for bit period (uS)
#define maxBitPeriod 550  // Max threshold for bit period (uS)
#define minSyncBits 8     // Min number of valid 1 plus 0 transitions before 1 plus 1

int A;
int B;
int maximumRange = 2000; // Maximum range needed (cm)
int minimumRange = 0; // Minimum range needed
long duration, distance, duration2, distance2; // Duration used to calculate distance
long timeout = 50000;  // Ping duration timeout

void setup() {
  pinMode(syncStateA, OUTPUT) ;
  pinMode(syncStateB, OUTPUT) ;
  pinMode(debugPinC, OUTPUT) ;

  Serial.begin (9600);
  pinMode(Forward1, OUTPUT);
  pinMode(Back1, OUTPUT);
  pinMode(PWM1, OUTPUT);
  pinMode(Forward2, OUTPUT);
  pinMode(Back2, OUTPUT);
  pinMode(PWM2, OUTPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(trigPin2, OUTPUT);
  pinMode(echoPin2, INPUT);
  pinMode(rfRxPin, INPUT);
  pinMode(LEDPin, OUTPUT) ;
  digitalWrite(LEDPin, LOW) ;
  digitalWrite(trigPin, LOW) ;
  digitalWrite(trigPin2, LOW) ;
}

void loop() {
{
  RxRFSync() ;    // Function blocks until sync sequence is detected
  digitalWrite(LEDPin,HIGH) ;
  digitalWrite(trigPin, HIGH);    // Start ping sequence
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH, timeout);

  //Calculate the distance (in cm) based on the speed of sound.
  distance = duration / 29.1 ;
  digitalWrite(LEDPin,LOW) ;
}


{
  RxRFSync() ;    // Function blocks until sync sequence is detected
  digitalWrite(LEDPin,HIGH) ;
  digitalWrite(trigPin2, HIGH);    // Start ping sequence
  delayMicroseconds(10);
  digitalWrite(trigPin2, LOW);
  duration2 = pulseIn(echoPin2, HIGH, timeout);

  //Calculate the distance (in cm) based on the speed of sound.
  distance2 = duration2 / 29.1 ;
  digitalWrite(LEDPin,LOW) ;
}
//start of computation, values are based on a straight line
//distance = first sensor left, distance2 = second sensor right
{
long A = distance - distance2; //I used this to determine what direction the bot will go, if values go positive goes left, otherwise go right
long B = ((distance + distance2)/2); //This is used for the control of speed, average distance
Serial.print("A = ");
Serial.println(A);
Serial.print("B = ");
Serial.println(B);
  
 if (A >= -3 || A <= 3) //got this for error leeway
 {
 if (B >= 35 || B <= 58) //35cm is about 1ft and 58 is about 2ft
  {
  digitalWrite(Forward1, HIGH);
  digitalWrite(Back1, LOW);
  digitalWrite(Forward2, HIGH);
  digitalWrite(Back2, LOW);
  analogWrite(PWM1, 125);
  analogWrite(PWM2, 125);
  if (B < 35)
  digitalWrite(Forward1, LOW);
  digitalWrite(Back1, LOW);
  digitalWrite(Forward2, LOW);
  digitalWrite(Back2, LOW);
  analogWrite(PWM1, 0);
  analogWrite(PWM2, 0);
  }
  if (B > 58)
  {
  digitalWrite(Forward1, HIGH);
  digitalWrite(Back1, LOW);
  digitalWrite(Forward2, HIGH);
  digitalWrite(Back2, LOW);
  analogWrite(PWM1, 200);
  analogWrite(PWM2, 200);
  }
 }
 if (A < -3)
 {
  digitalWrite(Forward1, HIGH);
  digitalWrite(Back1, LOW);
  analogWrite(PWM1, 200);
  digitalWrite(Forward2, LOW);
  digitalWrite(Back2, LOW);
 }
 if (A > 3)
 {
  digitalWrite(Forward1, LOW);
  digitalWrite(Back1, LOW);
  digitalWrite(Forward2, HIGH);
  digitalWrite(Back2, LOW);
  analogWrite(PWM2, 200);
 }
}
}
// Function to detect "syncSeq" bit sequence on RF receive port
void RxRFSync()
{
  long int lastBitTime = 0 ;    // holds time of last bit transition (uS)
  int BitCount = 0 ;            // counts number of valid bits detected

  boolean synced = false ;
  boolean lastBit = LOW ;  // holds last bit detected

  digitalWrite(syncStateA, LOW) ; digitalWrite(syncStateB, LOW) ; digitalWrite(debugPinC, LOW) ;

  while (!synced)
  {
    while (digitalRead(rfRxPin) == lastBit) { } // Block until bit transition
    int currBitTime = micros() ;
    int bitPeriod = currBitTime - lastBitTime ;

    if ((bitPeriod > (2 * minBitPeriod)) && (bitPeriod < (2 * maxBitPeriod)) && (lastBit == HIGH) && (BitCount > minSyncBits))
    {
      // Valid completion of sync sequence
      synced = true ;
      digitalWrite(syncStateA, HIGH) ; digitalWrite(syncStateB, HIGH) ; digitalWrite(debugPinC, lastBit) ;
    }
    else
    {
      lastBit = !lastBit ;
      lastBitTime = currBitTime ;
      if ((bitPeriod > minBitPeriod) && (bitPeriod < maxBitPeriod))
      {
        // Valid single bit detected, increment valid bit count and look for next bit
        BitCount += 1 ;     // increment valid bit count
        digitalWrite(syncStateA, LOW) ; digitalWrite(syncStateB, HIGH) ; digitalWrite(debugPinC, lastBit) ;
      }
      else
      {
        // Invalid bit detected, reset valid bit count and look for next bit
        BitCount = 0 ;
        digitalWrite(syncStateA, HIGH) ; digitalWrite(syncStateB, LOW) ; digitalWrite(debugPinC, lastBit) ;
      }
    }
  }
}

EDIT: I'm also using a l298n driver for this project. Thanks in advance for your help!

try a piece of string.

Allan

However I can't get it to work

What's it (not) doing?

How far apart are the receivers, I'm guessing no more than 50-100mm? The distance from each to a target is not going to be hugely different with such a narrow base.

Are you confident the two measured differences are accurate enough to pinpoint the position (edit) left/right direction of the target?

Just did some sums. It's not easy to find figures on how good these things are, but forum member vglfr reckons 2.5%. Let's use that.

I have no idea what your robot's size is, but let's say the receivers are 100mm apart.

Let's have a target 300mm to the left of the left hand receiver, and 1000mm ahead. Mr Pythagoras tells me (if I got the numbers right) that the target is 1044 from the left receiver and 1075 from the right.

Worst case would be the left one over reads by 2.5% and says the target is 1070 away; right one under reads by 2.5% and says 1050. That's enough to flip the position: your subtraction which should place the target on the left (1075>1044) places the target on the right (1050<1070). Your robot's going to zoom off in the wrong direction.

Put your own figures in there, with some testing to find out how much confidence you can place in the distance measurement, and see what you come up with.

But seeing as you just said you "can't get it work", with no elaboration, the foregoing might not be of any importance.

Oh yes my bad, I was concentrating on disclosing the details of my work but forgot to mention the real problem.

Anyway, the 2 RXs are 6in. apart from each other and thought that their position is just right. I conducted tests with the distances and I can say it is pretty accurate, errors I get is just an inch or so, due to noise.

My question is on the coding part, did I miss a "logical" way of setting my parameters?

Think of a cartesian plane, if distance1 - distance2 goes negative, it just means that the transmitter is on the left side, then the goal is to make the left motor stop and turn the right motor on so it would turn on the left, if it satisfies the condition distancediff >= -3 || distancediff <= 3 (I guess difference of 3cm is enough error consideration) it goes straight path.

You still didn't say what the problem is....

What does it do that it shouldn't, and/or not do that it should?

It doesn't do what my code says, the motors particularly

Another observation I'm having is that when I try to connect the supply of the driver the rf transmission slows or is cut off.

It doesn't do what my code says, the motors particularly

That's still a crap description of what's (not) happening.

You need to put serial prints into the parts where you hope it's going in order to run the motors: see if it's actually going where you expect.

I think you have your signs the wrong way round here:

if (A >= -3 || A <= 3) //got this for error leeway

A is the difference, and you want to move only if its absolute value is greater than 3, so you want

if (A <= -3 || A >= 3) //got this for error leeway

And it would be easier to use abs(A).

 if (B >= 35 || B <= 58) //35cm is about 1ft and 58 is about 2ft

Similarly, this expression is always true. All numbers are either >= 35 or <=58. Many numbers are both!

  {
  digitalWrite(Forward1, HIGH);
  digitalWrite(Back1, LOW);
  digitalWrite(Forward2, HIGH);
  digitalWrite(Back2, LOW);
  analogWrite(PWM1, 125);
  analogWrite(PWM2, 125);
  if (B < 35)               // SHOULDN'T THERE BE AN OPEN-BRACKET HERE?
  digitalWrite(Forward1, LOW);   // WITHOUT THE BRACKETS, THIS IS THE ONLY STATEMENT IN THE 'if'.
  digitalWrite(Back1, LOW);
  digitalWrite(Forward2, LOW);
  digitalWrite(Back2, LOW);
  analogWrite(PWM1, 0);
  analogWrite(PWM2, 0); 
   //  AND IT PROBABLY NEEDS A CLOSE BRACKET HERE
  }

Hi,

I already edited my code to my outmost understanding of the situation.

/* //correct, tested
  Receive side of one way ultrasonic ranging using HC-SR04.
  Node sync is performed with 433 MHz OOK transmit receive pair via a sync sequence

  HC-SR04 Ping distance sensor:
  VCC to arduino 5v
  GND to arduino GND
  Echo to Arduino pin 7
  Trig to Arduino pin 8

  433 MHz Receiver:
  Data to Arduino pin 9

  HC-SR04 scheme from here: http://arduinobasics.blogspot.com.au/2012/11/arduinobasics-hc-sr04-ultrasonic-sensor.html
*/
#define syncStateA 10
#define syncStateB 11
#define debugPinC 12

#define echoPin2 3 // Echo Pin2
#define trigPin2 4 // Trigger Pin2
#define echoPin 5 // Echo Pin
#define trigPin 6 // Trigger Pin
#define rfRxPin 7 // rf Receive input pin
#define LEDPin 2 // Onboard LED
#define IN1 13 //Forward right wheel
#define IN2 12 //Backward right wheel
#define ENA 11 //Control right
#define ENB 10 //Control left
#define IN3 9 //Forward left wheel
#define IN4 8 //Backward left wheel

 
// Parameters for sync detection
#define minBitPeriod 450  // Low threshold for bit period (uS)
#define maxBitPeriod 550  // Max threshold for bit period (uS)
#define minSyncBits 8     // Min number of valid 1 plus 0 transitions before 1 plus 1

int A;
int B;
int maximumRange = 2000; // Maximum range needed (cm)
int minimumRange = 0; // Minimum range needed
long duration, distance, duration2, distance2; // Duration used to calculate distance
long timeout = 50000;  // Ping duration timeout

void setup() {
  pinMode(syncStateA, OUTPUT) ;
  pinMode(syncStateB, OUTPUT) ;
  pinMode(debugPinC, OUTPUT) ;

  Serial.begin (9600);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(ENA, OUTPUT);
  pinMode(ENB, OUTPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(trigPin2, OUTPUT);
  pinMode(echoPin2, INPUT);
  pinMode(rfRxPin, INPUT);
  pinMode(LEDPin, OUTPUT) ;
  digitalWrite(LEDPin, LOW) ;
  digitalWrite(trigPin, LOW) ;
  digitalWrite(trigPin2, LOW) ;
}
//---------MOTOR--------
void forwardslow(){
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(ENA, 125);
  analogWrite(ENB, 125);
}

void forwardstop(){
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
}

void forwardfast(){
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(ENA, 200);
  analogWrite(ENB, 200);
}

void right(){
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(ENA, 200);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
}

void left(){
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(ENB, 200);
}

//----------LOOP------------
void loop() {
{
  RxRFSync() ;    // Function blocks until sync sequence is detected
  digitalWrite(LEDPin,HIGH) ;
  digitalWrite(trigPin, HIGH);    // Start ping sequence
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH, timeout);

  //Calculate the distance (in cm) based on the speed of sound.
  distance = duration / 29.1 ;
  digitalWrite(LEDPin,LOW) ;
}


{
  RxRFSync() ;    // Function blocks until sync sequence is detected
  digitalWrite(LEDPin,HIGH) ;
  digitalWrite(trigPin2, HIGH);    // Start ping sequence
  delayMicroseconds(10);
  digitalWrite(trigPin2, LOW);
  duration2 = pulseIn(echoPin2, HIGH, timeout);

  //Calculate the distance (in cm) based on the speed of sound.
  distance2 = duration2 / 29.1 ;
  digitalWrite(LEDPin,LOW) ;
}
//start of computation, values are based on a straight line
{
long A = distance - distance2; //I used this to determine what direction the bot will go
long B = ((distance + distance2)/2); //This is used for the control of speed
  
 if (A >= -3 && A <= 3)
 {
 if (B >= 35 &&  B <= 58) //35cm is about 1ft and 58 is about 2ft
  {
  forwardslow();
  Serial.print("Forward, SLOW");
  Serial.print("\n");
  }
  else if (B < 35){
  forwardstop();
  Serial.print("Forward, STOP");
  Serial.print("\n");
  }
  else
  {
  forwardfast();
  Serial.print("Forward, FAST");
  Serial.print("\n");
  }
 }
 else if (A < -3)
 {
  right();
  Serial.print("RIGHT");
  Serial.print("\n");
 }
 else
 {
  left();
  Serial.print("LEFT");
  Serial.print("\n");
 }
}
}
// Function to detect "syncSeq" bit sequence on RF receive port
void RxRFSync()
{
  long int lastBitTime = 0 ;    // holds time of last bit transition (uS)
  int BitCount = 0 ;            // counts number of valid bits detected

  boolean synced = false ;
  boolean lastBit = LOW ;  // holds last bit detected

  digitalWrite(syncStateA, LOW) ; digitalWrite(syncStateB, LOW) ; digitalWrite(debugPinC, LOW) ;

  while (!synced)
  {
    while (digitalRead(rfRxPin) == lastBit) { } // Block until bit transition
    int currBitTime = micros() ;
    int bitPeriod = currBitTime - lastBitTime ;

    if ((bitPeriod > (2 * minBitPeriod)) && (bitPeriod < (2 * maxBitPeriod)) && (lastBit == HIGH) && (BitCount > minSyncBits))
    {
      // Valid completion of sync sequence
      synced = true ;
      digitalWrite(syncStateA, HIGH) ; digitalWrite(syncStateB, HIGH) ; digitalWrite(debugPinC, lastBit) ;
    }
    else
    {
      lastBit = !lastBit ;
      lastBitTime = currBitTime ;
      if ((bitPeriod > minBitPeriod) && (bitPeriod < maxBitPeriod))
      {
        // Valid single bit detected, increment valid bit count and look for next bit
        BitCount += 1 ;     // increment valid bit count
        digitalWrite(syncStateA, LOW) ; digitalWrite(syncStateB, HIGH) ; digitalWrite(debugPinC, lastBit) ;
      }
      else
      {
        // Invalid bit detected, reset valid bit count and look for next bit
        BitCount = 0 ;
        digitalWrite(syncStateA, HIGH) ; digitalWrite(syncStateB, LOW) ; digitalWrite(debugPinC, lastBit) ;
      }
    }
  }
}

Here's the thing.

First,

Similarly, this expression is always true. All numbers are either >= 35 or <=58. Many numbers are both!

Thanks for correcting me for this, I want to express it in AND and not OR.

Second, I think my conditions are correct since serial monitor does print the status as I move transmitter (see attached photo).

And lastly, tho the serial monitor outputs the correct command, my motors still doesn't do anything. Please help, thanks in advance!

The manipulation of the motor control pins looks reasonable so my guess would be a wiring error between the Arduino and the motor controller. Can you provide detailed information about the controller and how everything is wired? Saying " a l298n driver " is not sufficient. A pointer to the board schematic would be best.