The nRF24L01 - Wire...
 
Notifications
Clear all

The nRF24L01 - Wireless Joystick for Arduino Robot Car with nRF24L01+

Page 1 / 3

DroneBot Workshop
(@dronebot-workshop)
Workshop Guru Admin
Joined: 2 years ago
Posts: 1004
Topic starter  

Use the nRF24L01+ to build an Arduino Robot Car with a wireless joystick!

Get all the code and more info about using the nRF24L01+ at https://dbot.ws/nrf24l01

Let’s learn how to use the nRF24L01+ radio modules! These inexpensive devices can add 2-way wireless communications capability to any Arduino project and once you understand how to work with them they are very easy to use. They perform well both indoors and outdoors.

We will use a couple of nRF24L01+ modules to construct a wireless remote joystick for the Robot Car that we constructed in an earlier video. If you haven’t seen the original robot car video you can take a look at it here

Actually, you can use this setup with any robot car base as the speed sensors we used in the original video are not used in this design.

In order to simplify our work with the nRF24L01+ modules, we’ll make use of the RadioHead Library, a very versatile Arduino library that works with all sorts of radio modules to provide advanced communications capabilities. We’ll examine a basic client-server data exchange system and a more advanced 2-way system that uses the “Reliable Datagram” method of packet communications. This is the system that we will adapt to use with our robot car joystick.

Even if you have no desire to remotely control a robot car you’ll still find the lessons valuable as they show you the basis of exchanging sensor and text data between two Arduinos. You can use this code in other remote sensing and control projects.

As always the code for everything, along with a detailed article, can be found on the DroneBot Workshop website at https://dbot.ws/nrf24l01 <.

It’s a VERY long video today, even for me! So if you want to skip ahead to the part that most interests you here’s the table of contents - just click on the timestamp to move to that part of the video:

00:00 - Introduction
04:22 - Introducing the nRF24L01+
09:16 - Tips for using the nRF24L01
12:06 - Hooking up the nRF24L01 module to the Arduino
14:23 - RadioHead Library Intro
17:44 - The Radiohead Library Basic Client-Server
24:08 - Demo 1
26:18 - Radiohead Reliable Datagram
31:57 - Demo 2
33:03 - Joystick Demo Hookup & Code
40:36 - Joystick Demo
42:36 - Wireless Joystick Hookup & Code
59:51 - Wireless Robot Car Demo
0114 - Car Crash Bloopers!

I even threw in a “bloopers” section for those of you who manage to make it to the end!

"Never trust a computer you can’t throw out a window." — Steve Wozniak


Quote
Troles
(@troles)
Active Member
Joined: 8 months ago
Posts: 11
 

I am relatively new to the micro controller world, but this site has helped me learn amazing things.  I need to build a joystick with 2 buttons to control a toy. I have most parts, but for the nrf2l01’s can I use one of the ‘basic’ ones and one with the large external antennae?  I know this may limit my range to the extent of the basic, but will it still work together. Also I plan to use a nano on transmitter end and uno on receiver side


ReplyQuote
codecage
(@codecage)
Member Admin
Joined: 2 years ago
Posts: 1078
 

@troles

The large antenna is what gives you more range, but not knowing what size "range" you envision makes it a little difficult give definitive answers.  And why not use a nano on both the TX and RX sides?  For a "toy" the nano is going to take up less real estate.

SteveG


ReplyQuote
Troles
(@troles)
Active Member
Joined: 8 months ago
Posts: 11
 

I understand the using of 2 nano's for space, but I happen to have an extra Uno and one extra nano.  Regarding the 2 models of nrf2l01’s and distance, it is really just about 30-40 feet.  I am assuming that by mixing the 2 styles ("external antennae" and 'standard') I am likely limited to the shorter/weaker range of the 'standard' one.  I just wanted to see if for some reason they would not be compatible.  I realize that was unlikely, as it seems to be the same device with just different antennas.  I haven't used them before but happen to have one of each and wanted to check before I started project in case I needed to order matching one and wait a few weeks for the slow boat to deliver.  I think I will just order a mate for each type for future projects, but will build it with one of each for now so I can get started.  Thanks to any and everyone for participation and help...there is a mountain of collective knowledge out there and I am thankful for forums like this and generous people lending their time and tips.  Thanks!  


