Autonomous robot drive in straight line using GPS

I'm using the GPS Neo 6M for my hardware and connect it to the Arduino Uno and also the motor driver. As for now when I connect the whole hardware only the GPS is detected but my motor driver is not running. My robot needs to maintain drive in straight path by using the coordinate from gps. The coding doesn't have error, but my robot does not move. I'm quite new in coding. Please help me :cry:

//include GPS Library
#include <TinyGPS++.h>
#include <TinyGPSPlus.h>
#include <SoftwareSerial.h>

//GPS RXTXPin and GPSBaud
static const int RXPin = 3, TXPin = 2;
static const uint32_t GPSBaud = 9600;

const int MOTORA_DIR_PIN = 4;
const int MOTORA_PWM_PIN = 5;
const int MOTORB_PWM_PIN = 6;
const int MOTORB_DIR_PIN = 7;
/* TOP VIEW, OF MOTOR
    <MOTOR A>      <MOTOR B>
                |
                |
    <left tyre> |  <rIGhT tyre>
*/
double latitude;
double longitude;
double targetLatitude = 3.5405;
const int CH_2_PIN = 8;
const int CH_3_PIN = 9;
const int CH_4_PIN = 10;
const int deadzone = 20; 
int ch2, ch3, ch4;
int fwbw, lfrgt;
int32_t maxspeed;
int32_t truespeed;
float subspeed; // ch2 for forward and backward, ch3 for max speed,
//ch4 for right and left

// The TinyGPS++ object
TinyGPSPlus gps;

// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);


void setup() {
  Serial.begin(9600);
  
  pinMode(CH_4_PIN, INPUT); pinMode(CH_2_PIN, INPUT); pinMode(CH_3_PIN, INPUT);
  pinMode(MOTORA_DIR_PIN, OUTPUT);
  pinMode(MOTORA_PWM_PIN, OUTPUT);
  pinMode(MOTORB_PWM_PIN, OUTPUT);
  pinMode(MOTORB_DIR_PIN, OUTPUT);

  ss.begin(GPSBaud); //GPS
}

void loop() {
  //Read GPS data
  while (ss.available() > 0){
    gps.encode(ss.read());
    if (gps.location.isUpdated()){
      //Get GPS coordinate
     latitude = gps.location.lat(), 6;
     longitude = gps.location.lng(), 6;
      Serial.print("Latitude= "); 
      Serial.print(gps.location.lat(), 6);
      Serial.print(" Longitude= "); 
      Serial.println(gps.location.lng(), 6);
     
 
  // read from higher channel pin first
  ch4 = pulseIn(CH_4_PIN, HIGH, 40000); // 40000 is the delay to make it works
  ch3 = pulseIn(CH_3_PIN, HIGH, 40000); // lower values will read 1 channel only
  ch2 = pulseIn(CH_2_PIN, HIGH, 40000); //delayMicroseconds(1);

  fwbw = pulseToPWM(ch2);
  lfrgt = pulseToPWM(ch4);
 if (ch3>2000){ch3=2000;}
 if (ch3<970){ch3=970;}
 
  maxspeed = map(ch3, 970, 2000, -1, 300);
  maxspeed = constrain(maxspeed, 0, 255);
  calcspeed();


  if (fwbw > 0) {
    digitalWrite(MOTORA_DIR_PIN, HIGH); digitalWrite(MOTORB_DIR_PIN, HIGH);
    
    if ( latitude < targetLatitude - 0.0001) { //Turn left
      analogWrite(MOTORB_PWM_PIN, 10); //truespeed
      analogWrite(MOTORA_PWM_PIN, 30);  //subspeed
     // Serial.println("CHECK 1");
      
    }
    if  (latitude > targetLatitude + 0.0001) {  //Turn Right
      analogWrite(MOTORB_PWM_PIN, 30); //subspeed
      analogWrite(MOTORA_PWM_PIN, 10); //truespeed
      // Serial.println("CHECK 2");
    }
    if  (latitude == targetLatitude) {  //Go Straight
      analogWrite(MOTORB_PWM_PIN, 30); //truespeed
      analogWrite(MOTORA_PWM_PIN, 30); //truespeed
       //Serial.println("CHECK 3");
      // delay (5000);
    }

    
    
  }
  else if (fwbw < 0) {
  //  digitalWrite(MOTORA_DIR_PIN, LOW); digitalWrite(MOTORB_DIR_PIN, LOW);

    analogWrite(MOTORA_PWM_PIN, 0);
    analogWrite(MOTORB_PWM_PIN, 0);
    }
  }
  
    /*
   if  (lfrgt < 0) {
      analogWrite(MOTORB_PWM_PIN, 20); //truespeed
      analogWrite(MOTORA_PWM_PIN, 10); //subspeed
      //Serial.println("CHECK 4");
    }
    if  (lfrgt > 0) {
      analogWrite(MOTORB_PWM_PIN, 10); //subspeed
      analogWrite(MOTORA_PWM_PIN, 20); //truespeed
      //Serial.println("CHECK 5");
    }
            if  (lfrgt == 0) {
      analogWrite(MOTORB_PWM_PIN, 20); //truespeed
      analogWrite(MOTORA_PWM_PIN, 20);  //truespeed
       //Serial.println("CHECK 6");
    }
  }
  else if ((fwbw == 0)&&(lfrgt<-50)){
    digitalWrite(MOTORA_DIR_PIN, LOW); digitalWrite(MOTORB_DIR_PIN, HIGH);
    analogWrite(MOTORB_PWM_PIN, 20); //truespeed
    analogWrite(MOTORA_PWM_PIN, 20); //truespeed
  }
    else if ((fwbw == 0)&&(lfrgt>50)){
    digitalWrite(MOTORA_DIR_PIN, HIGH); digitalWrite(MOTORB_DIR_PIN, LOW);
    analogWrite(MOTORA_PWM_PIN, 20);  //truespeed
    analogWrite(MOTORB_PWM_PIN, 20);  //truespeed
  }

  else {
    //Stop motor if no at 0,0 position
    analogWrite(MOTORA_PWM_PIN, 0);
    analogWrite(MOTORB_PWM_PIN, 0);
    // Serial.println("CHECK 7");
    
  }
*/
 //printMapped();  //printCH();

}
}

