Help Transmitting Button Tap over nRF24L01

Hello all!

Currently working on two sketches that when a button is tapped (not pressed and held) that get transmitted wirelessly via nRF24L01 to a receiver with a servo attached that on first button tap moves 90 degrees clockwise (and lights two leds) then on second button tap moves 90 degrees counter/anticlockwise back to it's original position.

As currently written, I'm able to transmit/receive that a button was pressed but the servo doesn't move aside from an initial 90 degree movement at power on and a 90 degree jerk counterclockwise on the first button tap. On subsequent button taps I can see that the angle is increasing by only 1 on each tap in the serial view, but the servo doesn't move. The code is based off a sketch I did previously that worked well enough, but the button was wired into main circuit with the servo.

Code for the Transmitter and Receiver are below, and the Original Wired Sketch along with the circuit diagrams are attached. As of now the Transmitter is running on a Nano and the Receiver is on an Uno, eventually it'll both be nanos. Appreciate any and all help!

Transmitter (w/ Button)

// Pin Connections:
// nRF24L01 Pins:
// CE - 7
// MISO - 12
// MOSI - 11
// SCK - 13
// CS - 8
// Other:
// Button - 3

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

RF24 radio(7, 8); // CE, CS         
const byte address[6] = "00001";  //Byte of array representing the address. This is the address where we will send the data. This should be same on the receiving side.

#define pushButtonPin 3   // Digital IO pin connected to the button.
boolean buttonPushed = 0;   // Sets this to True/False (intialize at False). Can be transmitted. 

void setup() {
  Serial.begin(9600);   //Sets Up Serial View, must be on 9600 baud, Serial View reads out actions
  Serial.println("Fem Mando Wireless Rangefinder Transmitter");   //Titles Serial View
  pinMode(pushButtonPin, INPUT_PULLUP);
  radio.begin();    //Starting the Wireless communication
  radio.setChannel(115);    //115 Band above WiFi signals
  radio.openWritingPipe(address); //Setting the address where we will send the data**???**
  radio.setPALevel(RF24_PA_MIN);  //You can set it as minimum or maximum depending on the distance between the transmitter and receiver.
  radio.setDataRate(RF24_250KBPS);    //Data Transfer Speed  
  radio.stopListening();          //This sets the module as transmitter
  Serial.println("Transmitter Setup Initialized"); 
}

void loop() {  //Transmit pushButtonPin state needed (Low) via buttonpushed. In receiver coder, replace if(digiread(pushbuttonpin)==low with if buttonpushed=low then rename GO buttonpushed variable to something else and go with 1/0
  buttonPushed = digitalRead(pushButtonPin);
  if(buttonPushed == LOW) {
    const char text[] = "Button Pushed LOW";
    radio.write(&text, sizeof(text));                  //Sending the message to receiver
    radio.write(&buttonPushed, sizeof(buttonPushed));  //Sending the message to receiver 
    delay(1000);
    Serial.println("Command Sent");
   }
}

Receiver (w/ Servo)

// Pin Connections:
// nRF24L01 Pins:
// CE - 7
// MISO - 12
// MOSI - 11
// SCK - 13
// CS - 8
// Other:
// Servo - 6
// NeoPixels - 5 

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Servo.h> // Adds Servo Library
#include <Adafruit_NeoPixel.h> // Adds Neopixel library

RF24 radio(7, 8); // CE, CS
const byte address[6] = "00001";

Servo myservo;  // create servo object to control a servo

#define servoPin 6
boolean buttonPushed = 0; //Acting as "pushButtonPin" in OG Wired code

// defines neopixel LEDs
#define PIXEL_PIN   5   // Digital IO pin connected to the NeoPixels.
#define PIXEL_COUNT 2   // number of neopixel (change this accordingly)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800); // Anytime "strip" is used is referring to the LEDs

int angle =0;  //intial Servo position, 90 degrees = vertical
int angleStep =1;  //Incremental speed, Smaller Number, slower speed
const int minAngle = 0;  //Defines Min/Max angles, Min must be < Max
const int maxAngle = 90; //"int" = integer

int stalkMoved =0; //Acting as "buttonPushed" in OG Wired code

