Odd robot behavior

#include <SPI.h>
#include <RF24.h>
#include "drive.h"
const int Bat = A0;
// Pin Definitions
int InA1 = 2;
int InA2 = 4;
int EnL = 3;
int InB1 = 6;
int InB2 = 7;
int EnR = 5;
int stby = 8;
int LED = 6;
// Other global variables
int Spd = 0;
int Trn = 0;
bool b1 = false;
bool b2 = false;
bool b3 = false;
bool led = false;
RF24 radio(10, 9);//ce/cs 
bool isTransmitter = false; //if true, device starts as transmitter
void setup() {
  Serial.begin(9600);
  radio.begin();
  radio.openWritingPipe(00001);//needs to be opposite on other device
  radio.setPALevel(RF24_PA_HIGH);//   ^
  radio.openReadingPipe(1, 000002);// |
  radio.startListening();

  pinMode(InA1, OUTPUT);
  pinMode(InA2, OUTPUT);
  pinMode(InB1, OUTPUT);
  pinMode(InB2, OUTPUT);
  pinMode(EnL, OUTPUT);
  pinMode(EnR, OUTPUT);
  pinMode(stby, OUTPUT);
  pinMode(LED, OUTPUT);
 
}

void loop() {

  
 Drive();
 
  if (isTransmitter) {
    handleTransmitterMode();//if transmitter is true, go to that function
  } else {
    handleReceiverMode();//if transmitter is false, go to that function
  }
  while (b1){
  digitalWrite(stby, HIGH);
  analogWrite(EnL, 255);
  analogWrite(EnR, 255);
  digitalWrite(InA1, HIGH);
  digitalWrite(InA2, LOW);
  digitalWrite(InB1, HIGH);
  digitalWrite(InB2, LOW);
  handleReceiverMode();
  handleTransmitterMode();
  }
    while (b2){
  digitalWrite(stby, HIGH);
  analogWrite(EnL, 255);
  analogWrite(EnR, 255);
  digitalWrite(InA1, LOW);
  digitalWrite(InA2, HIGH);
  digitalWrite(InB1, HIGH);
  digitalWrite(InB2, LOW);
  handleReceiverMode();
  handleTransmitterMode();
  }
  if(b3){
    digitalWrite(LED, HIGH);
  }
 }


void handleTransmitterMode() {
 int rawValue = analogRead(Bat);
  float batteryVoltage = (float)rawValue * (12.6 / 1023.0);
  float batteryPercentage = map(batteryVoltage, 7.2, 12.6, 0, 100);
  Serial.println();
  radio.stopListening(); //turns radio into transmitter

  delay(10);
   String bat = "bat" + String(batteryPercentage);
  radio.write(bat.c_str(), bat.length() + 1); // +1 to include null terminator
  //toggles transmitter role

  char text[] = "Change"; //converts the text "change" into an array under the name text
  radio.write(&text, sizeof(text)); // radio sends the message and the size of the message
 
  //  char text1[] = "bat50"; //converts the text "change" into an array under the name text
//  radio.write(&text1, sizeof(text1)); // radio sends the message and the size of the message
   isTransmitter = !isTransmitter;
}


void handleReceiverMode() {
  radio.startListening(); //toggles radio into reciever mode
  if (radio.available()) {
    char text[32] = ""; //clears the 32 byte variable known as "text"
    radio.read(&text, sizeof(text)); //reads the transmission

       if (strcmp(text, "Zero") == 0) {
        digitalWrite(EnL, LOW);
        digitalWrite(EnR, LOW);
        Spd=0;
        Trn=0;
   }

   if (strcmp(text, "Change") == 0) { //checks if teh transmission is "change", if it is
     isTransmitter = !isTransmitter; //then toggle
      
    }
        if (strncmp(text, "spd", 3) == 0) {
            int spd = extractNumber(text);
         //   Serial.print("Received SPD value: ");
         //   Serial.println(spd);
            Spd=spd;
// delay(500); //unblock these comments to read the variables
        }
if (strncmp(text, "trn", 3) == 0) {
            int trn = extractNumber(text);
       //   Serial.print("Received trn value: ");
         // Serial.println(trn);
            Trn=trn;
 //delay(500);
}
if (strncmp(text, "b1", 2) == 0) {
b1 = !b1;
}
if (strncmp(text, "b2", 2) == 0) {
b2 = !b2;
}
if (strncmp(text, "b3", 2) == 0) {
b3 = !b3;
Serial.println("b3 pressed!!!!!!!");
led = true;
}
}
}


