RC controlled arduino robot question about software ! help !

hello everyone,
I am trying to program an arduino robot which i build using the NRF24L01 transceiver and this motor driver : https://www.aliexpress.com/item/2-channel-DC-motor-driving-module-Positive-inversion-PWM-speed-mini-motor-dual-h-bridge-stepper/32811507123.html?spm=a2g0s.9042311.0.0.zBqTl0

what I am trying to do is controlling the robot using a joystick potentiometers for forward, backward, left and right with the same stick.
The robot has 2 motorized wheels and 1 castor, so the steering is by differential driver
I managed to make the wireless connection between the 2 NRF24L01 modules and receiving the potentiometers values from both pots of the joystick. I managed too, to make the motors go forward alone and backward alone but i did not manage to make them turn while pushing the throttle forward or backward at the same time ! The results I need to reach is to hit the throttle in an analog form and make the robot go forward gradually with speed controlling and and same for turning like an RC car. So I need help please with the software which i am not able so far to write. Below is the Receiver side which is the problem, the transmitter side is successfully written and all it does is sending the values of each of the two potentiometers so please help me write the software for motor forward backward left and right :

#include <SPI.h>
//#include <nRF24L01.h>
#include <RF24.h>

int msgRX[2]; //Message to be transmitted, can contain up to 2 array elements, 2 bytes
int ackMessage[2]; //Acknowledgment message, means the message that will be received from the receiver or the car, 1 element for the moment

RF24 radio(7, 8); // CE, CSN

//const byte address[6] = "00001";

//Defining the radio variables and values
const uint64_t pipe = 0xE8E8F0F0E1LL; //pipe address
const rf24_datarate_e dataRate = RF24_250KBPS; //Data rate defined in the documentations, RF24_250KBPS, RF24_1MBPS or RF24_2MBPS

const int motorPin1 = 3; 
const int motorPin2 = 10;
const int motorPin3 = 5; 
const int motorPin4 = 6; 

int Throttle;
int Steering;
int Throttlemap;
int Motor2Steering;

void setup() {
  //Set pins as outputs
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
  pinMode(motorPin4, OUTPUT);
  
  //Serial.begin(9600);
  radio.begin();
  radio.setDataRate(RF24_250KBPS);
  //radio.openReadingPipe(0, address);
  radio.openReadingPipe(1, pipe);
  //radio.setPALevel(RF24_PA_MAX);//Power Amplifier (PA) level to one of four levels RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX
  radio.enableAckPayload();
  radio.startListening();
  
}
void loop() {
  //ackMessage[1] = 200;
  //radio.writeAckPayload(1, ackMessage, sizeof(ackMessage));
 
  while (radio.available()) {
    radio.read(msgRX, sizeof(msgRX)); 
    Throttle = msgRX[0]; //middle throttle value is 121
    Steering = msgRX[1]; //middle steering value is 125
    
    //FORWARD or BACKWARD
    if (Throttle <= 121 && Steering == 125) {
      Throttlemap = map(Throttle, 0, 121, 255, 0);
      // RIGHT MOTOR
      analogWrite(motorPin1, Throttlemap); // Right Motor forward
      analogWrite(motorPin2, 0);
      
      // LEFT MOTOR
      analogWrite(motorPin3, Throttlemap); // Left Motor forward
      analogWrite(motorPin4, 0);
    
    } else if (Throttle > 121 && Steering == 125) {
      Throttlemap = map(Throttle, 121, 255, 0, 255);
      analogWrite(motorPin1, 0);
      analogWrite(motorPin2, Throttlemap);
     
      analogWrite(motorPin3, 0);
      analogWrite(motorPin4, Throttlemap);
    } else if (Throttle > 121 && Steering == 125){
    
    } else if (Throttle == 121 && Steering == 125){
      analogWrite(motorPin1, 0);
      analogWrite(motorPin2, 0);
     
      analogWrite(motorPin3, 0);
      analogWrite(motorPin4, 0);
    }
    
  }
}

You seem to have left out a lot of important detail. So I can't give you a very detailed answer. It looks like you have a throttle and a steering variable. I would use the throttle variable to control the speed and the steering variable to control the steering. How you would do that I don't know because I don't know if your robot turns by steering the wheels or by differential drive or if it has 2 wheels or 4 or really anything about your particular robot. Why wouldn't you tell those things if you want someone to help you figure out how to write code to steer it?

