Transmitting PS4 joystick values using NRF24

I have been using NRF24 transceivers for a while now and I have been trying to find out to transmit PS4 joystick values. I have tried to transmit my PS4 joystick values like a Arduino joystick. Unfortunately my reciever is not reading my PS4 joystick values because my serial monitor is staying at value '127' when I move my PS4 joystick on my reciever. My joystick values are reading very well on my transmitter serial monitor. This is my transmitter code:

#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif


//-----( Import needed libraries )-----/
#include <PS4USB.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

USB Usb;
PS4USB PS4(&Usb);
//-----( Declare Constants and Pin Numbers )---/
#define SCK_PIN 13
#define MISO_PIN 12
#define MOSI_PIN 11
#define SS_PIN 10
#define PS4_VID         0x054C // Sony Corporation
#define PS4_PID         0x05C4 // PS4 Controller
#define PS4_PID_SLIM    0x09CC // PS4 Slim Controller

// NOTE: the "LL" at the end of the constant is "LongLong" type
const uint64_t pipe[1] = {0xE8E8F0F0E1LL}; // Define the transmit pipe


//---( Declare objects )---/
RF24 radio(9, 10); // Create a Radio
//---( Declare Variables )---/
int16_t joyPos[2];  // 2 element array holding Joystick readings

void setup()   /**** SETUP: RUNS ONCE ****/
{
  radio.begin();
  radio.setAutoAck(true);
  radio.enableAckPayload();
  radio.enableDynamicPayloads();
  radio.setDataRate(RF24_250KBPS);
  radio.stopListening();
  radio.openWritingPipe(pipe[0]);
  radio.setRetries(15, 15);

Serial.begin(115200); {
#if !defined(__MIPSEL__)
      while (!Serial); 
#endif
      if (Usb.Init() == -1) {
        Serial.print(F("\r\nOSC did not start"));
        while (1); // Halt
      }
      Serial.print(F("\r\nPS4 USB Library Started"));
   }


}//--(end setup )-


void loop() {
      Usb.Task();

      if (PS4.connected()) 
        if (PS4.getAnalogHat(LeftHatX) > 137 || PS4.getAnalogHat(LeftHatX) < 117 || PS4.getAnalogHat(LeftHatY) > 137 || PS4.getAnalogHat(LeftHatY) < 117 || PS4.getAnalogHat(RightHatX) > 137 || PS4.getAnalogHat(RightHatX) < 117 || PS4.getAnalogHat(RightHatY) > 137 || PS4.getAnalogHat(RightHatY) < 117)
{       
   //RUNS CONSTANTLY ****/

  joyPos[0] = PS4.getAnalogHat(LeftHatX);
  int data1 = map( joyPos[0] , 0 , 255 , 0 , 180 ); 
  joyPos[1] = PS4.getAnalogHat(LeftHatY);
  int data2 = map( joyPos[1] , 0 , 255 , 0 ,180 );
  radio.write( &joyPos, sizeof(joyPos));
  Serial.print("Transmitting Data : ");
Serial.println(data1); /* Printing POT value on serial monitor*/
Serial.print("Transmitting Data : ");
Serial.println(data2);

delay (30);

 }
}

this is my receiver code:

//---( Import needed libraries )---//
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Servo.h>
//---( Declare Constants and Pin Numbers )---/
#define SCK_PIN 13
#define MISO_PIN 12
#define MOSI_PIN 11
#define SS_PIN 10


// NOTE: the "LL" at the end of the constant is "LongLong" type
const uint64_t pipe[1] = {0xE8E8F0F0E1LL}; // Define the transmit pipe


//---( Declare objects )---/
RF24 radio(9, 10); // Create a Radio

Servo ESC;
Servo Turn;

//---( Declare Variables )---/
int joyPos[2];  // 2 element array holding Joystick readings
int Throttle = 127;
int Steering = 127;
int fail = 0;

void setup()   /**** SETUP: RUNS ONCE ****/
{
  Serial.begin(115200);
  delay(1000);
  Serial.println("Nrf24L01 Receiver Starting");
  radio.begin();
  radio.setAutoAck(true);
  radio.enableAckPayload();
  radio.enableDynamicPayloads();
  radio.setDataRate(RF24_250KBPS);
  radio.openReadingPipe(1, pipe[0]);
  radio.setRetries(15, 15);
  radio.startListening();
  ESC.attach(3);
  Turn.attach(5);
}//--(end setup )-


