The nRF24L01 - Wire...
 
Notifications
Clear all

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


DroneBot Workshop
(@dronebot-workshop)
Workshop Guru Admin
Joined: 2 years ago
Posts: 911
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
01:02:14 - 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: 2 months ago
Posts: 6
 

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: 972
 

@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: 2 months ago
Posts: 6
 

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: 972
 

@troles

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

SteveG


ReplyQuote
Scott
(@scott)
New Member
Joined: 2 weeks ago
Posts: 3
 

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)
New Member
Joined: 2 weeks ago
Posts: 3
 

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 2 weeks ago by Scott

ReplyQuote
Scott
(@scott)
New Member
Joined: 2 weeks ago
Posts: 3
 
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: 2 months ago
Posts: 6
 

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