Delta_G:
You seem to have left out a lot of important detail. So I can't give you a very detailed answer. It looks like you have a throttle and a steering variable. I would use the throttle variable to control the speed and the steering variable to control the steering. How you would do that I don't know because I don't know if your robot turns by steering the wheels or by differential drive or if it has 2 wheels or 4 or really anything about your particular robot. Why wouldn't you tell those things if you want someone to help you figure out how to write code to steer it?

Sorry forgot these details, i'll add them, the robot has 2 motorized wheels and 1 castor, so the steering is by differential driver

firashelou:
Below is the Receiver side which is the problem,

Please post the complete program after (if you have not already done so) using the AutoFormat tool to lay out the code for easy reading.

Also please tell us what a message from the transmitter contains.

...R
Simple nRF24L01+ Tutorial

Robin2:
Please post the complete program after (if you have not already done so) using the AutoFormat tool to lay out the code for easy reading.

Also please tell us what a message from the transmitter contains.

...R
Simple nRF24L01+ Tutorial

ok Robin2 i'll share when I go home from work, but the problem is not making the wireless connection, it's just how to make the robot go forward backward and steer with differential drive while having control over the speed with the joystick as it goes forward and left and right

Robin I added the RX codes

firashelou:
Robin I added the TX codes

Do you mean that you added the code to your Original Post? I can't remember what was there originally.

Don't make retrospective changes to Posts (other than to correct typos) as it makes the flow of the Thread very difficult to follow. Post new stuff in a new Reply.

In any case, I believe you said the problem is with the receiver code.

...R

Robin2:
Do you mean that you added the code to your Original Post? I can't remember what was there originally.

Don't make retrospective changes to Posts (other than to correct typos) as it makes the flow of the Thread very difficult to follow. Post new stuff in a new Reply.

In any case, I believe you said the problem is with the receiver code.

...R

yes to the original post, the problem is with the receiver only yes

here are the codes of the Receiver:

#include <SPI.h>
//#include <nRF24L01.h>
#include <RF24.h>

int msgRX[2]; //Message to be transmitted, can contain up to 2 array elements, 2 bytes
int ackMessage[2]; //Acknowledgment message, means the message that will be received from the receiver or the car, 1 element for the moment

RF24 radio(7, 8); // CE, CSN

//const byte address[6] = "00001";

//Defining the radio variables and values
const uint64_t pipe = 0xE8E8F0F0E1LL; //pipe address
const rf24_datarate_e dataRate = RF24_250KBPS; //Data rate defined in the documentations, RF24_250KBPS, RF24_1MBPS or RF24_2MBPS

const int motorPin1 = 3;
const int motorPin2 = 10;
const int motorPin3 = 5;
const int motorPin4 = 6;

int Throttle;
int Steering;
int Throttlemap;
int Motor2Steering;

void setup() {
  //Set pins as outputs
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
  pinMode(motorPin4, OUTPUT);
 
  //Serial.begin(9600);
  radio.begin();
  radio.setDataRate(RF24_250KBPS);
  //radio.openReadingPipe(0, address);
  radio.openReadingPipe(1, pipe);
  //radio.setPALevel(RF24_PA_MAX);//Power Amplifier (PA) level to one of four levels RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX
  radio.enableAckPayload();
  radio.startListening();
 
}
void loop() {
  //ackMessage[1] = 200;
  //radio.writeAckPayload(1, ackMessage, sizeof(ackMessage));
 
  while (radio.available()) {
    radio.read(msgRX, sizeof(msgRX));
    Throttle = msgRX[0]; //middle throttle value is 121
    Steering = msgRX[1]; //middle steering value is 125
   
    //FORWARD or BACKWARD
    if (Throttle <= 121 && Steering == 125) {
      Throttlemap = map(Throttle, 0, 121, 255, 0);
      // RIGHT MOTOR
      analogWrite(motorPin1, Throttlemap); // Right Motor forward
      analogWrite(motorPin2, 0);
     
      // LEFT MOTOR
      analogWrite(motorPin3, Throttlemap); // Left Motor forward
      analogWrite(motorPin4, 0);
   
    } else if (Throttle > 121 && Steering == 125) {
      Throttlemap = map(Throttle, 121, 255, 0, 255);
      analogWrite(motorPin1, 0);
      analogWrite(motorPin2, Throttlemap);
     
      analogWrite(motorPin3, 0);
      analogWrite(motorPin4, Throttlemap);
    } else if (Throttle > 121 && Steering == 125){
   
    } else if (Throttle == 121 && Steering == 125){
      analogWrite(motorPin1, 0);
      analogWrite(motorPin2, 0);
     
      analogWrite(motorPin3, 0);
      analogWrite(motorPin4, 0);
    }
   
  }
}

