Arduino Feather 32u4 LoRa runs/transmits slower while on battery

Not exactly sure where to put this, as I don't know exactly where the problem lies.

I have two Arduino's, one acting as a receiver, and one as a transmitter. The transmitter has two buttons that sends a signal to the receiver that rotates a stepper motor left or right.

This works. But my issue is this:
The transmitter will act as a wireless remote control, and needs to run on a battery. When it get's it's power from my computer using a cable, everything runs smootly, but when I switch over to a battery, everything runs slow (fewer signals are sent per second) and there is a longer delay.

What could be the cause of this? And is there a solution?

Details about the project

The battery is fully charged, and a PKCELL LP785060 3.7V 2500mAh.

Code for transmitter:

#include <SPI.h>
#include <RH_RF95.h>

// Radio: feather32u4 
#define RFM95_CS 8
#define RFM95_RST 4
#define RFM95_INT 7

// Radio: Change to 434.0 or other frequency, must match RX's freq!
#define RF95_FREQ 434.0

// Radio: Singleton instance of the radio driver
RH_RF95 rf95(RFM95_CS, RFM95_INT);

// Buttons
#define UP_BUTTON 2
#define DOWN_BUTTON 3

// Battery
#define VBATPIN 9

// Variables
uint8_t down_btn_prev;
uint8_t up_btn_prev;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    delay(1);
  }
  delay(100);
  
  Serial.println("Transmitter!");
  
  setupRadio();
  setupButtons();
}

/**
  Possible logic:
  * TRANSCIEVER: Move upon received signal with a specified timeout
  * If new command is received before timer, cancel timer and set new timer.
  * (The transmitter should then be able to send multiple signals in a row by holding it in, but with a max frequency)
*/

void loop() {
  if (digitalRead(UP_BUTTON) == LOW /* && up_btn_prev == HIGH */) {
   sendPacket(0); 
  } 
  
  if (digitalRead(DOWN_BUTTON) == LOW /*&& down_btn_prev == HIGH*/) {
   sendPacket(1); 
  }
 
  //down_btn_prev = digitalRead(DOWN_BUTTON);
  //up_btn_prev = digitalRead(UP_BUTTON);
}

void setupRadio() {
  pinMode(RFM95_RST, OUTPUT);
  digitalWrite(RFM95_RST, HIGH);
  
  // manual reset
  digitalWrite(RFM95_RST, LOW);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);
  
  while (!rf95.init()) {
    Serial.println("LoRa radio init failed"); 
    Serial.println("Uncomment '#define SERIAL_DEBUG' in RH_RF95.cpp for detailed debug info");
    while (1);
  }
  
  Serial.println("LoRa radio init OK!");
  
  // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
  if (!rf95.setFrequency(RF95_FREQ)) {
    Serial.println("setFrequency failed");
    while (1);
  }
  Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);
  
  // The default transmitter power is 13dBm, using PA_BOOST.
  // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then 
  // you can set transmitter powers from 5 to 23 dBm:
  rf95.setTxPower(23, false);
}

void setupButtons() {
  pinMode(DOWN_BUTTON, INPUT);
  pinMode(UP_BUTTON, INPUT);
  down_btn_prev = digitalRead(DOWN_BUTTON);
  up_btn_prev = digitalRead(UP_BUTTON);
}

// 0 = UP, 1 = DOWN
void sendPacket(int direction) {
  String batt = String(checkBattery(), 2);// using a float and the decimal places
  
  Serial.print("Sending: ");
  Serial.println(direction == 0 ? "UP" : "DOWN");

  if (direction == 0) {
    String upmessage = "UP ";
    upmessage.concat(batt);
    delay(10);
    upmessage[7] = 0;
    rf95.send((uint8_t *)upmessage.c_str(), 7);
    // Wait for packet to complete
    delay(10);
    rf95.waitPacketSent();
  } else {
    String downmessage = "DOWN ";
    downmessage.concat(batt);
    downmessage[9] = 0;
    delay(10);
    rf95.send((uint8_t *)downmessage.c_str(), 9);
    // Wait for packet to complete
    delay(10);
    rf95.waitPacketSent();
  }
}

/*
 * This routine checks the voltage on the battery (if it exists) and returns that value.  Should be in the 3.2-4.2 range depending upon the battery used
 This returns the current voltage of the battery on a Feather 32u4.
 */
float checkBattery() {
  float measuredvbat = analogRead(VBATPIN);
  measuredvbat *= 2;    // we divided by 2, so multiply back
  measuredvbat *= 3.3;  // Multiply by 3.3V, our reference voltage
  measuredvbat /= 1024; // convert to voltage
  return measuredvbat;
}

Code for receiver:

