I am working on a project where I am building a GPS Car. At first I had the entire thing working but I decided to add a second gps for reliability issues. Ever since then, I have been unable to get it to respond to Bluetooth commands I send from a serial app on my phone. It does however send data via Bluetooth which I can read on my phone but the other way doesn't work. I need bluetooth commands to switch between waypoint lists, as well as set new waypoints based on the current location. Any help is appreciated.
Here is the new code:
#include <TinyGPS++.h>
#include <Wire.h>
#include <QMC5883LCompass.h>
#include <SoftwareSerial.h> // For the second GPS module
#include <Adafruit_GPS.h>
// Constants
static const uint32_t GPSBaud = 9600;
#define HEADING_TOLERANCE 5
#define WAYPOINT_DIST_TOLERANCE 1
#define stopwaypoint 5
#define MAX_WAYPOINTS 10
#define buttonPin 12
// GPS and Compass objects
SoftwareSerial GPS1_Serial(10, 11); // RX, TX for GPS1
TinyGPSPlus gps;
TinyGPSPlus gps1;
Adafruit_GPS GPS(&Serial3);
Adafruit_GPS GPS1(&GPS1_Serial);
QMC5883LCompass compass;
// GPS variables
float currentLat, currentLong;
float targetLat, targetLong;
int distanceToTarget, originalDistanceToTarget;
int current_waypoint = 0;
//compass variables
int targetHeading;
int currentHeading;
int headingError; // signed (+/-) difference between targetHeading and currentHeading
// Waypoints
float waypointList[MAX_WAYPOINTS][2] = {
{23.202905, 72.658213},
{23.202849, 72.658091},
{23.202746, 72.658156},
{23.202841, 72.658310},
{23.202839, 72.658197}
};
// Preset Waypoints
float presetWaypointList[MAX_WAYPOINTS][2] = {
{23.201336, 72.660916},
{23.201501, 72.660902},
{23.201659, 72.660930},
{23.201779, 72.660978},
{23.201927, 72.661102}
// Add more if needed
};
// Bluetooth command handling
String bluetoothCommand = "";
String inputString = "";
bool stringComplete = false;
int id = 0;
int mode;
String val[5];
int nprint = 0;
int aprint = 0;
bool useGPS1 = false;
void setup() {
Serial.begin(9600);
GPS1_Serial.begin(9600);
Serial2.begin(9600); // Bluetooth
Serial3.begin(9600); // GPS
pinMode(buttonPin, INPUT_PULLUP);
GPS.begin(9600);
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
GPS.sendCommand(PGCMD_NOANTENNA);
GPS1.begin(9600);
GPS1.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
GPS1.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
GPS1.sendCommand(PGCMD_NOANTENNA);
compass.init();
compass.setCalibration(-1056, 1358, -1380, 638, -1118, 0);
Serial.println("Start");
Serial.println(waypointList[0][0], 6);
Serial.println(waypointList[0][1], 6);
Serial.println(waypointList[1][0], 6);
Serial.println(waypointList[1][1], 6);
// Initialize target latitude and longitude
targetLat = waypointList[0][0];
targetLong = waypointList[0][1];
}
void loop() {
// Read data from both GPS modules
while (Serial3.available() > 0) {
if (gps.encode(Serial3.read())) {
// Read data from GPS until no more data is available
}
}
while (GPS1_Serial.available() > 0) {
if (gps1.encode(GPS1_Serial.read())) {
// Read data from GPS until no more data is available
}
}
// Process GPS data
processGPS();
// Process Bluetooth commands continuously
processBluetoothCommand();
// Check if the button is pressed
if (digitalRead(buttonPin) == LOW) {
stopRobotAndSendStats();
} else {
// Proceed with navigation if GPS data is valid
if (currentLong > 0 && targetLong > 0) {
currentHeading = readCompass();
calcDesiredTurn();
move_robot();
aprint++;
if (aprint == 200) {
aprint = 0;
Serial2.print("wp "); Serial2.print(current_waypoint);
Serial2.print("_ch "); Serial2.print(currentHeading);
Serial2.print("_th "); Serial2.print(targetHeading);
Serial2.print("_eh "); Serial2.print(headingError);
Serial2.print("_di "); Serial2.print(distanceToTarget);
Serial2.print("_st1 "); Serial2.print(gps.satellites.value(), 6);
Serial2.print("_st2 "); Serial2.print(gps1.satellites.value(), 6);
Serial2.print("_gn "); Serial2.print(useGPS1 ? 2 : 1);
Serial2.println();
}
} else {
// Print a message if GPS data is not valid
Serial2.println("Check GPS");
}
}
}
void processGPS() {
// Reset current coordinates
currentLat = 0.00;
currentLong = 0.00;
// Check if GPS 1 is in use
if (!useGPS1) {
// If GPS 1 is not in use, try using it
if (gps.location.isValid() && gps.satellites.value() >= 3) { // Adjust the minimum satellites as needed
currentLat = gps.location.lat();
currentLong = gps.location.lng();
// Calculate distance and course to waypoint
distanceToWaypoint();
courseToWaypoint();
}
else {
// If GPS 1 fails or has insufficient satellites, switch to GPS 2
if (gps1.location.isValid() && gps1.satellites.value() >= 3) { // Adjust the minimum satellites as needed
currentLat = gps1.location.lat();
currentLong = gps1.location.lng();
// Calculate distance and course to waypoint
distanceToWaypoint();
courseToWaypoint();
useGPS1 = true; // Switch to GPS 2
}
}
}
else {
// If GPS 1 is in use, try using it
if (gps1.location.isValid() && gps1.satellites.value() >= 3) { // Adjust the minimum satellites as needed
currentLat = gps1.location.lat();
currentLong = gps1.location.lng();
// Calculate distance and course to waypoint
distanceToWaypoint();
courseToWaypoint();
}
else {
// If GPS 1 fails or has insufficient satellites, switch to GPS 2
if (gps.location.isValid() && gps.satellites.value() >= 3) { // Adjust the minimum satellites as needed
currentLat = gps.location.lat();
currentLong = gps.location.lng();
// Calculate distance and course to waypoint
distanceToWaypoint();
courseToWaypoint();
useGPS1 = false; // Switch to GPS 1
}
}
}
}
int distanceToWaypoint()
{
float delta = radians(currentLong - targetLong);
float sdlong = sin(delta);
float cdlong = cos(delta);
float lat1 = radians(currentLat);
float lat2 = radians(targetLat);
float slat1 = sin(lat1);
float clat1 = cos(lat1);
float slat2 = sin(lat2);
float clat2 = cos(lat2);
delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
delta = sq(delta);
delta += sq(clat2 * sdlong);
delta = sqrt(delta);
float denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
delta = atan2(delta, denom);
distanceToTarget = delta * 6372795;
// check to see if we have reached the current waypoint
if (distanceToTarget <= WAYPOINT_DIST_TOLERANCE-1)
{
//berhenti();
delay(stopwaypoint*1000);
nextWaypoint();
}
return distanceToTarget;
}
int readCompass() {
compass.read();
return compass.getAzimuth();
}
int courseToWaypoint()
{
float dlon = radians(targetLong - currentLong);
float cLat = radians(currentLat);
float tLat = radians(targetLat);
float a1 = sin(dlon) * cos(tLat);
float a2 = sin(cLat) * cos(tLat) * cos(dlon);
a2 = cos(cLat) * sin(tLat) - a2;
a2 = atan2(a1, a2);
if (a2 < 0.0)
{
a2 += TWO_PI;
}
targetHeading = degrees(a2);
return targetHeading;
}
void nextWaypoint()
{
current_waypoint++;
targetLat = waypointList[current_waypoint][0];
targetLong = waypointList[current_waypoint][1];
if ((targetLat == 0 && targetLong == 0)) // last waypoint reached?
{
//berhenti();
Serial2.println("FINISH");
while (1); //PRESS RESET BUTTON
}
else
{
processGPS();
distanceToTarget = originalDistanceToTarget = distanceToWaypoint();
courseToWaypoint();
}
}
int error_output;
void calcDesiredTurn(void)
{
headingError = targetHeading - currentHeading; // calculate where we need to turn to head to destination
// adjust for compass wrap
if (headingError < -180)
headingError += 360;
if (headingError > 180)
headingError -= 360;
// calculate which way to turn to intercept the targetHeading
if (abs(headingError) <= HEADING_TOLERANCE) // if within tolerance, don't turn
error_output = 0;
else if (headingError < 60 && headingError > -60)
{
error_output = headingError;
}
else if (headingError >= 60)
error_output = 100;
else if (headingError <= -60)
error_output = -100;
}
float Kp, Kd;
void move_robot()
{
if (error_output == 0)
{
//forward();
Serial2.println("fwd");
}
else if (error_output < 60)
{
if (error_output < 0)
//left();
Serial2.println("lft");
else
//right();
Serial2.println("rgt");
}
else if (error_output == 100)
{
//sharpright();
}
else if (error_output == -100)
{
//sharpleft();
}
}
void processBluetoothCommand() {
while (Serial2.available()) {
char inChar = (char)Serial2.read();
if (inChar == '\n') {
// End of command, process it
processCommand(bluetoothCommand);
bluetoothCommand = ""; // Clear command for next one
} else {
// Append character to command
bluetoothCommand += inChar;
}
}
}
void processCommand(String command) {
if (command == "swp1") {
waypointList[0][0] = currentLat;
waypointList[0][1] = currentLong;
} else if (command == "swp2") {
waypointList[1][0] = currentLat;
waypointList[1][1] = currentLong;
} else if (command == "swp3") {
waypointList[2][0] = currentLat;
waypointList[2][1] = currentLong;
} else if (command == "swp4") {
waypointList[3][0] = currentLat;
waypointList[3][1] = currentLong;
} else if (command == "swp5") {
waypointList[4][0] = currentLat;
waypointList[4][1] = currentLong;
} else if (command == "pswp") {
for (int i = 0; i < MAX_WAYPOINTS; i++) {
waypointList[i][0] = presetWaypointList[i][0];
waypointList[i][1] = presetWaypointList[i][1];
}
Serial2.println("Waypoint list swapped to preset!");
}
// Add more command handling as needed
}
void serialEvent2() //bluetooth
{
while (Serial2.available())
{
char inChar = (char)Serial2.read();
if (inChar == '\n') // Assuming newline marks the end of a command
{
processBluetoothCommand();
bluetoothCommand = ""; // Clear the command for the next one
}
else
{
bluetoothCommand += inChar;
}
}
}
void stopRobotAndSendStats() {
//berhenti(); // Stop the robot
Serial2.print("la "); Serial2.print(currentLat, 6);
Serial2.print("_lo "); Serial2.print(currentLong, 6);
Serial2.print("_la "); Serial2.print(targetLat, 6);
Serial2.print("_lo "); Serial2.print(targetLong, 6);
Serial2.print("_ch "); Serial2.print(readCompass());
Serial2.print("_st1 "); Serial2.print(gps.satellites.value(), 6);
Serial2.print("_st2 "); Serial2.print(gps1.satellites.value(), 6);
Serial2.print("_gn "); Serial2.print(useGPS1 ? 2 : 1);
Serial2.println();
Serial.print("la "); Serial.print(currentLat, 6);
Serial.print("_lo "); Serial.print(currentLong, 6);
Serial.print("_la "); Serial.print(targetLat, 6);
Serial.print("_lo "); Serial.print(targetLong, 6);
Serial.print("_ch "); Serial.print(readCompass());
Serial.print("_st1 "); Serial.print(gps.satellites.value(), 6);
Serial.print("_st2 "); Serial.print(gps1.satellites.value(), 6);
Serial.print("_gn "); Serial.print(useGPS1 ? 2 : 1);
Serial.println();
delay(1000);
}
And the old one:
#include <TinyGPS++.h>
static const uint32_t GPSBaud = 9600;
TinyGPSPlus gps;
// Compass navigation
#include <Wire.h>
#include <QMC5883LCompass.h>
QMC5883LCompass compass;
int targetHeading;
int currentHeading;
int headingError; // signed (+/-) difference between targetHeading and currentHeading
#define HEADING_TOLERANCE 5 // tolerance +/- (in degrees) within which we don't attempt to turn to intercept targetHeading
#include "math.h"
#include <Adafruit_GPS.h>
Adafruit_GPS GPS(&Serial3);
float currentLat,
currentLong;
int distanceToTarget, // current distance to target (current waypoint)
originalDistanceToTarget; // distance to original waypoing when we started navigating to it
#define WAYPOINT_DIST_TOLERANE 1 //tolerance in meters to waypoint; once within this tolerance, will advance to the next waypoint
#define stopwaypoint 5 //second
int current_waypoint = 0;
float waypointList[10][2] = {
{ 23.202905, 72.658213},
{ 23.202849, 72.658091},
{ 23.202746, 72.658156},
{ 23.202841, 72.658310},
{ 23.202839, 72.658197},
};
float presetWaypointList[10][2] = {
{ 23.201336, 72.660916},
{ 23.201501, 72.660902},
{ 23.201659, 72.660930},
{ 23.201779, 72.660978},
{ 23.201927, 72.661102},
// ... you can continue for up to 10 waypoints
};
float targetLat = waypointList[0][0];
float targetLong = waypointList[0][1];
const int IR1 = 8;
const int IR2 = 9;
long duration;
int distance;
String bluetoothCommand = ""; // to accumulate characters from Bluetooth
void setup()
{
Serial.begin(9600); //Debug
Serial3.begin(9600); //GPS
Serial2.begin(9600); //Bluetooth
pinMode(12, INPUT_PULLUP);
setup_motor();
GPS.begin(9600); // 9600 NMEA default speed
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); // turns on RMC and GGA (fix data)
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 1 Hz update rate
GPS.sendCommand(PGCMD_NOANTENNA); // turn off antenna status info
delay(1000);
compass.init();
compass.setCalibration(-1215, 1033, -1236, 1112, -890, 0);
pinMode(IR1, INPUT);
pinMode(IR2, INPUT);
Serial.println("Start");
Serial.println(waypointList[0][0], 6);
Serial.println(waypointList[0][1], 6);
Serial.println(waypointList[1][0], 6);
Serial.println(waypointList[1][1], 6);
}
String inputString = "";
String inputdata = "";
bool stringComplete = false;
int id = 0;
int mode;
String val[5];
int nprint = 0;
int aprint = 0;
void loop()
{
int sensorVal = digitalRead(12);
while (Serial3.available() > 0)
if (gps.encode(Serial3.read()))
processGPS();
if (stringComplete)
{
Serial.println(inputString);
int n = 0;
for (int i = 0; i < 30; i++)
{
if (inputString[i] == 0)
{
n++;
if (n == 4)
break;
}
else
{
val[n] += inputString[i];
}
}
if (val[1] == "1")
{
targetLat = val[2].toFloat();
targetLong = val[3].toFloat();
}
inputString = "";
val[1] = "";
val[2] = "";
val[3] = "";
stringComplete = false;
}
if (sensorVal == LOW)
{
berhenti();
// Serial.print("la "); Serial.print(currentLat, 6);
// Serial.print("_lo "); Serial.print(currentLong, 6);
// Serial.print("_la "); Serial.print(targetLat, 6);
// Serial.print("_lo "); Serial.print(targetLong, 6);
// Serial.println();
nprint++;
if (nprint == 10000)
{
nprint = 0;
Serial2.print("la "); Serial2.print(currentLat, 6);
Serial2.print("_lo "); Serial2.print(currentLong, 6);
Serial2.print("_la "); Serial2.print(targetLat, 6);
Serial2.print("_lo "); Serial2.print(targetLong, 6);
Serial2.print("_ch "); Serial2.print(currentHeading);
Serial2.print("_st "); Serial2.print(gps.satellites.value(), 6);
Serial2.println();
}
processBluetoothCommand();
}
else if (sensorVal == HIGH)
{
// if(IR1==HIGH && IR2==HIGH){
if (currentLong > -1 && targetLong > -1)
{
currentHeading = readCompass();
calcDesiredTurn();
move_robot();
// Serial.print("_ch "); Serial.print(currentHeading);
// Serial.print("_th "); Serial.print(targetHeading);
// Serial.print("_eh "); Serial.print(headingError);
// Serial.print("_di "); Serial.print(distanceToTarget);
// Serial.println();
aprint++;
if (aprint == 200 )
{
aprint = 0;
Serial2.print("wp "); Serial2.print(current_waypoint);
Serial2.print("_ch "); Serial2.print(currentHeading);
Serial2.print("_th "); Serial2.print(targetHeading);
Serial2.print("_eh "); Serial2.print(headingError);
Serial2.print("_di "); Serial2.print(distanceToTarget);
Serial2.println();
}
}
else
{
berhenti();
Serial2.println("Check GPS");
}
/*}
else{
berhenti();
Serial2.println("Obstacle Detected");
}*/
}
}
void processGPS()
{
if (gps.location.isValid())
{
currentLat = gps.location.lat();
currentLong = gps.location.lng();
// update the course and distance to waypoint based on our new position
distanceToWaypoint();
courseToWaypoint();
}
}
// returns course in degrees (North=0, West=270) from position 1 to position 2,
// both specified as signed decimal-degrees latitude and longitude.
// Because Earth is no exact sphere, calculated course may be off by a tiny fraction.
// copied from TinyGPS library
int courseToWaypoint()
{
float dlon = radians(targetLong - currentLong);
float cLat = radians(currentLat);
float tLat = radians(targetLat);
float a1 = sin(dlon) * cos(tLat);
float a2 = sin(cLat) * cos(tLat) * cos(dlon);
a2 = cos(cLat) * sin(tLat) - a2;
a2 = atan2(a1, a2);
if (a2 < 0.0)
{
a2 += TWO_PI;
}
targetHeading = degrees(a2);
return targetHeading;
}
// returns distance in meters between two positions, both specified
// as signed decimal-degrees latitude and longitude. Uses great-circle
// distance computation for hypothetical sphere of radius 6372795 meters.
// Because Earth is no exact sphere, rounding errors may be up to 0.5%.
// copied from TinyGPS library
int distanceToWaypoint()
{
float delta = radians(currentLong - targetLong);
float sdlong = sin(delta);
float cdlong = cos(delta);
float lat1 = radians(currentLat);
float lat2 = radians(targetLat);
float slat1 = sin(lat1);
float clat1 = cos(lat1);
float slat2 = sin(lat2);
float clat2 = cos(lat2);
delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
delta = sq(delta);
delta += sq(clat2 * sdlong);
delta = sqrt(delta);
float denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
delta = atan2(delta, denom);
distanceToTarget = delta * 6372795;
// check to see if we have reached the current waypoint
if (distanceToTarget <= WAYPOINT_DIST_TOLERANE-1)
{
berhenti();
delay(stopwaypoint*1000);
nextWaypoint();
}
return distanceToTarget;
}
int readCompass()
{
compass.read();
int a;
a = compass.getAzimuth();
return (a);
}
void nextWaypoint()
{
current_waypoint++;
targetLat = waypointList[current_waypoint][0];
targetLong = waypointList[current_waypoint][1];
if ((targetLat == 0 && targetLong == 0)) // last waypoint reached?
{
berhenti();
Serial2.println("FINISH");
while (1); //PRESS RESET BUTTON
}
else
{
processGPS();
distanceToTarget = originalDistanceToTarget = distanceToWaypoint();
courseToWaypoint();
}
}
int error_output;
void calcDesiredTurn(void)
{
headingError = targetHeading - currentHeading; // calculate where we need to turn to head to destination
// adjust for compass wrap
if (headingError < -180)
headingError += 360;
if (headingError > 180)
headingError -= 360;
// calculate which way to turn to intercept the targetHeading
if (abs(headingError) <= HEADING_TOLERANCE) // if within tolerance, don't turn
error_output = 0;
else if (headingError < 60 && headingError > -60)
{
error_output = headingError;
}
else if (headingError >= 60)
error_output = 100;
else if (headingError <= -60)
error_output = -100;
}
float Kp, Kd;
void move_robot()
{
if (error_output == 0)
{
forward();
}
else if (error_output < 60)
{
if (error_output < 0)
left();
else
right();
}
else if (error_output == 100)
{
sharpright();
}
else if (error_output == -100)
{
sharpleft();
}
}
void processBluetoothCommand()
{
if (bluetoothCommand == "swp1")
{
waypointList[0][0] = currentLat;
waypointList[0][1] = currentLong;
}
else if (bluetoothCommand == "swp2")
{
waypointList[1][0] = currentLat;
waypointList[1][1] = currentLong;
}
else if (bluetoothCommand == "swp3")
{
waypointList[2][0] = currentLat;
waypointList[2][1] = currentLong;
}
else if (bluetoothCommand == "swp4")
{
waypointList[3][0] = currentLat;
waypointList[3][1] = currentLong;
}
else if (bluetoothCommand == "swp5")
{
waypointList[4][0] = currentLat;
waypointList[4][1] = currentLong;
}
else if (bluetoothCommand == "pswp")
{
for (int i = 0; i < 10; i++)
{
waypointList[i][0] = presetWaypointList[i][0];
waypointList[i][1] = presetWaypointList[i][1];
}
Serial2.println("Waypoint list swapped to preset!");
}
targetLat = waypointList[0][0];
targetLong = waypointList[0][1];
}
void serialEvent2() //bluetooth
{
while (Serial2.available())
{
char inChar = (char)Serial2.read();
if (inChar == '\n') // Assuming newline marks the end of a command
{
processBluetoothCommand();
bluetoothCommand = ""; // Clear the command for the next one
}
else
{
bluetoothCommand += inChar;
}
}
}