I presume your code is correctly receiving the two values for Throttle and Steering. If you have not confirmed that then you should do so asap.

If I understand the problem correctly the speed of each motor must take account of both the throttle value and the steering value. To do that I would create a separate steering value for each motor. Assuming the full range of steering values is 0 to 250 (you say 125 is the centre) then I would do something like this (I am treating numbers > 125 as "turn right")

rightSteerValue = Steering - 125;
leftSteerValue = - rightSteerValue;

rightMotorPower = Throttle + rightSteerValue;
leftMotorPower = Throttle + leftSteerValue;

if (rightMotorPower > 255) {
  rightMotorPower = 255;
}
if (rightMotorPower < 0) {
  rightMotorPower = 0;
}
 // likewise for leftMotorPower

analogwrite(rightMotorPin, rightMotorPower);
// etc

As with all code temporarily add some Serial.print() statements so you can see f the values are being calculated properly.

...R

Robin2:
I presume your code is correctly receiving the two values for Throttle and Steering. If you have not confirmed that then you should do so asap.

If I understand the problem correctly the speed of each motor must take account of both the throttle value and the steering value. To do that I would create a separate steering value for each motor. Assuming the full range of steering values is 0 to 250 (you say 125 is the centre) then I would do something like this (I am treating numbers > 125 as "turn right")

rightSteerValue = Steering - 125;

leftSteerValue = - rightSteerValue;

rightMotorPower = Throttle + rightSteerValue;
leftMotorPower = Throttle + leftSteerValue;

if (rightMotorPower > 255) {
 rightMotorPower = 255;
}
if (rightMotorPower < 0) {
 rightMotorPower = 0;
}
// likewise for leftMotorPower

analogwrite(rightMotorPin, rightMotorPower);
// etc




As with all code temporarily add some Serial.print() statements so you can see f the values are being calculated properly.

...R

thank you Robin2 i'll check the functionality of the codes when I get back home,
yes I am receiving the values correctly from the Transmitter the problem is just in forward backward left and right
About the 125, it is not exactly the middle because the full value is 255 but when i checked with Serial.print() I received this value 125 for the neutral position and 121 for the other potentiometer

Note: As you can see in my codes to make things easier I remapped the values of the potentiometers

hello Robin2,
here is my final code, but it is not working as it is supposed to, which means if i push the throttle forward, the robot should go forward, if i push the throttle backward the robot must go backward, if i push it to the right the robot must go to the right and if left must go to left, instead the right motor starts by rolling when i click the on switch
I added some codes for trying to convert the value of pots as it must be :

void loop() {
  //ackMessage[1] = 200;
  //radio.writeAckPayload(1, ackMessage, sizeof(ackMessage));
 
  while (radio.available()) {
    radio.read(msgRX, sizeof(msgRX)); 
    Throttle = msgRX[0]; //middle throttle value is 121
    Steering = msgRX[1]; //middle steering value is 125
    
    //Throttle = map(Throttle, 0, 121, 255, 0);
    //Steering = map(Steering, 125, 255, 255, 0);
      if (Throttle <= 134) {
          Throttle = map(Throttle, 0, 134, 255, 0);
      } else if (Throttle > 134) {
          Throttle = map(Throttle, 134, 255, 0, 255);
      } 
      if (Steering <= 125) {
          Steering = map(Steering, 0, 125, 255, 0);
      } else if (Steering > 125) {
          Steering = map(Steering, 125, 255, 0, 255);
      }
    
    int rightSteerValue = Steering - 125;
    int leftSteerValue = - rightSteerValue;
    
    int rightMotorPower = Throttle + rightSteerValue;
    int leftMotorPower = Throttle + leftSteerValue;
    
    if (rightMotorPower > 255) {
      rightMotorPower = 255;
    }
    if (rightMotorPower < 0) {
      rightMotorPower = 0;
    }
    
    if (leftMotorPower > 255) {
      leftMotorPower = 255;
    }
    if (leftMotorPower < 0) {
      leftMotorPower = 0;
    }
    
    analogWrite(motorPin1, rightMotorPower);
    //analogWrite(motorPin2, 0);
    
    analogWrite(motorPin3, leftMotorPower);
    //analogWrite(motorPin4, 0);
    
    
    
  }
}

firashelou:
here is my final code, but it is not working as it is supposed to, which means if i push the throttle forward, the robot should go forward, if i push the throttle backward the robot must go backward, if i push it to the right the robot must go to the right and if left must go to left, instead the right motor starts by rolling when i click the on switch