#include <SPI.h>
#include <RH_RF95.h>

// Radio: feather32u4 
#define RFM95_CS 8
#define RFM95_RST 4
#define RFM95_INT 7

// Radio: Change to 434.0 or other frequency, must match RX's freq!
#define RF95_FREQ 434.0

// Radio: Singleton instance of the radio driver
RH_RF95 rf95(RFM95_CS, RFM95_INT);

// Stepper
int dirPin = 10; // Step direction orange
int stepPin = 11; // Step pin

String lastDirection = "DOWN";
bool shouldMove = false;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    delay(1);
  }
  delay(100);
  
  Serial.println("Transmitter X!");
  
  setupRadio();
  
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  digitalWrite(stepPin, LOW);
  digitalWrite(dirPin, LOW);
}

int numberOfLoops = 0;

void loop() {
 receiveRadioMessage();
 
  if (shouldMove) {
    if (lastDirection == "UP") {
      digitalWrite(dirPin, HIGH);
    } else {
      digitalWrite(dirPin, LOW);
    }
    
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(900);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(900);
  }
 
  if (numberOfLoops > 0) {
    numberOfLoops--;
  }
  
  if (numberOfLoops == 0) {
     shouldMove = false;
   }
}


void setupRadio() {
  pinMode(RFM95_RST, OUTPUT);
  digitalWrite(RFM95_RST, HIGH);
  
  Serial.println("Feather LoRa RX Test!");
  
  // manual reset
  digitalWrite(RFM95_RST, LOW);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);
  
  while (!rf95.init()) {
    Serial.println("LoRa radio init failed");
    Serial.println("Uncomment '#define SERIAL_DEBUG' in RH_RF95.cpp for detailed debug info");
    while (1);
  }
  Serial.println("LoRa radio init OK!");
  
  // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
  if (!rf95.setFrequency(RF95_FREQ)) {
    Serial.println("setFrequency failed");
    while (1);
  }
  Serial.print("Set Freq to: "); 
  Serial.println(RF95_FREQ);

  
  // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
  
  // The default transmitter power is 13dBm, using PA_BOOST.
  // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then
  // you can set transmitter powers from 5 to 23 dBm:
  rf95.setTxPower(23, false);
}



void receiveRadioMessage() {
  if (rf95.available()) {
    // Should be a message for us now
    uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);
    memset(buf, 0, len);
  
    if (rf95.recv(buf, &len)) {
      String received = buf;
      Serial.print("Got: ");
      Serial.println(received);
      
      if(received.indexOf("UP") >= 0) {
        shouldMove = true;
        lastDirection = "UP";
        numberOfLoops = 300;
      }
      if(received.indexOf("DOWN") >= 0) {
        shouldMove = true;
        lastDirection = "DOWN";
        numberOfLoops = 300;
      }
    }
    else {
      Serial.println("Receive failed");
    }
  }
}

/**
  Possible logic:
  * Move upon received signal with a specified timeout
  * If new command is received before timer, cancel timer and set new timer.
  * (The transmitter should then be able to send multiple signals in a row by holding it in, but with a max frequency)
*/

Very unlikely. What evidence do you have for this?

If fewer packets per second are received, then the likely explanation is reception failure leading to retries or packets dropped. There are several possible causes for this: poor antennas, interference, etc.

Incidentally, do not use Strings on an AVR based Arduino like the 32U4. They are never necessary, and cause program malfunctions due to poor garbage collection and memory corruption.

I think you are wrong about that. It's the exact same setup, I don't move or touch anything just switch out one cable (battery vs power), and immediately everything speeds up. You can see the logs on the monitor as well.

Also, I can clearly feel/see the there is a longer delay when I hit the button and something happens on the receiver, when using the battery.

Take a look at the videos!

My theories are there are some power saving feature when running on battery so it slows down, or there is a lot of interference from the battery.

Another data point: I connected both power from computer, and the battery (then it runs on power from the computer, but charges the battery), it runs fast, as it should. That too me eliminates the interference theory.

Provide evidence by measuring and printing the number of packets sent per second, on the serial monitor of the transmitting program.

How do I do that while it's using battery?

Good question! While it is possible to do that, other alternatives can be imagined, like blinking an LED each time through the loop and counting the flashes. Right now you have no evidence for your assertions, so forum members will be skeptical.

Have you thought about happens with the print statements in loop() and hence, sendPacket(), when not connected to the serial monitor?

What happens when you call checkBattery(), when not using the battery?

Finally, statements like this usually hang forever, when the serial monitor is not connected:

  while (!Serial) {
    delay(1);
  }

Most people put in an exit clause, or just replace that with something like delay(2000);

Lots of possible pitfalls in the posted code.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.