int extractNumber(const char* text) {
    int result = 0;
    int sign = 1;  // Positive by default
    int i = 3;  // Start from the fourth character after "spd"

    if (text[i] == '-') {
        sign = -1;
        i++;
    }

    while (text[i] >= '0' && text[i] <= '9') {
        result = result * 10 + (text[i] - '0');
        i++;
    }

    return sign * result;
}



void Drive(){
  int Speed = map(Spd, 0, 512, 0, 255);
  
  if(Spd>10){ //forward
  digitalWrite(stby, HIGH);
  analogWrite(EnL, Speed);
  analogWrite(EnR, Speed);
  digitalWrite(InA1, HIGH);
  digitalWrite(InA2, LOW);
  digitalWrite(InB1, HIGH);
  digitalWrite(InB2, LOW);
  //Serial.println(Speed);
}
 if(Spd<-10){ //backward
 Speed=Speed*-1;
 digitalWrite(stby, HIGH);
  analogWrite(EnL, Speed);
  analogWrite(EnR, Speed);
  digitalWrite(InA1, LOW);
  digitalWrite(InA2, HIGH);
  digitalWrite(InB1, LOW);
  digitalWrite(InB2, HIGH);
  //Serial.println(Speed);
  }

if (Trn > 15) {
  digitalWrite(stby, HIGH);
  int Left = map((Spd + Trn), 0, 510, 0, 255);
  int Right = map(Spd, 0, 510, 0, 255);

  analogWrite(EnL, Left);
  analogWrite(EnR, Right);

Serial.print("Left: ");
 Serial.println(Left);
Serial.print("Right: ");
  Serial.println(Right);
  //delay(100);
}

if (Trn < -15) {
  digitalWrite(stby, HIGH);
  Trn*-1; // Make Trn positive
  int Left = map(Spd, 0, 510, 0, 255);
  int Right = map((Spd - Trn), 0, 510, 0, 255);

  analogWrite(EnL, Left);
  analogWrite(EnR, Right);

 Serial.print("Left: ");
Serial.println(Left);
  Serial.print("Right: ");
  Serial.println(Right);
 // delay(100);
}
}



so the robot works perfectly fine when it drives forward, backwards, or turns right. But when i put the joystick fully left, so we want the right motors to spin, in serial i get "right 255, left 0". However, the right motors just stall out.

 digitalWrite(stby, HIGH);
  analogWrite(EnL, 255);
  analogWrite(EnR, 255);
  digitalWrite(InA1, LOW);
  digitalWrite(InA2, LOW);
  digitalWrite(InB1, LOW);
  digitalWrite(InB2, HIGH);
  delay(2000);

when i try just this, the right motors spin just fine, and the left stay still. im stumped.

When turning, should both motors be enabled?

don't see this in the code you posted?

why repeatedly invoke the code to set the speed and direction of the motors instead of recognizing a command (e.g. "b1") and processing it just once? why those while loops in loop()? shouldn't these only be invoked if handleReciveMode() is invoked

why invoke the following in multiple locations, conditionally and both unconditionally?

No, when the joystick is all the way left, only the right motors should be enabled so that the robot pivots left. But as the joystick hugs the left wall, and goes forward, the left motors should turn on slowely to scale down the pivoting.

The first snippet was a test i did to make sure the right motors work alone, and they did.

This is a robot thats revieving and transmitting so depending on the function recieved from the other end i might ask it to send something back. Which is why it flips trans/recv so many times.

And it constantly updates speed and turning because i am using a joystick to control it, and b1, b2, and b3 (which dont work currently but thats not my priority right now, i know hkw to fix those) are seperate functions. So on my controller i can press b1 and it will stay forward, and then when i press it again i release control back to the joystick if that makes sense.

i don't see where your code reads a joystick (analogRead() ?) and don't see code that turns right (or outputs "right 255 ...")

why not use a single well tested function in all cases

void
driveMotor (
    int  spdLeft,
    int  spdRight )
{
    if (0 > spdLeft) {
        digitalWrite (InA1, LOW);
        digitalWrite (InA2, HIGH);
    }
    else {
        digitalWrite (InA1, HIGH);
        digitalWrite (InA2, LOW);
    }

    if (0 > spdRight) {
        digitalWrite (InB1, LOW);
        digitalWrite (InB2, HIGH);
    }
    else {
        digitalWrite (InB1, HIGH);
        digitalWrite (InB2, LOW);
    }

    analogWrite (EnL, spdLeft);
    analogWrite (EnR, spdRight);
}