ReplyQuote
codecage
(@codecage)
Member Admin
Joined: 2 years ago
Posts: 1078
 

@troles

That should work and allows you to go ahead and get started.

SteveG


ReplyQuote
Scott
(@scott)
Active Member
Joined: 7 months ago
Posts: 11
 

Hello all,

I've been trying to automate little projects with arduinos for a while but only recently tried to get a radio communication between two of them.

I'm baffled by the trouble i've been having whilst trying to use the dronebot workshop guide to wireless control:

https://dronebotworkshop.com/nrf24l01-wireless-joystick/

More specifically I have been mutating the receiver code to drive a radio controlled car (after doing the "hello world!" tutorials and such).
It should have been so easy to take the two signals, one for each motor controller, and change it to use one of them to drive a steering servo for my little car instead.

Of course it's never quite as simple as one imagines but eventually I get there. The axis of the joystick controls the motor correctly. Great.

Next, the steering servo. Should be simple enough, I've already got the signal to transmit successfully and have used servos with the arduino before.

I add the servo.h library in the sketch and - nothing. It won't even compile.

I spend a few evenings going through the internet and discover two things:

1. Surprisingly few arduino projects use the NRF24 with a servo. Even the "rc car" projects either use two motors instead of the traditional motor/servo setup, or else they use bluetooth.
2. Something about the servo.h library and the RH_NRF24.h library using the same "timer" somewhere onboard the arduino.

I'm now completeley out of my depth but I'm in too deep, so I press on and find this blog with a description of a "ServoTimer2 library":

#############

"I've been trying to make a humanoid robot recently- which means dealing with Servo motors. Everything worked just as fine just before I tried to make the robot TALK.
When I needed to use the TMRpcm library. But there's some libraries like

#TMRpcm.h
#VirtualWire.h
are libraries that use the Timer1 of Arduino.
It appears that you can't use two devices simultaneously where both use the same timer...
So, if my robot talks- the servos don't work. Because The Servo.h and the TMRpcm both works on Arduino TImer1.
Which is a mess. If you want to make both of them work you have to use another library for servos. Which is ServoTimer2 library?"

########

Blog can be found here: https://create.arduino.cc/projecthub/ashraf_minhaj/how-to-use-servotimer2-library-simple-explain-servo-sweep-512fd9

 

He goes on to describe the library and how to install it.

So I go through it all and finally my sketches work. Kind of.

1. It's not reliable, sometimes it won't compile, sometimes won't upload, sometimes just doesn't work.
2. It only sends servo signals as PWM so as the tutorial says:

"But in ServoTimer2 library we must write the Pulsewidth of the servo and the servo moves to that position using that.
Most commonly 1500 means 90 degree."

- So it now seems that i'm sending a signal to the servo which varies in 0.12 degree increments rather than 1 degree increments, and this (I think) is what causes it to now twitch constantly.

I am now baffled and need to find answers to two questions:

1. Am I really the only one to try and use a arduino nrf24 with a servo? Does it really require an obscure library like this?
2. If I really must control the servo using PWM, how can I get it to send the servo increments of 180 degrees so that it doesn't twitch constantly?

Many thanks to anyone who has taken the time to read this far.. I'd be very grateful for any information available on this.

I'll put my code in two posts below.

Thanks again,

Scott.


ReplyQuote
Scott
(@scott)
Active Member
Joined: 7 months ago
Posts: 11
 

Below is my transmitting code at the joystick arduino:

 

/*
nRF24L01+ Joystick Transmitter
nrf24l01-joy-xmit-car.ino
nRF24L01+ Transmitter with Joystick for Robot Car
Use with Joystick Receiver for Robot Car
DroneBot Workshop 2018
https://dronebotworkshop.com
*/

// Include RadioHead ReliableDatagram & NRF24 Libraries
#include <RHReliableDatagram.h>
#include <RH_NRF24.h>

// Include dependant SPI Library
#include <SPI.h>

// Define Joystick Connections
#define joyVert A0
#define joyHorz A1

// Define Joystick Values - Start at 512 (middle position)
int joyposVert = 512;
int joyposHorz = 512;