void setup() {
  pinMode(6, INPUT_PULLUP);
  Serial.begin(9600);
  Serial.println("Fem Mando Wireless Rangefinder Helmet Receiver");   //Titles Serial View
  radio.begin();  //Starting the Wireless communication
  radio.setChannel(115);  //115 Band above WiFi signals
  radio.openReadingPipe(0, address);  //Setting the address at which we will receive the data
  radio.setPALevel(RF24_PA_MIN);  //You can set this as minimum or maximum depending on the distance between the transmitter and receiver.
  radio.setDataRate(RF24_250KBPS);  //Data Transfer Speed  
  radio.startListening(); //This sets the module as receiver
  myservo.attach(servoPin);  // Attaches the servo object (myservo) to the ~6 Data Pin on arduino
  strip.begin();  //initiates LEDs
  strip.show();
  Serial.println("Receiver Setup Initialized"); 
}

void loop() {
  if (radio.available()) {           //Looking for the data.
    char text[32] = "";                 //Saving the incoming data
    radio.read(&text, sizeof(text));    //Reading the data
    radio.read(&buttonPushed, sizeof(buttonPushed));    //Reading the data
    if(buttonPushed == LOW) {
      stalkMoved = 1;
    if(stalkMoved ==1){ // If the button is pushed, the following code chunk happens
    // Initial loop move:
    angle = angle + angleStep; //Determines movement

      // Reverse directon of the servo on button press
      if (angle <= minAngle || angle >= maxAngle){ // If servo angle is less than or equal to the minimal angle (line20) or "||" greater than or equal to max angle (line21), reverse Servo
        angleStep = -angleStep;
          stalkMoved = 0;
      }
      myservo.write(angle);  // Moves servo to angle; THIS IS WHERE THE MOVE HAPPENS! 
        Serial.print("Moved to: ");  // Writes to the serial
        Serial.print(angle);  // Writes angle value
        Serial.println(" degree");  //Writes "degree" after angle value
      delay(10); // Waits for servo to move between degrees (in milliseconds)
      if (angle == 90 || angle == 0) {
        Serial.println("Movement Complete");  // Mostly a test to see actions post delay
      }
      if (angle == 90) {  // LED Code
        strip.setPixelColor(0, 236, 252 ,3); // Sets first pixel (0) to Neon Yellow "Pixel number, R, G, B")
        strip.show();
        strip.setPixelColor(1, 232, 232, 232); // Sets second pixel (1) to White)
        strip.show(); 
      }
      else {
        strip.setPixelColor(0, 0, 0, 0);
        strip.show();
        strip.setPixelColor(1, 0, 0, 0);
      }   
    }
      //digitalWrite(6, HIGH);
      //Serial.println(text);
    }
  } // Ends Movement loop
} // Returns void loop to start

A few notes:

  • The circuit diagrams show two on/off switches from the power supply. It was the only 4AA holder I could find. IRL it just has one on/off
  • The nRF24L01's both have 5v breakouts on them

OriginalWiredCode.txt (3.48 KB)

Seems like you need to divide the problem into 3 parts:

  1. Detect and differentiate between a button tap and the button being pressed and held.
  2. When the tap is detected, send the information over nRF24L01.
  3. Receive the button tap information at the far end and do something useful with it.

It doesn't look like you've accomplished item #1 yet. My advise would be to do that first without the complication of RF comms. Start with the StateChangeDetection example in the Arduino IDE:
File --> Examples --> 02.Digital --> StateChangeDetection

6V into Vin is too low a voltage for the on board regulator.

gfvalvo:
Seems like you need to divide the problem into 3 parts:

  1. Detect and differentiate between a button tap and the button being pressed and held.
  2. When the tap is detected, send the information over nRF24L01.
  3. Receive the button tap information at the far end and do something useful with it.

It doesn't look like you've accomplished item #1 yet. My advise would be to do that first without the complication of RF comms. Start with the StateChangeDetection example in the Arduino IDE:
File --> Examples --> 02.Digital --> StateChangeDetection

So I have an additional question here: When I did this without RF originally, I used pinMode(pushButtonPin, INPUT_PULLUP) vice just using the straight up "INPUT" in the example to avoid having to add the 10kohm resistor to keep the build as tight as possible, and it worked in the fully wired instance. Is "INPUT_PULLUP" just something that doesn't translate over RF? Code for the wired (non-RF) sketch I used previously:

//2020.07.07

// Use one button to control servo position.
// Initial button press moves rangefindder from 0 to 90 degrees and activates LEDs after XXX.0s wait
// Second button press moves rangefinder from 90 to 0 degrees

#include <Servo.h> // Adds Servo Library
#include <Adafruit_NeoPixel.h> // Adds Neopixel library