If something starts happening when you switch it on the problem is probably in the setup() code or the initial values in variables - which you have not posted. Always post a complete program.

You don't have any Serial.print() statements in your program to allow you to see if the variables have the values you expect them to have. It is not possible to figure out problems without watching how things are changing within the program.

If it was my project I would have one function to receive the data from the nRF24 and a separate function to control the motors. That way you could test each of the separately

...R

here is my final code

I think you mean that it is your latest code, not your final code if

it is not working as it is supposed to

Take Robin's advice and print the value of pertinent variables at strategic points in your program to track what is going on.

I did not add the serial.print in the RX because my arduino is not connecting to pc and i cannot change it because it is connected to the hardware so what i am doing is taking the Atmega from it and place it on another Uno board program it and then get it back to the circuit but i Serial.printed the values on the transmitter and they print as wanted with remapped values !
here is my Transmitter codes:

#include <SPI.h>
#include <RF24.h>
//#include <nRF24L01.h>
//#include <LiquidCrystal.h> //LCD Library

//1st byte is for throttle value from pot
//2nd byte is for Steering Left state
//3rd byte is for Steering Right state
//4th byte is for reverse state
//5th byte is for 
//6th byte is for 
//7th byte is for 
int msgTX[2]; //Message to be transmitted, can contain up to 2 array elements, 2 bytes
int ackMessage[2]; //Acknowledgment message, means the message that will be received from the receiver or the car, 1 element for the moment

//Defining radio object for the RF24 function
RF24 radio(7, 8); // CE, CSN
//const byte address[6] = "00001";

//Defining the radio variables and values
const uint64_t pipe = 0xE8E8F0F0E1LL; //pipe address
const rf24_datarate_e dataRate = RF24_250KBPS; //Data rate defined in the documentations, RF24_250KBPS, RF24_1MBPS or RF24_2MBPS

//Steering potentiometers
const byte Throttle = A0;
const byte Steering = A1;

void setup() {
 //Serial.begin(9600);
 radio.begin();
 radio.setDataRate(dataRate);
 //radio.openWritingPipe(address);
 radio.enableAckPayload(); //enables receiving data from receiver side
 //radio.setPALevel(RF24_PA_MIN); //Power Amplifier (PA) level to one of four levels RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX
 //radio.stopListening();
 
}
void loop() {
 int ThrottleValue = analogRead(Throttle);  // read the value from the sensor
 ThrottleValue =  map(ThrottleValue, 0, 1023, 255, 0); //middle throttle value 121
 
 int SteeringValue = analogRead(Steering);  // read the value from the sensor
 SteeringValue =  map(SteeringValue, 0, 1023, 0, 255); //middle steering value 125
 
 //Serial.print("Throttle : ");
 //Serial.println(ThrottleValue);
 //Serial.print("Steering : ");
 //Serial.println(SteeringValue);
 //delay(1000);
 
 radio.openWritingPipe(pipe);
 msgTX[0] = ThrottleValue;
 msgTX[1] = SteeringValue;
 radio.write(msgTX, sizeof(msgTX)); //Sends the Data
 AcknowledgmentDATA();
 
}

//DATA Receiving from the Receiver part, Acknowledgment Data
void AcknowledgmentDATA(){
   
   while ( radio.isAckPayloadAvailable() ){
       //Serial.println("Ack Available");
radio.read(ackMessage, sizeof(ackMessage));
       int value = ackMessage[1];
       //Serial.println(value); 
//delay(1000);

  }
  //else{
  //    Serial.println("No connection is made");
  //}
 
}

Proving that the Tx has the correct values is a start but without knowing what the Rx is getting you are no further forward. What exactly is the receiving hardware and how much can you change it ?

UKHeliBob:
Proving that the Tx has the correct values is a start but without knowing what the Rx is getting you are no further forward. What exactly is the receiving hardware and how much can you change it ?

the receiving hardware did not change, it's just the module in the start post with arduino uno, NRF24L01 and 2 motors like these : https://872c4715dbe9f10b83d1-0b39dab3ba460c18aad59cf32aacf5c8.ssl.cf5.rackcdn.com/TE696-E-10-9.jpg

the receiving hardware did not change, it's just the module in the start post with arduino uno, NRF24L01 and 2 motors

So there is a Uno on the receiving end. Is that correct ?

If so then why can't you connect it to your PC to see what it is receiving ?

firashelou:
I did not add the serial.print in the RX because my arduino is not connecting to pc and i cannot change it because it is connected to the hardware

That's like trying to catch a goldfish in a large tank in the dark with your eyes closed.

You might get lucky and be successful, but .....