void loop()   /**** LOOP: RUNS CONSTANTLY ****/
{
  if ( radio.available() )
  {
    {
      // Fetch the data payload
      radio.read( joyPos, sizeof(joyPos) );

      Throttle = map(joyPos[0], 0, 255, 0, 180);
      Steering = map(joyPos[1], 0, 255, 0, 180);

      Serial.print("Throttle = ");
      Serial.print(joyPos[0]);
      Serial.print(" Steering = ");
      Serial.print(joyPos[1]);
      Serial.print(" Throttle Adjusted = ");
      Serial.print(Throttle);
      Serial.print(" Steering Adjusted = ");
      Serial.println(Steering);

      fail = 0;

    }
  }
  else
  {
    Serial.println("No radio available");
    fail++;
    if (fail > 200){

The teensy 3 has 32-bit integers, the receiving side seems to be a normal AVR with 16-bit integers.

Why are you using integers to transfer values between 0 and 255 anyway?

There is no way your receiving sketch only prints "0".

Printing something, when no packet is available, is a sure way to block on serial.

1 Like

Also, it is usual to implement a pause (delay() etc.) in the loop() on the TX side to give the RX part a chance to process the incoming messages.

1 Like

Oh I did not realize that I was using the normal AVR 16 Bit integers because I got the code online and only modified the transmitter.

The reason why I mapped the PS4 joystick values between 0 to 255 is because on most of the PS4 RC car project's, The joysticks were mapped between 0 to 255 and 0 to 180.

I have made some last minute modifications and the serial monitor should be reading 127. However what I meant to say is that the values are not changing on the serial monitor when I use my PS4 joystick.

Oh and I forgot to mention that the serial monitor reads the joystick values fine on the transmitter. However it is still staying at 127 on the receiver.

Ok I added a delay on the transmitter and the receiver

A delay on the TX part only. The RX part must run constantly to ensure it is active when the TX part sends something.

1 Like

Ok I added a delay only on the transmitter and I have updated my post.

OK. You have updated the code for TX part with a small delay but not dealt with the mixed ‘int’ problem mentioned by @Whandall .
To preserve the original code structure, but make it compatible with 8bit and 32bit systems, change this:
int joyPos[2]; // 2 element array holding Joystick readings
To:
int16_t joyPos[2]; // 2 element array holding Joystick readings

1 Like

Ok I'll test the new code when I get home, Thank you

Ok I have tested the code and have added int16_t joyPos[2] and I have also changed (PS4.getAnalogHat(LeftHatX) > 137 || PS4.getAnalogHat(LeftHatX) < 117); to PS4.getAnalogHat(LeftHatX) because the code before was not reading my analog values. After removing > 137 || PS4.getAnalogHat(LeftHatX) < 117); it works. I have done the same for LeftHatY. However, After preforming these changes my serial monitor still prints

Throttle = 0 Steering = 0 Throttle adjusted = 0 steering adjusted = 0
Throttle = 0 Steering = 0 Throttle adjusted = 0 steering adjusted = 0
Throttle = 0 Steering = 0 Throttle adjusted = 0 steering adjusted = 0
Throttle = 0 Steering = 0 Throttle adjusted = 0 steering adjusted = 0

when I move my joystick. I have added a 30ms delay to my transmitter and I should also mention that I am transmitting with 1 joystick. LeftHatX is the xAxis and LeftHatY is the yAxis.

In principle, you should not modify the code in your OP. You should publish the new code in a new post otherwise it gets confusing.

Is the transmitter part printing the expected values, read from the joystick, to the serial console ?
If that does not work, then there is no hope of getting the correct values to the receiver part. So you should first focus on ensuring the transmitter part can correctly interpret the results from the joystick.

You appear to be assuming that the method getAnalogHat() returns a value between 0 and 255. Are you sure that this also applies to the Teensy you appear to be using ?

1 Like

ok so I have noticed on my serial monitor that when I read joyPos[0] and joyPos[1], I get both values to be between 0 to 255. However, when I Map those same values like this

int data1 = map(joyPos[0], 0, 255, 0 ,180 );
 int data2 = map( joyPos[1] , 0 , 255, 180, 0 );

I get data1 and data2 to be between 0 and 180. I want data1 to read between 0 and 255 because (PS4.getAnalogHat(LefthatX) is mapped between those numbers when I type Serial.printIn(LeftHatX). I also want Data2(LeftHatY) to read between 0 and 180 for the same reason, LefthatY is mapped between those values (0-180) when I do the same thing. I have also noticed that the code that I "borrowed" from had that teensy block of code

#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif

this is the link where I got that code from USB_Host_Shield_2.0/PS4USB.ino at master · felis/USB_Host_Shield_2.0 · GitHub
I have removed that in the new transmitter code here:

//-----( Import needed libraries )-----/
#include <PS4USB.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

USB Usb;
PS4USB PS4(&Usb);
//-----( Declare Constants and Pin Numbers )---/
#define SCK_PIN 13
#define MISO_PIN 12
#define MOSI_PIN 11
#define SS_PIN 10
#define PS4_VID         0x054C // Sony Corporation
#define PS4_PID         0x05C4 // PS4 Controller
#define PS4_PID_SLIM    0x09CC // PS4 Slim Controller

// NOTE: the "LL" at the end of the constant is "LongLong" type
const uint64_t pipe[1] = {0xE8E8F0F0E1LL}; // Define the transmit pipe


//---( Declare objects )---/
RF24 radio(9, 10); // Create a Radio
//---( Declare Variables )---/
int16_t joyPos[2];  // 2 element array holding Joystick readings

void setup()   /**** SETUP: RUNS ONCE ****/
{
  radio.begin();
  radio.setAutoAck(true);
  radio.enableAckPayload();
  radio.enableDynamicPayloads();
  radio.setDataRate(RF24_250KBPS);
  radio.stopListening();
  radio.openWritingPipe(pipe[0]);
  radio.setRetries(15, 15);

Serial.begin(115200); {
#if !defined(__MIPSEL__)
      while (!Serial); 
#endif
      if (Usb.Init() == -1) {
        Serial.print(F("\r\nOSC did not start"));
        while (1); // Halt
      }
      Serial.print(F("\r\nPS4 USB Library Started"));
   }


}//--(end setup )-


void loop() {
      Usb.Task();

      if (PS4.connected()) 
        if (PS4.getAnalogHat(LeftHatX) > 137 || PS4.getAnalogHat(LeftHatX) < 117 || PS4.getAnalogHat(LeftHatY) > 137 || PS4.getAnalogHat(LeftHatY) < 117 || PS4.getAnalogHat(RightHatX) > 137 || PS4.getAnalogHat(RightHatX) < 117 || PS4.getAnalogHat(RightHatY) > 137 || PS4.getAnalogHat(RightHatY) < 117) {
 
{       


   //RUNS CONSTANTLY ****/

  joyPos[0] = (PS4.getAnalogHat(LeftHatX));
  int data1 = map(joyPos[0], 0, 255, 0 , 180 ); 
  joyPos[1] = (PS4.getAnalogHat(LeftHatY));
  int data2 = map( joyPos[1] , 0 , 255, 180, 0 );
  radio.write( &joyPos, sizeof(joyPos));
  Serial.print(F("\r\nxAxis Data : "));
Serial.println(data1); /* Printing POT value on serial monitor*/
Serial.print(F("\tyAxis Data : "));
Serial.println(data2);
delay (100);

  }
 }
}

RX:

//---( Import needed libraries )---//
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Servo.h>
//---( Declare Constants and Pin Numbers )---/
#define SCK_PIN 13
#define MISO_PIN 12
#define MOSI_PIN 11
#define SS_PIN 10


// NOTE: the "LL" at the end of the constant is "LongLong" type
const uint64_t pipe[1] = {0xE8E8F0F0E1LL}; // Define the transmit pipe
 

//---( Declare objects )---/
RF24 radio(9, 10); // Create a Radio

Servo ESC;
Servo Turn;

//---( Declare Variables )---/
int16_t joyPos[2];  // 2 element array holding Joystick readings
int Throttle = 80;
int Steering = 90;
int fail = 0;


void setup()   /**** SETUP: RUNS ONCE ****/
{
  Serial.begin(115200);
  delay(1000);
  Serial.println("Nrf24L01 Receiver Starting");
  radio.begin();
  radio.setAutoAck(true);
  radio.enableAckPayload();
  radio.enableDynamicPayloads();
  radio.setDataRate(RF24_250KBPS);
  radio.openReadingPipe(1, pipe[0]);
  radio.setRetries(15, 15);
  radio.startListening();
  ESC.attach(3);
  Turn.attach(5);
}//--(end setup )-


void loop()   /**** LOOP: RUNS CONSTANTLY ****/
{
  if ( radio.available() )
  {
    {
      // Fetch the data payload
      radio.read( joyPos, sizeof(joyPos) );

      Throttle = map(joyPos[0], 0, 255, 0, 180);
      Steering = map(joyPos[1], 0, 255, 180, 0);

      Serial.print("Throttle = ");
      Serial.print(joyPos[0]);
      Serial.print(" Steering = ");
      Serial.print(joyPos[1]);
      Serial.print(" Throttle Adjusted = ");
      Serial.print(Throttle);
      Serial.print(" Steering Adjusted = ");
      Serial.println(Steering);

      fail = 0;
    }
  }
  else
  {
    Serial.println("No radio available");
    fail++;
    if (fail > 200){
      Throttle = 80;
      Steering = 90;
    }
  }
  
  ESC.write(Throttle);
  Turn.write(Steering);
}

@6v6gt

ok I now fixed it, joyPos[0] reads between 0 and 255 and joyPos[1] reads between 0 and 180. This means that my transmitter is printing the expected values, Now there is hope for connecting it to the receiver.
new transmitter code:

//-----( Import needed libraries )-----/
#include <PS4USB.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

USB Usb;
PS4USB PS4(&Usb);
//-----( Declare Constants and Pin Numbers )---/
#define SCK_PIN 13
#define MISO_PIN 12
#define MOSI_PIN 11
#define SS_PIN 10
#define PS4_VID         0x054C // Sony Corporation
#define PS4_PID         0x05C4 // PS4 Controller
#define PS4_PID_SLIM    0x09CC // PS4 Slim Controller

// NOTE: the "LL" at the end of the constant is "LongLong" type
const uint64_t pipe[1] = {0xE8E8F0F0E1LL}; // Define the transmit pipe


//---( Declare objects )---/
RF24 radio(9, 10); // Create a Radio
//---( Declare Variables )---/
int16_t joyPos[2];  // 2 element array holding Joystick readings

void setup()   /**** SETUP: RUNS ONCE ****/
{
  radio.begin();
  radio.setAutoAck(true);
  radio.enableAckPayload();
  radio.enableDynamicPayloads();
  radio.setDataRate(RF24_250KBPS);
  radio.stopListening();
  radio.openWritingPipe(pipe[0]);
  radio.setRetries(15, 15);

Serial.begin(115200); {
#if !defined(__MIPSEL__)
      while (!Serial); 
#endif
      if (Usb.Init() == -1) {
        Serial.print(F("\r\nOSC did not start"));
        while (1); // Halt
      }
      Serial.print(F("\r\nPS4 USB Library Started"));
   }


}//--(end setup )-


void loop() {
      Usb.Task();

      if (PS4.connected()) 
        if (PS4.getAnalogHat(LeftHatX) > 137 || PS4.getAnalogHat(LeftHatX) < 117 || PS4.getAnalogHat(LeftHatY) > 137 || PS4.getAnalogHat(LeftHatY) < 117 || PS4.getAnalogHat(RightHatX) > 137 || PS4.getAnalogHat(RightHatX) < 117 || PS4.getAnalogHat(RightHatY) > 137 || PS4.getAnalogHat(RightHatY) < 117) {
 
{       


   //RUNS CONSTANTLY ****/

  joyPos[0] = (PS4.getAnalogHat(LeftHatX));
  int data1 = map(joyPos[0], 0, 255, 0, 180 ); 
  joyPos[1] = (map(PS4.getAnalogHat(LeftHatY), 0, 255, 180, 0));
  int data2 = joyPos[1];
  radio.write( &joyPos, sizeof(joyPos));
  Serial.print(F("\r\nxAxis Data : "));
Serial.println(joyPos[0]); /* Printing POT value on serial monitor*/
Serial.print(F("\tyAxis Data : "));
Serial.println(data2);

delay (100);

  }
 }
}
//--(end main loop )-