Servo myservo;  // create servo object to control a servo

#define pushButtonPin 2    // Digital IO pin connected to the button. **
#define servoPin 6

// defines neopixel LEDs
#define PIXEL_PIN    5   // Digital IO pin connected to the NeoPixels.
#define PIXEL_COUNT 2   // number of neopixel (change this accordingly)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800); // Anytime "strip" is used is referring to the LEDs

int angle =0;  //intial Servo position, 90 degrees = vertical
int angleStep =1;  //Incremental speed, Smaller Number, slower speed
const int minAngle = 0;  //Defines Min/Max angles, Min must be < Max
const int maxAngle = 90; //"int" = integer

int buttonPushed =0; //**

void setup() {  // voidSetup activates initializes following code at startup, "{" and "}" dictates code chunk
  Serial.begin(9600);  // Sets Up Serial View, must be on 9600 baud, Serial view reads out actions
  myservo.attach(servoPin);  // Attaches the servo object (myservo) to the ~6 Data Pin on arduino
  pinMode(pushButtonPin, INPUT_PULLUP); // Activates action on button depress, eliminates need for resistor by pulling to 5v **
  Serial.println("Fem Mando Rangefinder Wired Test");  //Initially lables the action read out... a bit unnecessary?
  strip.begin();  //initiates LEDs
  strip.show();
}

void loop()  { // voidLoop begins repeatable code sequence
  if(digitalRead(pushButtonPin) == LOW){ // "==" if button pushed, continue forward and add one to "buttonPushed" variable ref in line 26 **
    buttonPushed = 1;  // Generally 0 = false, 1 = true
  }  // This chunk repeatedly checks for button push
  if(buttonPushed ==1){ // If the button is pushed, the following code chunk happens
    // Initial loop move:
    angle = angle + angleStep; //??? Determines movement

      // Reverse directon of the servo on button press
      if (angle <= minAngle || angle >= maxAngle){ // If servo angle is less than or equal to the minimal angle (line20) or "||" greater than or equal to max angle (line21), reverse Servo
        angleStep = -angleStep;
          buttonPushed = 0;
      }
      myservo.write(angle);  // Moves servo to angle; THIS IS WHERE THE MOVE HAPPENS! Possible if statement here for light manipulation post delay, add serialPrint to show light on/off status
        Serial.print("Moved to: ");  // Writes to the serial
        Serial.print(angle);  // Writes angle value
        Serial.println(" degree");  //Writes "degree" after angle value
      delay(10); // Waits for servo to move between degrees (in milliseconds)
      if (angle == 90 || angle == 0) {
        Serial.println("Movement Complete");  // Mostly a test to see actions post delay
      }
      if (angle == 90) {  // LED Code
        strip.setPixelColor(0, 236, 252 ,3); // Sets first pixel (0) to Neon Yellow "Pixel number, R, G, B")
        strip.show();
        strip.setPixelColor(1, 232, 232, 232); // Sets second pixel (1) to White)
        strip.show(); 
      }
      else {
        strip.setPixelColor(0, 0, 0, 0);
        strip.show();
        strip.setPixelColor(1, 0, 0, 0);
      }
  }  // Ends Movement loop

}  // Returns voidLoop to start

I do not know why the state change example was written using an external pull down resistor, but the preferred method is how you did it (using internal pullups and INPUT_PULLUP).

Have you checked the servo's actual range of movement - most cannot do the full 0 to 180 range, or anything
like that.

groundFungus:
I do not know why the state change example was written using an external pull down resistor, but the preferred method is how you did it (using internal pullups and INPUT_PULLUP).

I feel a little bit better that SOMETHING was done right haha I'm just curious if it transmits the right way (which in my tests it seems to? The servo isn't really responding to it though aside from an initial move). I'll also look into your voltage concern. I read 6V is a minimum and for all intents and purposes everything seems to be functioning off it...

MarkT:
Have you checked the servo's actual range of movement - most cannot do the full 0 to 180 range, or anything
like that.

I'm only looking for 90 degrees of movement (ie ~12 o'clock to 3 o'clock then back to 12 o'clock) so hopefully that shouldn't be an issue?

INPUT_PULLUP has absolutely nothing to do with nRF24L01 transmission. Completely unrelated. That's why I suggested doing things in stages in My Reply #1.

Get Task #1 to work before doing anything else. Just print something like "Tap Detected" or "Long Press Detected" to the Serial Monitor when the corresponding actions are detected.