Remote Controlled Car

I have built an remote controlled car which sends signals from remote to car via nrf24l01 using an anlog joystick I have coded the transmitter and receiver code. Everything works fine, it moves forward, backward, left and right but the problem I get is that when the joystick is at resting or normal position the 2 motors connected to the motor driver l298n rotate forward for half a second then stop then rotate forward for half a second then stop, it continuosly does that. The values for restiong position is 518 or 517, 502 What do I do?

Transmitter code

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

RF24 radio(9,10); //CE, CSN

const byte address[] = "12345";

void setup(){
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_LOW);
}

void loop(){
  int xValue = analogRead(A0);
  int yValue = analogRead(A1);

  radio.write(&xValue, sizeof(xValue));
  radio.write(&yValue, sizeof(yValue));

  delay(100);
}

Receiver Code

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

RF24 radio(9, 10); // CE, CSN

const byte address[] = "12345";

const int enA = A0;
const int enB = A1;
const int in1 = 2;
const int in2 = 3;
const int in3 = 4;
const int in4 = 5;

void setup() {
  radio.begin();
  radio.openReadingPipe(1, address);
  radio.setPALevel(RF24_PA_LOW);
  radio.startListening();

  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);

  Serial.begin(9600); // Initialize Serial communication at a baud rate of 9600
}

void loop() {
  int xValue;
  int yValue;

  if (radio.available()) {
    radio.read(&xValue, sizeof(xValue));
    radio.read(&yValue, sizeof(yValue));
  }

  int restingThreshold = 30;

  // Implement a deadzone for joystick values
  if (abs(xValue - 517) <= restingThreshold && abs(yValue - 502) <= restingThreshold) {
    xValue = 517; // Set it to the center value
    yValue = 502; // Set it to the center value
  }

  Serial.print("xValue: ");
  Serial.print(xValue);
  Serial.print(", yValue: ");
  Serial.println(yValue);

  // Define the range for joystick values to stay still
  if (xValue >= 512 && xValue <= 517 && yValue >= 498 && yValue <= 502) {
    // Motors stay still
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
    digitalWrite(in3, LOW);
    digitalWrite(in4, LOW);
    analogWrite(enA, 0);
    analogWrite(enB, 0);
  } else {
    // Control the motors based on joystick position
    if (xValue >= 510 && xValue <= 518) {
      if (yValue >= 0 && yValue <= 8) { // Forward
        digitalWrite(in1, LOW);
        digitalWrite(in2, HIGH);
        digitalWrite(in3, HIGH);
        digitalWrite(in4, LOW);
        analogWrite(enA, 255);
        analogWrite(enB, 255);
      } 
      else if (yValue >= 1018 && yValue <= 1026) { // Backward
        digitalWrite(in1, HIGH);
        digitalWrite(in2, LOW);
        digitalWrite(in3, LOW);
        digitalWrite(in4, HIGH);
        analogWrite(enA, 255);
        analogWrite(enB, 255);
      } 
      else {
        // Motors stay still if joystick is not in a recognized position
        digitalWrite(in1, LOW);
        digitalWrite(in2, LOW);
        digitalWrite(in3, LOW);
        digitalWrite(in4, LOW);
        analogWrite(enA, 0);
        analogWrite(enB, 0);
      }
    } 
    else if (xValue >= 1018 && xValue <= 1023) { // Right
      digitalWrite(in1, HIGH);
      digitalWrite(in2, LOW);
      digitalWrite(in3, HIGH);
      digitalWrite(in4, LOW);
      analogWrite(enA, 255);
      analogWrite(enB, 255);
    } 
    else if (xValue >= 0 && xValue <= 498) { // Left
      digitalWrite(in1, LOW);
      digitalWrite(in2, HIGH);
      digitalWrite(in3, LOW);
      digitalWrite(in4, HIGH);
      analogWrite(enA, 255);
      analogWrite(enB, 255);
    }
  }
}

Try a wider interval.
Use Serial.print of the values and serial monitor to show the values slipping through.

As @Railroader says... you want 100 bit deadband. Your code looks to be 5.

To add one more thing to @Railroader and @xfpd advice…

The deadband needs to be wide, but in the receiver it should be programmed to be centered around 512, the theoretical half way point.

Then fix your transmitter, it's called trimming and most transmitters and/or transmitter software makes a provision for this.

My old old transmitter has little mechanical trim tabs; these days it's more likely to be a calibration mode where your TX hardware learns what centered sticks actually produce.

This would be more important if you did not have a deadband. Some r/c stuff crops up where a deadband is just truly annoying.

The better your calibration, the smaller any deadbands need to be to mean no input means no motte power.

a7

Starting the session by a calibration of the pots could be a good thing.
For a 3 axle CNC I added pots for manual control. Calibrating the pots, in setup, made them work like a charm.

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

RF24 radio(9, 10); //CE, CSN
int trimX = 0;
int trimY = 0;
struct Payload{
  int xValue ;
  int yValue ;
}payload;
const byte address[] = "12345";

void setup() {
  trimX = analogRead(A0);
  trimY = analogRead(A1);
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_LOW);
}

void loop() {
  payload.xValue = analogRead(A0) - trimX;
  payload.yValue = analogRead(A1) - trimY;

  radio.write(&payload, sizeof(payload));
  delay(100);
}
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(9, 10); // CE, CSN

struct Payload {
  int xValue ;
  int yValue ;
} payload;
const byte address[] = "12345";

const int enA = A0;
const int enB = A1;
const int in1 = 2;
const int in2 = 3;
const int in3 = 4;
const int in4 = 5;

void setup() {
  radio.begin();
  radio.openReadingPipe(1, address);
  radio.setPALevel(RF24_PA_LOW);
  radio.startListening();

  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);

  Serial.begin(9600); // Initialize Serial communication at a baud rate of 9600
}

void loop() {
  const int restingThreshold = 30;
  static uint32_t last_Update = millis();
  static int Speed = 0;
  static int Rotate = 0;

  if (radio.available()) {
    radio.read(&payload, sizeof(payload));
    last_Update = millis();
  }
  if (millis() - last_Update > 500) { // Motors stay still if signal lost
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
    digitalWrite(in3, LOW);
    digitalWrite(in4, LOW);
    analogWrite(enA, 0);
    analogWrite(enB, 0);
  }
  // Implement a deadzone for joystick values
  if (abs(payload.xValue) > restingThreshold)  Speed = constrain(abs(payload.xValue) / 2, 0, 255);
  else Speed = 0;

  if (abs(payload.yValue) > restingThreshold)  Rotate = constrain(abs(payload.yValue) / 2, 0, 255);
  else Rotate = 0;

  bool more = payload.xValue > 0;
  bool fewer = payload.xValue < 0;
  
  digitalWrite(in1, (payload.yValue > 0) ? fewer : more);
  digitalWrite(in2, (payload.yValue > 0) ? more : fewer);
  digitalWrite(in3, (payload.yValue < 0) ? more : fewer);
  digitalWrite(in4, (payload.yValue < 0) ? fewer : more);
  analogWrite(enA, Speed );
  analogWrite(enB, Speed );

  Serial.print("xValue: ");
  Serial.print(payload.xValue);
  Serial.print(", yValue: ");
  Serial.println(payload.yValue);
}

Rc systems incorporate a "dead zone" in the servo amp ..well, at least the older ones.
New digital systems could be smarter but much more involved.

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