// Define addresses for radio channels
#define CLIENT_ADDRESS 1
#define SERVER_ADDRESS 2

// Create an instance of the radio driver
RH_NRF24 RadioDriver;

// Sets the radio driver to NRF24 and the client address to 1
RHReliableDatagram RadioManager(RadioDriver, CLIENT_ADDRESS);

// Declare unsigned 8-bit motorcontrol array
// 2 Bytes for motor speeds plus 1 byte for direction control
uint8_t motorcontrol[3];

// Define the Message Buffer
uint8_t buf[RH_NRF24_MAX_MESSAGE_LEN];

void setup()
{
// Setup Serial Monitor
Serial.begin(9600);

// Initialize RadioManager with defaults - 2.402 GHz (channel 2), 2Mbps, 0dBm
if (!RadioManager.init())
Serial.println("init failed");

// Set initial motor direction as forward
motorcontrol[2] = 0;

}

void loop()
{
// Print to Serial Monitor
Serial.println("Reading motorcontrol values ");

// Read the Joystick X and Y positions
joyposVert = analogRead(joyVert);
joyposHorz = analogRead(joyHorz);

// Determine if this is a forward or backward motion
// Do this by reading the Verticle Value
// Apply results to MotorSpeed and to Direction

if (joyposVert < 460)
{
// This is Backward
// Set Motors backward
motorcontrol[2] = 1;

//Determine Motor Speeds
// As we are going backwards we need to reverse readings
motorcontrol[0] = map(joyposVert, 460, 0, 0, 255);
motorcontrol[1] = map(joyposVert, 460, 0, 0, 255);

}
else if (joyposVert > 564)
{
// This is Forward
// Set Motors forward
motorcontrol[2] = 0;

//Determine Motor Speeds
motorcontrol[0] = map(joyposVert, 564, 1023, 0, 255);
motorcontrol[1] = map(joyposVert, 564, 1023, 0, 255);

}
else
{
// This is Stopped
motorcontrol[0] = 0;
motorcontrol[1] = 0;
motorcontrol[2] = 0;

}

// Now do the steering
// The Horizontal position will "weigh" the motor speed
// Values for each motor

if (joyposHorz < 460)
{
// Move Left
// As we are going left we need to reverse readings
// Map the number to a value of 255 maximum
joyposHorz = map(joyposHorz, 460, 0, 0, 255);

motorcontrol[0] = motorcontrol[0] - joyposHorz;
motorcontrol[1] = motorcontrol[1] + joyposHorz;

// Don't exceed range of 0-255 for motor speeds
if (motorcontrol[0] < 0)motorcontrol[0] = 0;
if (motorcontrol[1] > 255)motorcontrol[1] = 255;

}
else if (joyposHorz > 564)
{
// Move Right
// Map the number to a value of 255 maximum
joyposHorz = map(joyposHorz, 564, 1023, 0, 255);

motorcontrol[0] = motorcontrol[0] + joyposHorz;
motorcontrol[1] = motorcontrol[1] - joyposHorz;

// Don't exceed range of 0-255 for motor speeds
if (motorcontrol[0] > 255)motorcontrol[0] = 255;
if (motorcontrol[1] < 0)motorcontrol[1] = 0;

}

// Adjust to prevent "buzzing" at very low speed
if (motorcontrol[0] < 8)motorcontrol[0] = 0;
if (motorcontrol[1] < 8)motorcontrol[1] = 0;

//Display the Motor Control values in the serial monitor.
Serial.print("Motor A: ");
Serial.print(motorcontrol[0]);
Serial.print(" - Motor B: ");
Serial.print(motorcontrol[1]);
Serial.print(" - Direction: ");
Serial.println(motorcontrol[2]);

//Send a message containing Motor Control data to manager_server
if (RadioManager.sendtoWait(motorcontrol, sizeof(motorcontrol), SERVER_ADDRESS))
{
// Now wait for a reply from the server
uint8_t len = sizeof(buf);
uint8_t from;
if (RadioManager.recvfromAckTimeout(buf, &len, 2000, &from))
{
Serial.print("got reply from : 0x");
Serial.print(from, HEX);
Serial.print(": ");
Serial.println((char*)buf);
}
else
{
Serial.println("No reply, is nrf24_reliable_datagram_server running?");
}
}
else
Serial.println("sendtoWait failed");

delay(100); // Wait a bit before next transmission
}
This post was modified 7 months ago by Scott