Find some way, perhaps with a USB-TTL cable, to communicate with your PC from the hardware where the Atmega 328 does its work.

You said in Reply #8 that you are receiving the data correctly so there is no point posting the transmitter code.

...R

PS ... (following @UKHeliBob's question) I have been assuming that there is an Atmega 328 on the receiving end so please do let us know if that is a wrong assumption.

UKHeliBob:
So there is a Uno on the receiving end. Is that correct ?

If so then why can't you connect it to your PC to see what it is receiving ?

I don't know what is the problem when I connect it, it gives the sound of usb connect then it gives another sound of usb disconnect :confused:

Robin2:
That's like trying to catch a goldfish in a large tank in the dark with your eyes closed.

You might get lucky and be successful, but .....

Find some way, perhaps with a USB-TTL cable, to communicate with your PC from the hardware where the Atmega 328 does its work.

You said in Reply #8 that you are receiving the data correctly so there is no point posting the transmitter code.

...R

PS ... (following @UKHeliBob's question) I have been assuming that there is an Atmega 328 on the receiving end so please do let us know if that is a wrong assumption.

true there is an arduino uno on the receiving end which has a problem of connecting to PC i will try to change the board, there is plenty of connections

hello,
I changed the arduino uno on the receiving side, now i can connect it to laptop and receive the Serial.print data

I am getting these values on the monitor and not 0:
rightSteerValue:
-2388

here is my current sketch for the receiver:

#include <SPI.h>
//#include <nRF24L01.h>
#include <RF24.h>

int msgRX[2]; //Message to be transmitted, can contain up to 2 array elements, 2 bytes
int ackMessage[2]; //Acknowledgment message, means the message that will be received from the receiver or the car, 1 element for the moment

RF24 radio(7, 8); // CE, CSN

//const byte address[6] = "00001";

//Defining the radio variables and values
const uint64_t pipe = 0xE8E8F0F0E1LL; //pipe address
const rf24_datarate_e dataRate = RF24_250KBPS; //Data rate defined in the documentations, RF24_250KBPS, RF24_1MBPS or RF24_2MBPS

const int motorPin1 = 3; 
const int motorPin2 = 10;
const int motorPin3 = 5; 
const int motorPin4 = 6; 

int Throttle;
int Steering;
int Throttlemap;
int Motor2Steering;

void setup() {
  //Set pins as outputs
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
  pinMode(motorPin4, OUTPUT);
  
  Serial.begin(9600);
  radio.begin();
  radio.setDataRate(RF24_250KBPS);
  //radio.openReadingPipe(0, address);
  radio.openReadingPipe(1, pipe);
  //radio.setPALevel(RF24_PA_MAX);//Power Amplifier (PA) level to one of four levels RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX
  radio.enableAckPayload();
  radio.startListening();
  
}
void loop() {
  //ackMessage[1] = 200;
  //radio.writeAckPayload(1, ackMessage, sizeof(ackMessage));
 
  while (radio.available()) {
    radio.read(msgRX, sizeof(msgRX)); 
    Throttle = msgRX[0]; //middle throttle value is 121
    Steering = msgRX[1]; //middle steering value is 125
    
    //Throttle = map(Throttle, 0, 121, 255, 0);
    //Steering = map(Steering, 125, 255, 255, 0);
      if (Throttle <= 134) {
          Throttle = map(Throttle, 0, 134, 255, 0);
      } else if (Throttle > 134) {
          Throttle = map(Throttle, 134, 255, 0, 255);
      } 
      if (Steering <= 125) {
          Steering = map(Steering, 0, 125, 255, 0);
      } else if (Steering > 125) {
          Steering = map(Steering, 125, 255, 0, 255);
      }
    
    int rightSteerValue = Steering - 125;
    int leftSteerValue = - rightSteerValue;
    Serial.println("rightSteerValue: ");
    Serial.println(rightSteerValue);
    int rightMotorPower = Throttle + rightSteerValue;
    int leftMotorPower = Throttle + leftSteerValue;
    
    if (rightMotorPower > 255) {
      rightMotorPower = 255;
    }
    if (rightMotorPower < 0) {
      rightMotorPower = 0;
    }
    
    if (leftMotorPower > 255) {
      leftMotorPower = 255;
    }
    if (leftMotorPower < 0) {
      leftMotorPower = 0;
    }
    
    analogWrite(motorPin1, rightMotorPower);
    //analogWrite(motorPin2, 0);
    
    analogWrite(motorPin3, leftMotorPower);
    //analogWrite(motorPin4, 0);
    
    
  }
}