void calcspeed() {
  float xx=(lfrgt);
  float yy=(fwbw);
  float Rad=sqrt(xx*xx+yy*yy);
   //truespeed = maxspeed*(abs(fwbw))/255;//;
  truespeed = Rad*maxspeed/255;//;
  subspeed = Rad*maxspeed/255*(abs(cos(abs(atan(xx / yy)))));
  
  if (Rad>=255){
    Rad=maxspeed;
    truespeed = maxspeed;
     subspeed = Rad*(abs(cos(abs(atan(xx / yy)))));
  }  
 
  //return truespeed, subspeed;
}

void printCH() {
 // Serial.print("CH2: ");
 // Serial.print(ch2);
 // Serial.print(",  CH3: ");
 // Serial.print(ch3);
 // Serial.print(",  CH4: ");
 // Serial.println(ch4);
}

void printMapped() {
  Serial.print("Forward Backward: ");
  //Serial.print(ch2); Serial.print(", ");
  Serial.print(fwbw);
  Serial.print(",  Left Right: ");// Serial.print(ch4);Serial.print(", ");
  Serial.print(lfrgt);
  Serial.print(",  Max Speed: "); // Serial.print(ch3);Serial.print(", ");
  Serial.print(maxspeed);

  Serial.print(", truespeed: ");
  Serial.print(truespeed);
  Serial.print(", subspeed: ");
  Serial.println(subspeed, 3);
}

int pulseToPWM(int pulse) {
  int minreadval = 940; //940 val lower from the lowest valu read
  int maxreadval = 2000; //2000 bithigher than highest value
  // If we're receiving numbers, convert them to motor PWM
  int pulses = pulse;
  if ( pulses > minreadval ) {
    pulse = map(pulse, minreadval, maxreadval, -300, 300);
    pulse = constrain(pulse, -255, 255);
  }
  if (pulses < minreadval) {
    pulse = -255;
  }

  // Anything in deadzone should stop the motor
  if ( abs(pulse) <= deadzone ) {
    pulse = 0;
  }

  return pulse;
}[quote="ahmedessam235, post:1, topic:373574, full:true"]
hey guys i'm building 2WD mobile robot using arduino mega and two motor of model 16G214E with built in encodrs MR2 i'm still planning the algorithm and i'm bit confused my goal is to give the robot distance between 1 to -20 meters and the robot will move that distance in straight line so to prevent deviation i will need PID control my algorithm is taking the input and mapping it into the encoder steps while the pid making sure the velocities of each wheel is equal
[/quote]