Because it is a reciever. The joystick isnt plugged into the reciever, its in the transmitter (controller) and the data is transferred and revieved as "spd" (y axis) and "trn" x axis.

The code responsible for turning is the x>15 (the working one) and x<-15 (the one with a problem) functions.

Its literally the same code except i turn "trn" into a positive with trn*-1; and it stops working. But when i print "right" into serial it outputs as 255 which is exactly what i want, however the motors dont spin.

When i do the opposite (trn>15), the left motors spin just fine.

don't understand the purpose of trn*-1; (besides it not having any effect

C:\stuff\SW\Arduino\_Others\Tst\Tst.ino:243:12: warning: statement has no effect [-Wunused-value]
         Trn*-1; // Make Trn positive

why does it need to be made positive if it is subtracted from `

i get the following using the code below

Drive: trn 20, spd 0
  > 15: Left 10, Right 0
Drive: trn -20, spd 0
  < -15: Left 0, Right 10

void Drive()
{
    sprintf (s, "Drive: trn %d, spd %d", Trn, Spd);
    Serial.println (s);

...

    if (Trn > 15) {
        digitalWrite(stby, HIGH);
        int Left = map((Spd + Trn), 0, 510, 0, 255);
        int Right = map(Spd, 0, 510, 0, 255);

        analogWrite(EnL, Left);
        analogWrite(EnR, Right);

#if 1
        sprintf (s, "  > 15: Left %d, Right %d", Left, Right);
        Serial.println (s);
#else
        Serial.print("Left: ");
        Serial.println(Left);
        Serial.print("Right: ");
        Serial.println(Right);
        //delay(100);
#endif
    }

    if (Trn < -15) {
        digitalWrite(stby, HIGH);
        Trn*-1; // Make Trn positive
        int Left = map(Spd, 0, 510, 0, 255);
        int Right = map((Spd - Trn), 0, 510, 0, 255);

        analogWrite(EnL, Left);
        analogWrite(EnR, Right);

#if 1
        sprintf (s, "  < -15: Left %d, Right %d", Left, Right);
        Serial.println (s);
#else
        Serial.print("Left: ");
        Serial.println(Left);
        Serial.print("Right: ");
        Serial.println(Right);
        // delay(100);
#endif
    }
}

I mean the problem isnt me getting the incorrect values.

For trn>15 i get left: 255 right:0
And this works.

For trn<-15 i get left:0, right 255
Which should be what we want, but the motors dont spin.

And as i said when i make a function to just spin the right motors it works fine which is why im really confused.

This makes me think its not the EnL or EnR values that are skewed, its thr InB values that are skewed and its trying to make both high or both low, but i cant find that in the code anywhere.

Im not at home atm but ill mess around with it some more soon and try your code.

Are you really comparing to a minus 15?

Yes. Obviously the analog value is from 0-1023 or whatever it is, but on my transmitter i subtract 512 which makes it go from -512 to +512, and the center of the joystick is 0.

And x<-15 is true when i move the joystick to the left, so i dont think thats my problem. It displays the serial print info i have in there.

Deadband: -15...15

Ill also upload some videos later today of the issue im facing and proof that the right motors can spin on their own so its not a hardware issue.

And ill test with a multi meter to see if its maybe writing inb1 high inb2 high

Check grounding from Arduino GND to motor driver board GND to power supply ground. The two boards need to have the same reference.

yep, thats not the issue.

ive just stumbled upon the weirdest thing.

if (Trn < -15) {
  digitalWrite(stby, HIGH);

  int Left = map(Spd, 0, 510, 0, 255);
  int Right = map((Spd-Trn), 0, 510, 0, 255);
Serial.print("Left: ");
Serial.println(Left);
Serial.print("Right: ");
Serial.println(Right);
analogWrite(EnL, Left);
analogWrite(EnR, 255);


when i make right 255 by default like this, it works as intended, but obviously we lose scalability which is what im going after. If i switch back to "Right" variable, the variable is 258 aswell which should work right? but no it stalls out.

the argument to analogWrite is 8 bits, so it may be interpreted as 3. see analogWrite()

1 Like

that seems to be the issue, if i set analogWrite(EnR, 258); the same whining happens.

yep , you were right. Thank you so much. Any idea why int Right = map((Spd-Trn), 0, 510, 0, 255); can map it to 258? just a rounding error? anyways ive set it to 252 as max and the Right variable seems to not go over 255, and it works. Thank you so much

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