What kind of cap? Most of them is soldered on the other side tho. But worth a try
Well you could use motor KV, gearing etc. to calculate the speed, however, the speed would be a theoretical speed and not the actual speed. This would only work if no load is applied I believe. Actually, the eRPM counter is more than enough and does the job very precise (at least the VESC 6)
@Deakbannok I have lately been thinking about the issue regarding acceleration turning of while giving max or minimum throttle. At the moment the receiver uses standard PWM signal to generate the throttle signale, however shouldn’t the signal be a PPM signal? I remember something about a “Servo” library which are able to generate a true PPM signal. I will give this a try, and return my findings
As far as I’m aware, receiver signal is actually PWM. I don’t know why people call it PPM. The position is not modulated, only the width. The correct way to generate a receiver signal is something like this (I made my own Arduino/NRF controller/receiver setup some time ago and this is part of my code):
#include <Servo.h>
Servo esc;
void setup() {
esc.attach(9);
}
void loop() {
receiveFromController();
int val = map(throttle, 0, 1023, 900, 2100);
esc.writeMicroseconds(val);
}
This post is quite useful (and I relied on it heavily when designing some code for @MysticalDork to control some LED headlights from a receiver signal): https://ryanboland.com/blog/reading-rc-receiver-values/
Is 180 degree but you have to compromising the negative output numbers min/max of Hall sensor. I am not super confident if that is right. But no worry I have fixed and added adjustable options to your code awhile ago. You will see it soon Right now I am looking on this glitchy RF24 code. Try to understand the limitation and how this thing works.
I am new to this program stuffs so it will take awhile for me to catch up. My work is piling up in the office so I hardly get time to continue working on your code except the weekend. I took a week off from work to Spain last week and tested there. Had a good running so far… but here are a few safety concerns i have found and added to the code. I will try to push out as soon as i have tested myself that everything is working correct before let the public try it out
Hi, Ervinelin! What exactly kind of magnet do you use? Like this one? aliexpress.com/item/50pcs-8mmx5mm-Strong-Round-Cylinder-Magnets-8x5-mm-Rare-Earth-Neodymium-N52-Permanent-Magnet-Powerful-Magnet/32789112260.html I’m asking because link in your BOM is on 5x5mm magnet.
I ordered this, U-JOVAN 20pcs N35 5 x 8 mm Mini Strong Round Cylinder Neodymium Magnets Disc Rare Earth Manget 5*8mm (from AliExpress Android) but it’s not here yet.
In the meanwhile I stacked my 5x5 with 3pcs of 1mm magnets to get 5x8mm.
is it possible to build yours without the custom pcb? good job btw
I think so, might be a little tricky keeping everything together but I suppose it should be doable.
I forked SolidGeek’s Github page, all available files for my trigger style remote are now available including the PCB files (I believe you can order it yourself from EasyEDA with the links).
as soon as i confirm my remote is working im gonna try your version too. pcbs cost $12 + shipping thanks for the contribution i feel like trigger style is better for me because original case is somewhat ucomfortable for small hands. holding down the trigger and braking at the same time is somewhat difficult
come back with updates when you would have some, i’m pretty interested. As well interested in buying steroids online. Any update would be much appreciated.
Hi guys,
another feature requeset… I like do switch on / off the lights of my board with the help of this remote. My idea was to add an extra point in the setting menu, where you can select light on or off. I tried to implement this in the code from @solidgeek but I’m an absolutely newbie in arduino programming. So I didn’t master it.
At the transmitter I added / changed this:
1.
struct settings {
byte triggerMode;
…
int lightValue;
};
2. const byte numOfSettings = 12;
String settingPages[numOfSettings][2] = { {“Trigger”, “”}, … {“Light”, “”} };
3. int settingRules[numOfSettings][3] { {0, 0, 3}, // 0 Killswitch, 1 cruise & 2 data toggle … {1, 0, 1}, // On or Off };
3. int getSettingValue(int index) { int value; switch (index) { case 0: value = remoteSettings.triggerMode; break; … case 11: value = remoteSettings.lightValue; break;
4. void setSettingValue(int index, int value) { switch (index) { case 0: remoteSettings.triggerMode = value; break; … case 11: remoteSettings.lightValue = value; break; }
5.
void transmitToVesc() {
// Transmit once every 50 millisecond
if (millis() - lastTransmission >= 50) {
lastTransmission = millis();
radio.write(&lightValue, sizeof(lightValue));
boolean sendSuccess = false;
// Transmit the speed value (0-255).
sendSuccess = radio.write(&throttle, sizeof(throttle));
radio.write(&lightValue, sizeof(lightValue));…
And at the receiver I added / changed this:
1. int motorSpeed = 127; int timeoutMax = 500; int speedPin = 5; int lightPin = 7; int lightValue;
2. pinMode(speedPin, OUTPUT); analogWrite(speedPin, motorSpeed); pinMode(lightPin, OUTPUT);
3. void loop() { … getVescData(); // If transmission is available if (radio.available()) { … radio.read(&lightValue, sizeof(lightValue)); if (lightValue==1){ digitalWrite(lightPin, HIGH); } else { digitalWrite(lightPin, LOW); }…
Compiling and upload to the arduinos works. However this code does not work in a proper way, unfortunately. I guess I made something wrong because the transmission of lightValue does not work. Could some please help me? I guess it is an easy task but I just to inexperienced.
THX in advance
Try using the </>
button so your code is actually readable
Okay, here is the full code in the right format:
TRANSMITTER:
#include <U8g2lib.h>
#include <Wire.h>
#include <SPI.h>
#include <EEPROM.h>
#include "RF24.h"
#include "VescUart.h"
// #define DEBUG
#ifdef DEBUG
#define DEBUG_PRINT(x) Serial.println (x)
#include "printf.h"
#else
#define DEBUG_PRINT(x)
#endif
int lightValue;
// Defining the type of display used (128x32)
U8G2_SSD1306_128X32_UNIVISION_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
static unsigned char logo_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x80, 0x3c, 0x01, 0xe0, 0x00, 0x07, 0x70, 0x18, 0x0e, 0x30, 0x18, 0x0c, 0x98, 0x99, 0x19, 0x80, 0xff, 0x01, 0x04, 0xc3, 0x20, 0x0c, 0x99, 0x30, 0xec, 0xa5, 0x37, 0xec, 0xa5, 0x37, 0x0c, 0x99, 0x30, 0x04, 0xc3, 0x20, 0x80, 0xff, 0x01, 0x98, 0x99, 0x19, 0x30, 0x18, 0x0c, 0x70, 0x18, 0x0e, 0xe0, 0x00, 0x07, 0x80, 0x3c, 0x01, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static unsigned char signal_transmitting_bits[] = {
0x18, 0x00, 0x0c, 0x00, 0xc6, 0x00, 0x66, 0x00, 0x23, 0x06, 0x33, 0x0f,
0x33, 0x0f, 0x23, 0x06, 0x66, 0x00, 0xc6, 0x00, 0x0c, 0x00, 0x18, 0x00
};
static unsigned char signal_connected_bits[] = {
0x18, 0x00, 0x0c, 0x00, 0xc6, 0x00, 0x66, 0x00, 0x23, 0x06, 0x33, 0x09,
0x33, 0x09, 0x23, 0x06, 0x66, 0x00, 0xc6, 0x00, 0x0c, 0x00, 0x18, 0x00
};
static unsigned char signal_noconnection_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x09,
0x00, 0x09, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// Defining struct to hold UART data.
struct vescValues {
float ampHours;
float inpVoltage;
long rpm;
long tachometerAbs;
};
// Defining struct to hold stats
struct stats {
float maxSpeed;
long maxRpm;
float minVoltage;
float maxVoltage;
};
// Defining struct to hold setting values while remote is turned on.
struct settings {
byte triggerMode;
byte batteryType;
byte batteryCells;
byte motorPoles;
byte motorPulley;
byte wheelPulley;
byte wheelDiameter;
bool useUart;
int minHallValue;
int centerHallValue;
int maxHallValue;
int lightValue;
};
// Defining variables for speed and distance calculation
float gearRatio;
float ratioRpmSpeed;
float ratioPulseDistance;
byte currentSetting = 0;
const byte numOfSettings = 12;
String settingPages[numOfSettings][2] = {
{"Trigger", ""},
{"Battery type", ""},
{"Battery cells", "S"},
{"Motor poles", ""},
{"Motor pulley", "T"},
{"Wheel pulley", "T"},
{"Wheel diameter", "mm"},
{"UART data", ""},
{"Throttle min", ""},
{"Throttle center", ""},
{"Throttle max", ""},
{"Light", ""}
};
// Setting rules format: default, min, max.
int settingRules[numOfSettings][3] {
{0, 0, 3}, // 0 Killswitch, 1 cruise & 2 data toggle
{0, 0, 1}, // 0 Li-ion & 1 LiPo
{10, 0, 12},
{14, 0, 250},
{15, 0, 250},
{40, 0, 250},
{83, 0, 250},
{1, 0, 1}, // Yes or no
{0, 0, 1023},
{512, 0, 1023},
{1023, 0, 1023},
{1, 0, 1} // on or off
};
struct vescValues data;
struct settings remoteSettings;
// Pin defination
const byte triggerPin = 4;
const int chargeMeasurePin = A1;
const int batteryMeasurePin = A2;
const int hallSensorPin = A3;
// Battery monitering
const float minVoltage = 3.2;
const float maxVoltage = 4.1;
const float refVoltage = 5.0; // Set to 4.5V if you are testing connected to USB, otherwise 5V (or the supply voltage)
// Defining variables for Hall Effect throttle.
short hallMeasurement, throttle;
byte hallCenterMargin = 4;
// Defining variables for NRF24 communication
bool connected = false;
short failCount;
const uint64_t pipe = 0xE8E8F0F0E1LL; // If you change the pipe, you will need to update it on the receiver to.
unsigned long lastTransmission;
// Defining variables for OLED display
char displayBuffer[20];
String displayString;
short displayData = 0;
unsigned long lastSignalBlink;
unsigned long lastDataRotation;
// Instantiating RF24 object for NRF24 communication
RF24 radio(9, 10);
// Defining variables for Settings menu
bool changeSettings = false;
bool changeSelectedSetting = false;
bool settingsLoopFlag = false;
bool settingsChangeFlag = false;
bool settingsChangeValueFlag = false;
void setup() {
// setDefaultEEPROMSettings(); // Call this function if you want to reset settings
#ifdef DEBUG
Serial.begin(9600);
#endif
loadEEPROMSettings();
pinMode(triggerPin, INPUT_PULLUP);
pinMode(hallSensorPin, INPUT);
pinMode(batteryMeasurePin, INPUT);
u8g2.begin();
drawStartScreen();
if (triggerActive()) {
changeSettings = true;
drawTitleScreen("Remote Settings");
}
// Start radio communication
radio.begin();
radio.setPALevel(RF24_PA_MAX);
radio.enableAckPayload();
radio.enableDynamicPayloads();
radio.openWritingPipe(pipe);
#ifdef DEBUG
printf_begin();
radio.printDetails();
#endif
}
void loop() {
calculateThrottlePosition();
if (changeSettings == true) {
// Use throttle and trigger to change settings
controlSettingsMenu();
}
else
{
// Use throttle and trigger to drive motors
if (triggerActive())
{
throttle = throttle;
}
else
{
// 127 is the middle position - no throttle and no brake/reverse
throttle = 127;
}
// Transmit to receiver
transmitToVesc();
}
// Call function to update display and LED
updateMainDisplay();
}
void controlSettingsMenu() {
if (triggerActive()) {
if (settingsChangeFlag == false) {
// Save settings to EEPROM
if (changeSelectedSetting == true) {
updateEEPROMSettings();
}
changeSelectedSetting = !changeSelectedSetting;
settingsChangeFlag = true;
}
} else {
settingsChangeFlag = false;
}
if (hallMeasurement >= (remoteSettings.maxHallValue - 150) && settingsLoopFlag == false) {
// Up
if (changeSelectedSetting == true) {
int val = getSettingValue(currentSetting) + 1;
if (inRange(val, settingRules[currentSetting][1], settingRules[currentSetting][2])) {
setSettingValue(currentSetting, val);
settingsLoopFlag = true;
}
} else {
if (currentSetting != 0) {
currentSetting--;
settingsLoopFlag = true;
}
}
}
else if (hallMeasurement <= (remoteSettings.minHallValue + 150) && settingsLoopFlag == false) {
// Down
if (changeSelectedSetting == true) {
int val = getSettingValue(currentSetting) - 1;
if (inRange(val, settingRules[currentSetting][1], settingRules[currentSetting][2])) {
setSettingValue(currentSetting, val);
settingsLoopFlag = true;
}
} else {
if (currentSetting < (numOfSettings - 1)) {
currentSetting++;
settingsLoopFlag = true;
}
}
} else if (inRange(hallMeasurement, remoteSettings.centerHallValue - 50, remoteSettings.centerHallValue + 50)) {
settingsLoopFlag = false;
}
}
void drawSettingNumber() {
// Position on OLED
int x = 2; int y = 10;
// Draw current setting number box
u8g2.drawRFrame(x + 102, y - 10, 22, 32, 4);
// Draw current setting number
displayString = (String)(currentSetting + 1);
displayString.toCharArray(displayBuffer, displayString.length() + 1);
u8g2.setFont(u8g2_font_profont22_tn);
u8g2.drawStr(x + 108, 22, displayBuffer);
}
void drawSettingsMenu() {
// Position on OLED
int x = 0; int y = 10;
// Draw setting title
displayString = settingPages[currentSetting][0];
displayString.toCharArray(displayBuffer, displayString.length() + 1);
u8g2.setFont(u8g2_font_profont12_tr);
u8g2.drawStr(x, y, displayBuffer);
int val = getSettingValue(currentSetting);
displayString = (String)val + "" + settingPages[currentSetting][1];
displayString.toCharArray(displayBuffer, displayString.length() + 1);
u8g2.setFont(u8g2_font_10x20_tr );
if (changeSelectedSetting == true) {
u8g2.drawStr(x + 10, y + 20, displayBuffer);
} else {
u8g2.drawStr(x, y + 20, displayBuffer);
}
}
void setDefaultEEPROMSettings() {
for (int i = 0; i < numOfSettings; i++) {
setSettingValue(i, settingRules[i][0]);
}
updateEEPROMSettings();
}
void loadEEPROMSettings() {
// Load settings from EEPROM to custom struct
EEPROM.get(0, remoteSettings);
bool rewriteSettings = false;
// Loop through all settings to check if everything is fine
for (int i = 0; i < numOfSettings; i++) {
int val = getSettingValue(i);
if (! inRange(val, settingRules[i][1], settingRules[i][2])) {
// Setting is damaged or never written. Rewrite default.
rewriteSettings = true;
setSettingValue(i, settingRules[i][0]);
}
}
if (rewriteSettings == true) {
updateEEPROMSettings();
} else {
// Calculate constants
calculateRatios();
}
}
// Write settings to the EEPROM then exiting settings menu.
void updateEEPROMSettings() {
EEPROM.put(0, remoteSettings);
calculateRatios();
}
// Update values used to calculate speed and distance travelled.
void calculateRatios() {
gearRatio = (float)remoteSettings.motorPulley / (float)remoteSettings.wheelPulley;
ratioRpmSpeed = (gearRatio * 60 * (float)remoteSettings.wheelDiameter * 3.14156) / (((float)remoteSettings.motorPoles / 2) * 1000000); // ERPM to Km/h
ratioPulseDistance = (gearRatio * (float)remoteSettings.wheelDiameter * 3.14156) /
(((float)remoteSettings.motorPoles * 3) * 1000000); // Pulses to km travelled
}
// Get settings value by index (usefull when iterating through settings).
int getSettingValue(int index) {
int value;
switch (index) {
case 0: value = remoteSettings.triggerMode; break;
case 1: value = remoteSettings.batteryType; break;
case 2: value = remoteSettings.batteryCells; break;
case 3: value = remoteSettings.motorPoles; break;
case 4: value = remoteSettings.motorPulley; break;
case 5: value = remoteSettings.wheelPulley; break;
case 6: value = remoteSettings.wheelDiameter; break;
case 7: value = remoteSettings.useUart; break;
case 8: value = remoteSettings.minHallValue; break;
case 9: value = remoteSettings.centerHallValue; break;
case 10: value = remoteSettings.maxHallValue; break;
}
return value;
}
// Set a value of a specific setting by index.
void setSettingValue(int index, int value) {
switch (index) {
case 0: remoteSettings.triggerMode = value; break;
case 1: remoteSettings.batteryType = value; break;
case 2: remoteSettings.batteryCells = value; break;
case 3: remoteSettings.motorPoles = value; break;
case 4: remoteSettings.motorPulley = value; break;
case 5: remoteSettings.wheelPulley = value; break;
case 6: remoteSettings.wheelDiameter = value; break;
case 7: remoteSettings.useUart = value; break;
case 8: remoteSettings.minHallValue = value; break;
case 9: remoteSettings.centerHallValue = value; break;
case 10: remoteSettings.maxHallValue = value; break;
}
}
// Check if an integer is within a min and max value
bool inRange(int val, int minimum, int maximum) {
return ((minimum <= val) && (val <= maximum));
}
// Return true if trigger is activated, false otherwice
boolean triggerActive() {
if (digitalRead(triggerPin) == LOW)
return true;
else
return false;
}
// Function used to transmit the throttle value, and receive the VESC realtime data.
void transmitToVesc() {
// Transmit once every 50 millisecond
if (millis() - lastTransmission >= 50) {
lastTransmission = millis();
boolean sendSuccess = false;
// Transmit the speed value (0-255).
sendSuccess = radio.write(&throttle, sizeof(throttle));
radio.write(&lightValue, sizeof(lightValue));
// Listen for an acknowledgement reponse (return of VESC data).
while (radio.isAckPayloadAvailable()) {
radio.read(&data, sizeof(data));
}
if (sendSuccess == true)
{
// Transmission was a succes
failCount = 0;
sendSuccess = false;
DEBUG_PRINT("Transmission succes");
} else {
// Transmission was not a succes
failCount++;
DEBUG_PRINT("Failed transmission");
}
// If lost more than 5 transmissions, we can assume that connection is lost.
if (failCount < 5) {
connected = true;
} else {
connected = false;
}
}
}
void calculateThrottlePosition() {
// Hall sensor reading can be noisy, lets make an average reading.
int total = 0;
for (int i = 0; i < 10; i++) {
total += analogRead(hallSensorPin);
}
hallMeasurement = total / 10;
DEBUG_PRINT( (String)hallMeasurement );
if (hallMeasurement >= remoteSettings.centerHallValue) {
throttle = constrain(map(hallMeasurement, remoteSettings.centerHallValue, remoteSettings.maxHallValue, 127, 255), 127, 255);
} else {
throttle = constrain(map(hallMeasurement, remoteSettings.minHallValue, remoteSettings.centerHallValue, 0, 127), 0, 127);
}
// removeing center noise
if (abs(throttle - 127) < hallCenterMargin) {
throttle = 127;
}
}
// Function used to indicate the remotes battery level.
int batteryLevel() {
float voltage = batteryVoltage();
if (voltage <= minVoltage) {
return 0;
} else if (voltage >= maxVoltage) {
return 100;
} else {
return (voltage - minVoltage) * 100 / (maxVoltage - minVoltage);
}
}
// Function to calculate and return the remotes battery voltage.
float batteryVoltage() {
float batteryVoltage = 0.0;
int total = 0;
for (int i = 0; i < 10; i++) {
total += analogRead(batteryMeasurePin);
}
batteryVoltage = (refVoltage / 1024.0) * ((float)total / 10.0);
return batteryVoltage;
}
void updateMainDisplay() {
u8g2.firstPage();
do {
if (changeSettings == true) {
drawSettingsMenu();
drawSettingNumber();
} else {
drawThrottle();
rawPage();
drawBatteryLevel();
drawSignal();
}
} while ( u8g2.nextPage() );
}
void drawStartScreen() {
u8g2.firstPage();
do {
u8g2.drawXBM( 4, 4, 24, 24, logo_bits);
displayString = "Esk8 remote";
displayString.toCharArray(displayBuffer, 12);
u8g2.setFont(u8g2_font_helvR10_tr );
u8g2.drawStr(34, 22, displayBuffer);
} while ( u8g2.nextPage() );
delay(1500);
}
void drawTitleScreen(String title) {
u8g2.firstPage();
do {
title.toCharArray(displayBuffer, 20);
u8g2.setFont(u8g2_font_helvR10_tr );
u8g2.drawStr(12, 20, displayBuffer);
} while ( u8g2.nextPage() );
delay(1500);
}
void drawPage() {
int decimals;
float value;
String suffix;
String prefix;
int first, last;
int x = 0;
int y = 16;
// Rotate the realtime data each 4s.
if ((millis() - lastDataRotation) >= 4000) {
lastDataRotation = millis();
displayData++;
if (displayData > 2) {
displayData = 0;
}
}
switch (displayData) {
case 0:
value = ratioRpmSpeed * data.rpm;
suffix = "KMH";
prefix = "SPEED";
decimals = 1;
break;
case 1:
value = ratioPulseDistance * data.tachometerAbs;
suffix = "KM";
prefix = "DISTANCE";
decimals = 2;
break;
case 2:
value = data.inpVoltage;
suffix = "V";
prefix = "BATTERY";
decimals = 1;
break;
}
// Display prefix (title)
displayString = prefix;
displayString.toCharArray(displayBuffer, 10);
u8g2.setFont(u8g2_font_profont12_tr);
u8g2.drawStr(x, y - 1, displayBuffer);
// Split up the float value: a number, b decimals.
first = abs(floor(value));
last = value * pow(10, 3) - first * pow(10, 3);
// Add leading zero
if (first <= 9) {
displayString = "0" + (String)first;
} else {
displayString = (String)first;
}
// Display numbers
displayString.toCharArray(displayBuffer, 10);
u8g2.setFont(u8g2_font_logisoso22_tn );
u8g2.drawStr(x + 55, y + 13, displayBuffer);
// Display decimals
displayString = "." + (String)last;
displayString.toCharArray(displayBuffer, decimals + 2);
u8g2.setFont(u8g2_font_profont12_tr);
u8g2.drawStr(x + 86, y - 1, displayBuffer);
// Display suffix
displayString = suffix;
displayString.toCharArray(displayBuffer, 10);
u8g2.setFont(u8g2_font_profont12_tr);
u8g2.drawStr(x + 86 + 2, y + 13, displayBuffer);
}
void drawThrottle() {
int x = 0;
int y = 18;
// Draw throttle
u8g2.drawHLine(x, y, 52);
u8g2.drawVLine(x, y, 10);
u8g2.drawVLine(x + 52, y, 10);
u8g2.drawHLine(x, y + 10, 5);
u8g2.drawHLine(x + 52 - 4, y + 10, 5);
if (throttle >= 127) {
int width = map(throttle, 127, 255, 0, 49);
for (int i = 0; i < width; i++) {
//if( (i % 2) == 0){
u8g2.drawVLine(x + i + 2, y + 2, 7);
//}
}
} else {
int width = map(throttle, 0, 126, 49, 0);
for (int i = 0; i < width; i++) {
//if( (i % 2) == 0){
u8g2.drawVLine(x + 50 - i, y + 2, 7);
//}
}
}
}
bool signalBlink = false;
void drawSignal() {
// Position on OLED
int x = 114; int y = 17;
if (connected == true) {
if (triggerActive()) {
u8g2.drawXBM(x, y, 12, 12, signal_transmitting_bits);
} else {
u8g2.drawXBM(x, y, 12, 12, signal_connected_bits);
}
} else {
if (millis() - lastSignalBlink > 500) {
signalBlink = !signalBlink;
lastSignalBlink = millis();
}
if (signalBlink == true) {
u8g2.drawXBM(x, y, 12, 12, signal_connected_bits);
} else {
u8g2.drawXBM(x, y, 12, 12, signal_noconnection_bits);
}
}
}
void drawBatteryLevel() {
int level = batteryLevel();
// Position on OLED
int x = 108; int y = 4;
u8g2.drawFrame(x + 2, y, 18, 9);
u8g2.drawBox(x, y + 2, 2, 5);
for (int i = 0; i < 5; i++) {
int p = round((100 / 5) * i);
if (p <= level)
{
u8g2.drawBox(x + 4 + (3 * i), y + 2, 2, 5);
}
}
}
and RECEIVER:
#include <SPI.h>
#include <nRF24L01.h>
#include "RF24.h"
#include "VescUart.h"
#define SERIALO
#define SERIALIO Serial
struct vescValues {
float ampHours;
float inpVoltage;
long rpm;
long tachometerAbs;
};
RF24 radio(9, 10);
const uint64_t pipe = 0xE8E8F0F0E1LL;
bool recievedData = false;
uint32_t lastTimeReceived = 0;
int motorSpeed = 127;
int timeoutMax = 500;
int speedPin = 5;
int lightPin = 7;
int lightValue;
struct bldcMeasure measuredValues;
struct vescValues data;
unsigned long lastDataCheck;
void setup() {
SERIALIO.begin(115200);
radio.begin();
radio.enableAckPayload();
radio.enableDynamicPayloads();
radio.openReadingPipe(1, pipe);
radio.startListening();
pinMode(speedPin, OUTPUT);
analogWrite(speedPin, motorSpeed);
pinMode(lightPin, OUTPUT);
}
void loop() {
getVescData();
// If transmission is available
if (radio.available())
{
// The next time a transmission is received on pipe, the data in gotByte will be sent back in the acknowledgement (this could later be changed to data from VESC!)
radio.writeAckPayload(pipe, &data, sizeof(data));
// Read the actual message
radio.read(&motorSpeed, sizeof(motorSpeed));
recievedData = true;
radio.read(&lightValue, sizeof(lightValue));
if (lightValue==1){
digitalWrite(lightPin, HIGH);
}
else {
digitalWrite(lightPin, LOW);
}
}
if (recievedData == true)
{
// A speed is received from the transmitter (remote).
lastTimeReceived = millis();
recievedData = false;
// Write the PWM signal to the ESC (0-255).
analogWrite(speedPin, motorSpeed);
}
else if ((millis() - lastTimeReceived) > timeoutMax)
{
// No speed is received within the timeout limit.
motorSpeed = 127;
analogWrite(speedPin, motorSpeed);
}
}
void getVescData() {
if (millis() - lastDataCheck >= 250) {
lastDataCheck = millis();
// Only transmit what we need
if (VescUartGetValue(measuredValues)) {
data.ampHours = measuredValues.ampHours;
data.inpVoltage = measuredValues.inpVoltage;
data.rpm = measuredValues.rpm;
data.tachometerAbs = measuredValues.tachometerAbs;
} else {
data.ampHours = 0.0;
data.inpVoltage = 0.0;
data.rpm = 0;
data.tachometerAbs = 0;
}
}
}
Thanks for that hint… unfortunately there isn’t such a mod
I believe the problem in your code is that the receiver never knows if its a lightValue or a throttle value it receives. I would add both throttle and lightvalue to a struct, and then transmit that whole struct. In this way you only have to do one radio.write(&package, sizeof(package)).
struct transmit {
int throttle;
bool light;
} package;
And then of course save the lightValue to the struct before transmitting it:
package.throttle = throttle;
package.light = lightValue;
sendSuccess = radio.write(&package, sizeof(package));
Cap? what cap? And where should it be?
THANKS!
What should I write in the receiver code? This does not work
radio.read(&package, sizeof(package));
if (lightValue==1){
digitalWrite(lightPin, HIGH);
}
else {
digitalWrite(lightPin, LOW);
}
https://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo <== nice colorful write up (although it appears site is closing soon).
“Solder a 100nF ceramic cap across the gnd and 3.3v pins direct on the nrf24l01+ modules!Some have used a 1uF to 10uF capacitor.”
SIDE NOTE; on any remote style used, be sure you have the right corresponding “nrf24 library” and change the OG pipe#.