Welcome to the forum

Please post a clear schematic of your project. A picture of a pencil and paper drawing is good enough

Here is the schematic diagram and my platform. Sorry for the drawing. I'm bad at draw.

Thanks for the info and wiring diagram, but you don't show how you have power connected to each device..

Can you please post a link to data/specs of the motor drivers/

Have you got code that JUST controls the motors?
This is to prove you have control of them before any extra code.

Thanks.. Tom.. :grinning: :+1: :coffee: :australia:

The GPS I/O is 3.3 volt and UNO I/O is 5 volt. Remove the connection from UNO pin
2, Tx. You don't need it for receiving GPS data.
It doesn't fix the motor issue but might save the GPS.

All the connection is then connected to the battery as the power supply, Without the gps the robot can move smoothly. But with that data from gps the robot cant move. Im using MD20A as the motor driver

Hi, @programmer28

Have you got code for the GPS that works on its own?

Can you describe to us how you are trying to use the GPS information to control the differential drive to the motors?

Thanks.. Tom.. :grinning: :+1: :coffee: :australia:

this is the code of GPS and the one that I give ups there is the combined and Im not really sure is that is the correct coding for moving the robot. I want the robot to move in a straight line by using the latitude and longitude info from the GPS


#include <TinyGPS++.h>
#include <TinyGPSPlus.h>
//#include <TinyGPS++.h>
#include <SoftwareSerial.h>

static const int RXPin = 3, TXPin = 2;
static const uint32_t GPSBaud = 9600;

// The TinyGPS++ object
TinyGPSPlus gps;

// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);

void setup(){
  Serial.begin(9600);
  ss.begin(GPSBaud);

}

void loop(){
  // This sketch displays information every time a new sentence is correctly encoded.
  while (ss.available() > 0){
    gps.encode(ss.read());
    if (gps.location.isUpdated()){
      Serial.print("Latitude= "); 
      Serial.print(gps.location.lat(), 6);
      Serial.print(" Longitude= "); 
      Serial.println(gps.location.lng(), 6);
    }
  }
}

Hi,
What interval, distance or time are you trying to update the robots position and correct its direction of travel.
How precise do you think GPS is?

If you are looking for 0.0001 degree change in direction, over a few cms, I think you need to reconsider your methodology.
You are working out the new direction to travel, but do not know in what direction your robot is pointing.

Check how accurate GPS first, display readings as you move and see if they correlate to the real world movement.

I fear you are over estimating the precision of the GPS system in a small scale world.

You are better to use encoders on each drive motor to make sure you have instantaneous straight line movement.

Tom.. :grinning: :+1: :coffee: :australia:

GPS can measure only position, and even then, only to limited accuracy. To drive in a straight line, you need another sensor.

A magnetometer (electronic compass) works well to determine robot heading, if it is properly calibrated and not subject to interference from motor magnets or metal objects.

Another approach is to use wheel encoders, and make sure that the encoders total up the same number of counts on each side of the robot, as it travels along.

The simplest approach with wheel encoders is PID steering, where the steering guide (PID INPUT) is the difference between encoder counts.

Finally, any external reference mark can be used: a visual scene caught by a camera, a bright light source, etc.

could I combine the GPS with the PID? and the coding of the PID need to add into the main coding to run the motor?

Why would you want to do that?

GPS can tell you where your robot is (approximately) at a given moment, but not which direction it is pointing.

I need my robot to maintain move in a straight line by using the data from GPS NEO 6M. But you said that gps could only give location but not make the robot move straight. Because the main hardware that I need to use is the GPS in order to make the robot move autonomously.

You will need additional hardware to make the robot move in straight lines.

Please help us understand what led you to believe data from that GPS would let your robot move in a straight line! Was there something in the documentation?

Why from a GPS?

Is this a school/college/university project?

Thanks.. Tom.. :grinning: :+1: :coffee: :australia:

Looking at the datasheet, the horizontal position accuracy of the GPS module is only 2.5 metres, so I'm interested in hearing how this is going to work as well... :popcorn:

The way that works is each time you get a position from GPS, it can lie ANYWHERE in a radius of 2.5 meters. If you average the results over some time period you can close in on the actual position. But that may take several minutes.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.