ReplyQuote
Scott
(@scott)
Active Member
Joined: 7 months ago
Posts: 11
 
Below is my current code for the receiver in the Rc car:




/*
nRF24L01+ Joystick Receiver for Robot Car
nrf24l01-joy-rcv-car.ino
nRF24L01+ Receiver and L298N driver for Robot Car
Use with Joystick Transmitter for Robot Car
DroneBot Workshop 2018
https://dronebotworkshop.com






*/

// Include RadioHead ReliableDatagram & NRF24 Libraries
#include <RHReliableDatagram.h>
#include <RH_NRF24.h>

#include <ServoTimer2.h>

#define rollPin 3

ServoTimer2 servoRoll; // declare variables for up to eight servos

int steerangle = 1500;

// Include dependant SPI Library
#include <SPI.h>

// Define addresses for radio channels
#define CLIENT_ADDRESS 1
#define SERVER_ADDRESS 2

// Motor A Connections ; //these are corrent for the soldered board on the car for the motor
int enA = 9;
int in1 = 14;
int in2 = 4;

// Create an instance of the radio driver
RH_NRF24 RadioDriver;

// Sets the radio driver to NRF24 and the server address to 2
RHReliableDatagram RadioManager(RadioDriver, SERVER_ADDRESS);

// Define a message to return if values received
uint8_t ReturnMessage[] = "JoyStick Data Received";

// Define the Message Buffer
uint8_t buf[RH_NRF24_MAX_MESSAGE_LEN];

boolean rotationDir; // Define a variable to save the motor's rotation direction, true and false are represented by positive rotation and reverse rotation.
int rotationSpeed; // Define a variable to save the motor rotation speed




void setup()
{

servoRoll.attach(rollPin); // attach a pin to the servos and they will start pulsing

// Setup Serial Monitor
Serial.begin(9600);

// Set all the motor control pins to outputs
pinMode(enA, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);

// Initialize RadioManager with defaults - 2.402 GHz (channel 2), 2Mbps, 0dBm
if (!RadioManager.init())
Serial.println("init failed");
}

void loop()
{
if (RadioManager.available())
{
// Wait for a message addressed to us from the client
uint8_t len = sizeof(buf);
uint8_t from;
if (RadioManager.recvfromAck(buf, &len, &from))

{




// Serial Print the values of joystick
// Serial.println("got request from : 0x");
// Serial.println(from, HEX);
// Serial.println(": MotorA = ");
// Serial.println(buf[0]);


// Set Motor Direction
if (buf[0] <125)
{
// Motors are backwards
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);

}else{
// Motors are forwards
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);

}
//try to condition the incoming signal to be motor speed
rotationSpeed = abs((buf[0]-125)*2);

//create a null zone
if (buf[0] <115 && buf[0] >135)
{ rotationSpeed = 0;
}

// Drive Motors
analogWrite(enA, constrain(rotationSpeed, 0, 255));

// Serial.println(rotationSpeed);

steerangle = (((buf[1])*5.88)+750); //set steer angle for servo
Serial.println(steerangle); //declare it

//send the signal to the servo
servoRoll.writewriteMicroseconds(1500);
delay(25);

// Send a reply back to the originator client, check for error
if (!RadioManager.sendtoWait(ReturnMessage, sizeof(ReturnMessage), from))
Serial.println("sendtoWait failed");
}
}
}

ReplyQuote
Troles
(@troles)
Active Member
Joined: 8 months ago
Posts: 11
 

topic-substituting the tb6612fng L298n motor controller

my project this weekend is to build this car and joystick. BUT, per a different DroneBot video, I got a tb6612 for my motor controller as Bill explains it is generally better.  My question, if I do the project car and joystick just like in the video (and code also I hope) except for substituting in the tb6612 for the l298n, will there be any problems (I am particularly anticipating code problems with joystick properly controlling car)?  Second question if anyone feels generous, I am hoping to adjust motor speed slower (not via joystick, but just one time in code ) so my 4 year old can drive it slowly.  


