A*u & Nordic nRF24's

Aloha –

I have a problem getting erroneous comms over nRF24 radios between an Amicro and BB’d328P-PU(Uno). Sketches are TX’er to RX’er of joystick values, x & y, with Au as RX’er. These sketches found in examples at http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo. The nRF24’s use SPI, so I use the three lines on that header, plus two pins for chip enable & chip select, CE_PIN and CSN_PIN, as referenced in above URL. I have tried taking the CE & CSN lines from 0 & 1, the A*'s TX/RX lines, to no avail. I then took the lines from 4 & 9, also to no avail. Unfortunately, all lines on other side of A*u are taken up by an md08a motor driver board, and am leaving the I2C lines available for something else. Few options.

In both of above pin configs, the erroneous numbers on A* RX’er that I get are “x=-1, y=-1”. I have swapped in the code the pin numbers for CE & CSN, just to check, and get the “No radio available” output in serial monitor. I have swapped out the Au and nRF24 modules, and receive same results. The above referenced sample code works on other equipment I own, the variable in this instance being the Au as RX’er. Is this problem stemming from something particular to these pins on the A*u that I use?

Here is code of A*u RX’er:

//Edited for brevity
//A*micro RX'er

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

#define CE_PIN   4
#define CSN_PIN  9

const uint64_t pipe = 0xE8E8F0F0E1LL; // Define the transmit pipe

RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

int joystick[2];  // 2 element array holding Joystick readings

void setup() 
{
  Serial.begin(9600);
  delay(1000);
  Serial.println("Nrf24L01 Receiver Starting");
  radio.begin();
  radio.openReadingPipe(1,pipe);
  radio.startListening();
}

void loop()  
{
  if ( radio.available() )
  {
    // Read the data payload until we've received everything
    bool done = false;
    while (!done)
    {
      // Fetch the data payload
      done = radio.read( joystick, sizeof(joystick) );
      Serial.print("X = ");
      Serial.print(joystick[0]);
      Serial.print(" Y = ");      
      Serial.println(joystick[1]);
    }
  }
  else
  {    
      Serial.println("No radio available");
  }
}

This rather confounds me, as I have A*/Uno combos in other applications that comm very well over nRF24’s.

I am working toward something like this with the A*u RX’er:

void loop(){
if (radio.available())
{//translate joystick values to motor heading and velocity control}
else robotControl(); //pinging obstacle avoiding robot
}

Thanks folks, for any assistance you could lend to this.
Mark

Hello, Mark.

I am sorry you are having trouble with the A*. The A* and other platforms that use the ATmega32U4, like the Arduino Leonardo, use Serial1 (and pins 0 and 1 on the A*) instead of Serial to communicate over TTL serial with other devices.

-Jon

Aloha Jon –

Thanks for the response. Kinda getting matters in hand. What stumps me are the delay()'s I had to add into the code to get things underway. Commenting out the serial data, and adding the minimum of delay()'s obtained through testing, I get reasonable response over RF. That done, I had to write in 4 new variables, as just mapping x&y to new values for PWM did not seem to work. I operate the joystick in a “+” fashion, as written in the code, although I seem to get differential turning with stick approaching “x” positions (under investigation). Code below.

void loop() {
  if ( radio.available() )
  {
    bool done = false;
    while (!done)
    {
      done = radio.read( joystick, sizeof(joystick) );
      //Serial.print("X = ");
      //Serial.print(joystick[0]);    // x value
      //Serial.print(" Y = ");      
      //Serial.println(joystick[1]);  // y value
      x = joystick[0];
      y = joystick[1];
      //**********BEGIN HERE RF CONTROL OF MOTORS********
      if (y > 532)
      {
        fory = map(y, 512, 1023, 0, 200);
        digitalWrite (AIN1,HIGH);
        digitalWrite (AIN2,LOW);
        digitalWrite (BIN1,HIGH);
        digitalWrite (BIN2,LOW);
        analogWrite(PWMA,fory);
        analogWrite(PWMB,fory);
        delay(40);
      }
      if (y < 492)
      {
        revy = map(y, 0, 512, 200, 0);
        digitalWrite (AIN1,LOW);
        digitalWrite (AIN2,HIGH);
        digitalWrite (BIN1,LOW);
        digitalWrite (BIN2,HIGH);
        analogWrite(PWMA,revy);
        analogWrite(PWMB,revy);
        delay(40);
      }
      if (492 < y < 532)
      {
        if (x > 532) // turn right, zero point turn
        {
          rtx = map(x, 512, 1023, 0, 200);
          digitalWrite (AIN1,LOW);
          digitalWrite (AIN2,HIGH);
          digitalWrite (BIN1,HIGH);
          digitalWrite (BIN2,LOW);
          analogWrite(PWMA,rtx);
          analogWrite(PWMB,rtx);
          delay(40);
        }
        if (x < 492) // turn left, zero point turn
        {
          lex = map(x, 0, 512, 200, 0);
          digitalWrite (AIN1,HIGH);
          digitalWrite (AIN2,LOW);
          digitalWrite (BIN1,LOW);
          digitalWrite (BIN2,HIGH);
          analogWrite(PWMA,lex);
          analogWrite(PWMB,lex);
          delay(40);
        }
          
      if ( 492 < y < 532 && 492 < x < 532)   // joystick centered
      {
        Stop();
      }
    }
  }
  }
  else   //****IF NO RADIO, GO TO OBSTACLE CHECKING
  {    
      robotControl();
      //Serial.println("No radio available");
  }
  delay(50);
}  //********END LOOP*********

I built up a quickie transmitter in this process with an AMini, moving from the BB’d328P-PU. Maybe that was the trick. Anyway, love these A’s, as those blue-colored Micro’s are always giving me headaches when trying to just drop a sketch onto it. Am posting full code below, in case anyone can suggest improvements. I am particularly interested in improving the chooseLR() function such that gives less predictable actions by the bot. Meaning, well, noobing, I lack the words to describe.

A hui hou
Mark

//AStar_md08a_Tamiya_nRF24
//24 Aug 2014

//**************RADIO STUFF******
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <NewPing.h>

#define CE_PIN   4
#define CSN_PIN  9
//*********PING STUFF************
#define TRIGPIN A0
#define ECHOPIN A1
#define MAXDIST 500
#define COLLDIST 20
#define CLOSINGDIST 40
//#define ALERTDIST COLLDIST*3
NewPing sonar(TRIGPIN, ECHOPIN, MAXDIST);  // Ping sensor pins for library
//*********MOTOR DRIVER STUFF*********
#define PWMA 10
#define AIN1 7
#define AIN2 8
#define PWMB 11
#define BIN1 6
#define BIN2 5
#define STBY 12    // HIGH to enable, LOW to disable
#define MAXSPEED 120
int speedSet = 0;

//*******MORE RADIO STUFF************
const uint64_t pipe = 0xE8E8F0F0E1LL;
RF24 radio(CE_PIN, CSN_PIN);
int joystick[2];
int x = 0;
int y = 0;
//int speedX = 0;
//int speedY = 0;
//********MOTOR SPEED VARIABLES OVER RADIO**********
int fory = 0;
int revy = 0;
int rtx = 0;
int lex = 0;
//*********PING VARS & PING FUNCTION*******
int curDist = 0;
int val[3];
//const int numReadings = 3;
int readPing() {
  delay(50);   
  unsigned int uS = sonar.ping();
  int cm = uS/US_ROUNDTRIP_CM;
  return cm;
}
//***********SETUP********
void setup() {
Serial.begin(9600);
  
//****md08a motor driver****
pinMode(PWMA,OUTPUT);
pinMode(AIN1,OUTPUT);
pinMode(AIN2,OUTPUT);
pinMode(STBY,OUTPUT);
pinMode(BIN1,OUTPUT);
pinMode(BIN2,OUTPUT);
pinMode(PWMB,OUTPUT);

val[0] = 0;
val[1] = 0;
val[2] = 0;

radio.begin();
radio.openReadingPipe(1,pipe);
radio.startListening();

delay(2000);
digitalWrite(STBY,HIGH);
Forward();
}
//*********LOOP*************
void loop() {
  if ( radio.available() )
  {
    bool done = false;
    while (!done)
    {
      done = radio.read( joystick, sizeof(joystick) );
      //Serial.print("X = ");
      //Serial.print(joystick[0]);    // x value
      //Serial.print(" Y = ");      
      //Serial.println(joystick[1]);  // y value
      x = joystick[0];
      y = joystick[1];
      //**********BEGIN HERE RF CONTROL OF MOTORS********
      if (y > 532)
      {
        fory = map(y, 512, 1023, 0, 200);
        digitalWrite (AIN1,HIGH);
        digitalWrite (AIN2,LOW);
        digitalWrite (BIN1,HIGH);
        digitalWrite (BIN2,LOW);
        analogWrite(PWMA,fory);
        analogWrite(PWMB,fory);
        delay(40);
      }
      if (y < 492)
      {
        revy = map(y, 0, 512, 200, 0);
        digitalWrite (AIN1,LOW);
        digitalWrite (AIN2,HIGH);
        digitalWrite (BIN1,LOW);
        digitalWrite (BIN2,HIGH);
        analogWrite(PWMA,revy);
        analogWrite(PWMB,revy);
        delay(40);
      }
      if (492 < y < 532)
      {
        if (x > 532) // turn right, zero point turn
        {
          rtx = map(x, 512, 1023, 0, 200);
          digitalWrite (AIN1,LOW);
          digitalWrite (AIN2,HIGH);
          digitalWrite (BIN1,HIGH);
          digitalWrite (BIN2,LOW);
          analogWrite(PWMA,rtx);
          analogWrite(PWMB,rtx);
          delay(40);
        }
        if (x < 492) // turn left, zero point turn
        {
          lex = map(x, 0, 512, 200, 0);
          digitalWrite (AIN1,HIGH);
          digitalWrite (AIN2,LOW);
          digitalWrite (BIN1,LOW);
          digitalWrite (BIN2,HIGH);
          analogWrite(PWMA,lex);
          analogWrite(PWMB,lex);
          delay(40);
        }
          
      if ( 492 < y < 532 && 492 < x < 532)   // joystick centered
      {
        Stop();
      }
    }
  }
  }
  else   //****IF NO RADIO, GO TO OBSTACLE CHECKING
  {    
      robotControl();
      //Serial.println("No radio available");
  }
  delay(50);
}  //********END LOOP*********

//*******OBSTACLE CHECKING******
void robotControl(){
  curDist = readPing();   // read distance
  if (curDist < CLOSINGDIST)
  {
    if (curDist < COLLDIST)
    {
      changePath();
    }
    else
    {
      aheadSlow();
    }
  }
  else Forward();
}
//*********PING CONTROL**********
void changePath(){
  Stop();
  turnLeft();
  delay(500);
  Stop();
  delay(100);
  val[0] = curDist;  //take left reading
  delay(100);
  turnRight();
  delay(500);
  Stop();
  delay(100);
  val[1] = curDist;      //take center reading
  delay(100);
  turnRight();
  delay(500);
  Stop();
  delay(100);
  val[2] = curDist;      //take right reading
  delay(100);
  turnLeft();
  delay(500);
  chooseLR();
} 
void chooseLR(){          //changed this funxn from V3
  if(val[0] > COLLDIST) // left clear
  {
    if(val[2] > COLLDIST) //right clear
    {
      if(val[0] > val[2])// left is more clear
      {
        turnLeft();
        delay(500);
        Forward();
      }
      else
      {
        turnRight();
        delay(500);
        Forward();
      }
    }
    /*
    else
    {
      turnLeft();
      delay(500);
      Forward();
    }
    */
  }
  else
  {
    if(val[2] > COLLDIST) //right clear
    {
      turnRight();
      delay(500);
      Forward();
    }
    
    else
    {
      Reverse();
      delay(600);
      if (random(2) == 0)
      {
        turnLeft();
        delay(500);
      }
      else turnRight();
      delay(500);
    }
  }
}
//********MOTOR CONTROL********** 
void Forward ()
{
  Serial.println("Forward");
  digitalWrite (AIN1,HIGH);
  digitalWrite (AIN2,LOW);
  digitalWrite (BIN1,HIGH);
  digitalWrite (BIN2,LOW);
  //for (speedSet = 0; speedSet < MAXSPEED; speedSet +=1)
  for (speedSet = 0; speedSet < MAXSPEED; ++speedSet)
  {
  analogWrite(PWMA,speedSet);
  analogWrite(PWMB,speedSet);
  //delay(5);
  }
  delay(5);
}
void aheadSlow ()
{
  Serial.println("Ahead slow");
  digitalWrite (AIN1,HIGH);
  digitalWrite (AIN2,LOW);
  digitalWrite (BIN1,HIGH);
  digitalWrite (BIN2,LOW);
  analogWrite(PWMA,MAXSPEED*0.5);
  analogWrite(PWMB,MAXSPEED*0.5);
  delay(10);
}
void Reverse ()
{
  Serial.println("Reverse");
  digitalWrite (AIN1,LOW);
  digitalWrite (AIN2,HIGH);
  digitalWrite (BIN1,LOW);
  digitalWrite (BIN2,HIGH);
  //for (speedSet = 0; speedSet < MAXSPEED; speedSet +=1)
  for (speedSet = 0; speedSet < MAXSPEED; ++speedSet)
  {
  analogWrite(PWMA,speedSet*0.5);
  analogWrite(PWMB,speedSet*0.5);
  }
  delay(5);
}
void turnLeft ()
{
  Serial.println("Turning left");
  digitalWrite (AIN1,HIGH);
  digitalWrite (AIN2,LOW);
  digitalWrite (BIN1,LOW);
  digitalWrite (BIN2,HIGH);
  //for (speedSet = 0; speedSet < MAXSPEED; speedSet +=1)
  for (speedSet = 0; speedSet < MAXSPEED; ++speedSet)
  {
  analogWrite(PWMA,speedSet*0.5);
  analogWrite(PWMB,speedSet*0.5);
  }
  delay(5);
}
void turnRight ()
{
  Serial.println("Turning right");
  digitalWrite (AIN1,LOW);
  digitalWrite (AIN2,HIGH);
  digitalWrite (BIN1,HIGH);
  digitalWrite (BIN2,LOW);
  //for (speedSet = 0; speedSet < MAXSPEED; speedSet +=1)
  for (speedSet = 0; speedSet < MAXSPEED; ++speedSet)
  {
  analogWrite(PWMA,speedSet*0.5);
  analogWrite(PWMB,speedSet*0.5);
  }
  delay(5);
}
void Stop ()
{
  Serial.println("Stopped");
  digitalWrite (AIN1,HIGH);
  digitalWrite (AIN2,HIGH);
  analogWrite(PWMA,255);
  digitalWrite (BIN1,HIGH);
  digitalWrite (BIN2,HIGH);
  analogWrite(PWMB,255);  
}
void turnAround()
{
  Reverse();
  delay(500);
  turnLeft();
  delay(600);
}

A recent update to aforementioned URL in re nRF24 radios, recommended capping the the power to the transceiver. I soldered on a 10uF electrolytic which cleared up the problem on the RX’er side, which got me to where I could figure out the delay() situation. The transceiver draws 12.3mA max @ 3.3V, according to Nordic’s datasheet, best I can tell. The A*u can supply up to 50mA on the 3.3V side, is that correct?
I am in process of tallying up current needs, and cannot find what current is consumed by the TB6612FNG Dual Motor Driver Carrier. That datasheet gives a Standby current consumption (on page 5, 1.5-2 mA?), but I am curious what that motor driver consumes on the logic side when awake/active. There is probably something I don’t understand here.

Mahalo,
Mark

It sounds like your system is working now; thanks for letting us know what you did. Yes, current drawn from the 3.3V output should not exceed about 50 mA. I do not expect the TB6612FNG logic to draw much more than a few mA.

-Jon

Hello Mark

My first post here…Hello All.
I am just setting up a baby orangutan board with a nordic nRF24LU1+ radio. I read through your post but was unclear as to what pins you finally used to connect to the two units. I want if possible to get straight to programming so if you could help that would be great.

The nordic has GND, CE, SCLK, MISO, VCC, CSN, MOSI, IRQ pins so if you could give me some connections and possibly a simple sketch that would be a real bonus.

My project is for intelligent slot cars and these units coupled together would be ideal for that. I currently have then running with an alternative radio setup. You can find more at the link below should you be interested.
http://www.heliumfrog.com/slotcararduinoslotless/blog2/slotlessdigitalracingblog2.html

Thanks

Martin

Aloha Martin, and welcome to the Pololu forum!

Your project is really cool. Really cool, indeed.

By now, you have probably compiled a decent library of reference material, which you may find the redundant in what I list below. As my needs have been quite modest, I am not using the nRF24L01+ to their full potential.

From the Baby-O product page (https://www.pololu.com/product/1220/pictures) you will find the pinouts identified by their port (PB0…&c.) and these correspond to pins on the chip as described in the Atmel ATMega328 product literature (http://www.atmel.com/devices/atmega328.aspx). If you find some port numbers missing, they are dedicated to the motor driver, and maybe other functions on the board. However, Arduino pin numbers are commonly given when you might browse the web in search of further info in re interfacing your nRF24 with the 328. From the Arduino UNO product page (http://arduino.cc/en/Main/ArduinoBoardUno), scroll down about halfway, looking for the link “mapping between Arduino pins and ATmega328 ports” (http://arduino.cc/en/Hacking/PinMapping168).

The nRF24’s communicate over SPI (http://arduino.cc/en/Reference/SPI), the pins of which are broken out to the 2x3 header on the Baby-O. There might be a small dot on the Baby-O indicating Pin 1 of SPI, otherwise it is noted in above referenced Baby-O product page. Programming your Baby-O is done via this header, so you will need to devise a strategy of both programming your board, and having the nRF24 connected here. (I put a bootloader onto the Baby-O that I have, and program in the Arduino IDE similarly to what is described here (http://www.gammon.com.au/breadboard)).

There is a wealth of info for the nRF24, as they are very inexpensive. I suggest your first stop be maniacbug’s blog, https://maniacbug.wordpress.com/2011/11/02/getting-started-rf24/. I use the library he wrote for this radio module. Try looking up his blog there in re networking nRF24’s. Also, take a look at this wiki (http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo)which has links out to a couple other libraries (MIRF and Radiohead) written for the module. All three libraries have example code you will find of value. Also, if you type “nRF24” into the search field at the Arduino forum (http://forum.arduino.cc/) you’ll get choke hits. And, go to Nordic and pull the product lit for the radio (http://www.nordicsemi.com/eng/Products/2.4GHz-RF/nRF24L01P) for those times when you can’t seem to get enough.

As far as passing you some code, trust me, you don’t want that. I am horrible at coding. Without the CompSci background, it is a struggle when I want to try something new. I hope that what I have provided here can be of use to you.

I think that is it. So, keep up us updated on the progress of your project. There is here a “Share Your Project” subforum, when you are ready for prime time.

A hui hou! – Mark

Thanks Mark for the information it is very helpful.
I managed to get two arduinos communicating last night using the details on maniacbugs webpage, so that part I now understand.

If I read you correctly the nordic radio board connects to the SPI 3x2 socket, but you also need this for programming. Does that mean that I will have to disconnect the radio board each time I want to flash in some software, or can I leave it in place (probably soldered underneath using jumper wires. This is important as in my project space is at a premium and the nordic board may need directly soldering to the baby orangutan.

There is also a discussion on another forum where are considering making up a dedicated board for our project. This will be based on the orangutan (but 3.3v) with an onboard radio. If there are any workarounds for this please feel free to share.

Hi Martin –

Yeah, I thought about that also. MOSI, MISO, SCK, those pins are broken out to the ICSP header (along with a +5V, GND, Reset). By desoldering the pins from the radio module, you are free to solder up the radio below the controller with short leads…hmmm…you will need to pull two digital lines for CSN and CE…okay. And of course this means you will not have header pins for programming the controller. There should be no need to disconnect the radio when uploading to the controller.

Pololu has some long male header pins, one side for soldering leads to the radio, and other side will have the ICSP pins in place for programming. Just a thought.

If cabling your programmer to the racer gets a bit of a hassle, could you orient the controller in such way that you could just pogopin through the car body? Maybe a little 2x3 aperture?

By the way, don’t forget a 10uF electrolytic across Vcc and GND on the radio module, small 10V ones work.

OK, a hui hou.