ReplyQuote
ronnie1
(@ronnie1)
New Member
Joined: 6 months ago
Posts: 4
 

Hi I have been following the articles here about nRF24L01,everythings works till I try connecting to a two car,using same code,arduino uno for rx and arduino nano for tx,the problem is a delay of aprox.1.5 secs when i push joy stick in any direction and the car moves? Also when I release stick car doesn't stop for aprox.1.5 to 2secs???? anyone run into this?

Thanks,ronnie1

 


ReplyQuote
Troles
(@troles)
Active Member
Joined: 8 months ago
Posts: 11
 

@ronnie, I have the same problem.  I built it about a month ago, and substituted tb6612 for the l298n motor controller, and that seemed to work out fine, but I also had a delay in the joystick.   Everything seems to be correct in wiring and code, but just a delay (and sometimes a random movement).  Also, when I try to figure it out by watching the serial monitor to see what is going on (i only have 1 computer, so I cannot watch both receiver/car and joystick/transmitter at the same time, but rather have to take turns watching the readings of each) I seem to get some off numbers sent...  for example, joystick forward will have proper reading at the car almost all the time, but then a random reading will sneak in every so often.  I have wondered if this is just because it is a cheap joystick and it is giving a bad number to the transmitter to send....not sure.  Anyway, I did have delay also.  It was was very frustrating for me.  I have since reprogrammed/coded it (same hardware setup) off of another version someone built on youtube, that doesn't use the radiohead library, but instead a different nrf2401 library (it's not "reliable" datagram) and I also have problems with that--not delay, just not responding properly to the controller.  I got frustrated, so i have put it on the shelf for a week to clear my head and restart.  I really want to get it to work eventually , and then adjust code to slow the car down (instead of 0-255 on the pwm speed, perhaps half that,) so it would be slow enough for my 4yr old to play with inside.  Let us know if you find out more with the delay, etc.  


ReplyQuote
MadMisha
(@madmisha)
Reputable Member
Joined: 2 years ago
Posts: 319
 
Posted by: @troles

  Also, when I try to figure it out by watching the serial monitor to see what is going on (i only have 1 computer, so I cannot watch both receiver/car and joystick/transmitter at the same time, but rather have to take turns watching the readings of each) I seem to get some off numbers sent...  for example, joystick forward will have proper reading at the car almost all the time, but then a random reading will sneak in every so often.

Unfortunately, I do not have a solution but maybe I can offer something that can make your life a little easier in troubleshooting. If you install PuTTY, you can have multiple instances open at the same time so you can be looking at multiple serial monitors that are all timestamped on the same screen.


ReplyQuote
ronnie1
(@ronnie1)
New Member
Joined: 6 months ago
Posts: 4
 

Well my problem with a delay seems to have fixed itself which  every tech hates, but after changing from uno to nano rewiring several times it works.On a different note

had 3 out of 4 bad adapters for nrf24l01,also make sure you have a good (not confusing) pin out of the nrf24l01,does smoke with 5v instead of 3v on nrf24l01.


ReplyQuote
Scott
(@scott)
Active Member
Joined: 7 months ago
Posts: 11
 
Posted by: @scott

 

1. Am I really the only one to try and use a arduino nrf24 with a servo? Does it really require an obscure library like this?

Still baffled, does anyone have an example of a project using nrf24 to communicate to an arduino with a servo on it?

Thanks,

Scott.


ReplyQuote
Rich1860
(@rich1860)
Active Member
Joined: 8 months ago
Posts: 14
 

I have had delay problems too with my robot project. I assumed it was because of the reliable program used with the Radiohead library. I tried getting into the library and put in a control to set the number of retries down to one (from the default of 3 retries), but that didn't seem to help. I did need to come to some resolution, through, as we are building these robots with high school students in FIRST Robotics. I was able to get a fast response with the RF24 library ( https://github.com/tmrh20/RF24/), which is the direct or not reliable as the RadioHead library. I found the code from SaptarskiSider on YouTube. In addition, I had to expand the program from xAxis and yAxis to an additional zAxis so I could control (by pushbutton) a sound program to make a whoop-whoop siren go off on the robot controlled by the driver. This seems to solve the problem, so I am keeping this library for the students robots.


ReplyQuote
Page 1 / 3