diff --git a/README.md b/README.md index 9a332c3..2ece6d2 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,32 @@ # nRF24-Esk8-Remote -Control your electric skateboard an Arduino controlled remote. This repository contains the needed software for the remote and the receiver, however you will need to install a few Arduino Libraries in order to compile the Arduino sketches. The Arduino IDE comes with most of the needed libraries, but you will ned to manually install VescUartControl from RollingGecko: https://github.com/RollingGecko/VescUartControl. +After building and hacking several together, I ended up with this design of my own based on electronics and software from SolidGeek (available at https://github.com/SolidGeek/nRF24-Esk8-Remote). + +The remote I designed has the following features: -You can find the 3D-models for the remote (STL files) on Thingiverse: https://www.thingiverse.com/thing:2454391 and read more about the project on: https://www.electric-skateboard.builders/t/simple-3d-printed-nrf-remote-arduino-controlled/28543 +- A dead man's switch which deactivates the throttle when the remote is not held (safety feature because the trigger can accidentally go off otherwise, ask me how I know) +- A mode switch which swaps between displayed data (Speed, distance, battery voltage, Ah drawn, current draw) +- Ergonomic OLED display position so you don't need to twist your wrist to read it. +- Menu to adjust settings +- Programmable deck selection via menu +- Calibration of throttle via menu +- Ambidextrous design, swap to left hand use by adjusting the script- +- Skate bearing used in trigger mechanism for smoother operation as well just a fun detail considering it's meant for an esk8 +- Hall sensor instead of potentiometer to prevent potential wear of a pot -I have made a Wiki here on Github, with a few tips and guides on how to build the remote. The Wiki can be found here: https://github.com/SolidGeek/nRF24-Esk8-Remote/wiki +STLs available at https://www.thingiverse.com/thing:2800544 -Donation link: https://www.paypal.me/solidgeek +Youtube video available at https://www.youtube.com/watch?v=gQl7mLMAiAs&feature=youtu.be + +Part List available at https://docs.google.com/spreadsheets/d/1vXR9ce0m25Ap6XxzlymFo_pfpIeT2RAqWCypW-a-Jes/edit?usp=sharing + +PCB Files available at https://easyeda.com/ervinelin/New_Project-35f7bf3537744cda8e1064904f6a78a5 + +Forum discussion available at https://www.electric-skateboard.builders/t/diy-trigger-style-remote-with-telemetry-complete-guide/48231 + +Build guide available at https://github.com/ModMiniMan/nRF24-Esk8-Remote/wiki + +You will need to have intermediate soldering skills to complete the build as well as knowledge on how to program an Arduino and adjust simple code. Of course if you print this yourself you will need to know how to 3D print. + +Caveats: +Remote is experimental and not an off the shelf product that has undergone proper testing. Build and use at your own risk. Please bench test extensively before actual use. Lastly, I highly recommend protective gear when using the remote just in case something doesn't work (many many things can go wrong) diff --git a/images/CopperTape.jpg b/images/CopperTape.jpg new file mode 100644 index 0000000..74cd74b Binary files /dev/null and b/images/CopperTape.jpg differ diff --git a/images/DIY-Remote-PCB-Bottom.jpg b/images/DIY-Remote-PCB-Bottom.jpg new file mode 100644 index 0000000..242409c Binary files /dev/null and b/images/DIY-Remote-PCB-Bottom.jpg differ diff --git a/images/DIY-Remote-PCB-Top.jpg b/images/DIY-Remote-PCB-Top.jpg new file mode 100644 index 0000000..514cf2d Binary files /dev/null and b/images/DIY-Remote-PCB-Top.jpg differ diff --git a/images/DIY_Kit_1.jpg b/images/DIY_Kit_1.jpg new file mode 100644 index 0000000..b6e3ae4 Binary files /dev/null and b/images/DIY_Kit_1.jpg differ diff --git a/images/DIY_Kit_2.jpg b/images/DIY_Kit_2.jpg new file mode 100644 index 0000000..9844432 Binary files /dev/null and b/images/DIY_Kit_2.jpg differ diff --git a/images/DIY_Remote_Massing.JPG b/images/DIY_Remote_Massing.JPG new file mode 100644 index 0000000..fb62cf7 Binary files /dev/null and b/images/DIY_Remote_Massing.JPG differ diff --git a/images/Deck_Select.jpg b/images/Deck_Select.jpg new file mode 100644 index 0000000..d1c9d03 Binary files /dev/null and b/images/Deck_Select.jpg differ diff --git a/images/Hacked_MiniRemote_1.jpg b/images/Hacked_MiniRemote_1.jpg new file mode 100644 index 0000000..8c2d8e5 Binary files /dev/null and b/images/Hacked_MiniRemote_1.jpg differ diff --git a/images/Hacked_MiniRemote_2.jpg b/images/Hacked_MiniRemote_2.jpg new file mode 100644 index 0000000..bfe7df7 Binary files /dev/null and b/images/Hacked_MiniRemote_2.jpg differ diff --git a/images/HallSensor.jpg b/images/HallSensor.jpg new file mode 100644 index 0000000..5e6d1c8 Binary files /dev/null and b/images/HallSensor.jpg differ diff --git a/images/InitialSketch.jpg b/images/InitialSketch.jpg new file mode 100644 index 0000000..1a01a56 Binary files /dev/null and b/images/InitialSketch.jpg differ diff --git a/images/LC_Filter.jpg b/images/LC_Filter.jpg new file mode 100644 index 0000000..1abcb4b Binary files /dev/null and b/images/LC_Filter.jpg differ diff --git a/images/NRF_MainPCB.jpg b/images/NRF_MainPCB.jpg new file mode 100644 index 0000000..3bf7db6 Binary files /dev/null and b/images/NRF_MainPCB.jpg differ diff --git a/images/NRF_SolderedPins.jpg b/images/NRF_SolderedPins.jpg new file mode 100644 index 0000000..3aa4ae7 Binary files /dev/null and b/images/NRF_SolderedPins.jpg differ diff --git a/images/OLED_SwapDirection.jpg b/images/OLED_SwapDirection.jpg new file mode 100644 index 0000000..75447fa Binary files /dev/null and b/images/OLED_SwapDirection.jpg differ diff --git a/images/OLED_Wiring_1.jpg b/images/OLED_Wiring_1.jpg new file mode 100644 index 0000000..bf5a7e5 Binary files /dev/null and b/images/OLED_Wiring_1.jpg differ diff --git a/images/OLED_Wiring_2.jpg b/images/OLED_Wiring_2.jpg new file mode 100644 index 0000000..5401521 Binary files /dev/null and b/images/OLED_Wiring_2.jpg differ diff --git a/images/PCB_1.jpg b/images/PCB_1.jpg new file mode 100644 index 0000000..1c9f20f Binary files /dev/null and b/images/PCB_1.jpg differ diff --git a/images/PCB_2.jpg b/images/PCB_2.jpg new file mode 100644 index 0000000..1d60e60 Binary files /dev/null and b/images/PCB_2.jpg differ diff --git a/images/PCB_3.jpg b/images/PCB_3.jpg new file mode 100644 index 0000000..474f8cb Binary files /dev/null and b/images/PCB_3.jpg differ diff --git a/images/PCB_4.jpg b/images/PCB_4.jpg new file mode 100644 index 0000000..fb09961 Binary files /dev/null and b/images/PCB_4.jpg differ diff --git a/images/PCB_Build.jpg b/images/PCB_Build.jpg new file mode 100644 index 0000000..f797120 Binary files /dev/null and b/images/PCB_Build.jpg differ diff --git a/images/PCB_Soldered.jpg b/images/PCB_Soldered.jpg new file mode 100644 index 0000000..0f1596e Binary files /dev/null and b/images/PCB_Soldered.jpg differ diff --git a/images/PCBs.jpg b/images/PCBs.jpg new file mode 100644 index 0000000..2f79de9 Binary files /dev/null and b/images/PCBs.jpg differ diff --git a/images/PaperPrint.jpg b/images/PaperPrint.jpg new file mode 100644 index 0000000..a1995c0 Binary files /dev/null and b/images/PaperPrint.jpg differ diff --git a/images/RemoteCasingPrint.jpg b/images/RemoteCasingPrint.jpg new file mode 100644 index 0000000..962ab7e Binary files /dev/null and b/images/RemoteCasingPrint.jpg differ diff --git a/images/RemoteCasingPrint_2.jpg b/images/RemoteCasingPrint_2.jpg new file mode 100644 index 0000000..6232d05 Binary files /dev/null and b/images/RemoteCasingPrint_2.jpg differ diff --git a/images/Remote_Casing.jpg b/images/Remote_Casing.jpg new file mode 100644 index 0000000..ed84a24 Binary files /dev/null and b/images/Remote_Casing.jpg differ diff --git a/images/Rx_1.jpg b/images/Rx_1.jpg new file mode 100644 index 0000000..e0da330 Binary files /dev/null and b/images/Rx_1.jpg differ diff --git a/images/Rx_2.jpg b/images/Rx_2.jpg new file mode 100644 index 0000000..9d55ff5 Binary files /dev/null and b/images/Rx_2.jpg differ diff --git a/images/Rx_HeatShrink.jpg b/images/Rx_HeatShrink.jpg new file mode 100644 index 0000000..d8fe3e1 Binary files /dev/null and b/images/Rx_HeatShrink.jpg differ diff --git a/images/Rx_NRF.jpg b/images/Rx_NRF.jpg new file mode 100644 index 0000000..85cdea3 Binary files /dev/null and b/images/Rx_NRF.jpg differ diff --git a/images/Rx_OLD.jpg b/images/Rx_OLD.jpg new file mode 100644 index 0000000..6a77e81 Binary files /dev/null and b/images/Rx_OLD.jpg differ diff --git a/images/Rx_PCB_OLD.png b/images/Rx_PCB_OLD.png new file mode 100644 index 0000000..a8e8d46 Binary files /dev/null and b/images/Rx_PCB_OLD.png differ diff --git a/images/Rx_inBag.jpg b/images/Rx_inBag.jpg new file mode 100644 index 0000000..db82736 Binary files /dev/null and b/images/Rx_inBag.jpg differ diff --git a/images/Schematic.jpg b/images/Schematic.jpg new file mode 100644 index 0000000..813abf3 Binary files /dev/null and b/images/Schematic.jpg differ diff --git a/images/Sketches.jpg b/images/Sketches.jpg new file mode 100644 index 0000000..1af560d Binary files /dev/null and b/images/Sketches.jpg differ diff --git a/images/SwitchWiring.jpg b/images/SwitchWiring.jpg new file mode 100644 index 0000000..44c285a Binary files /dev/null and b/images/SwitchWiring.jpg differ diff --git a/images/Transmitter_1.jpg b/images/Transmitter_1.jpg new file mode 100644 index 0000000..3c0ccef Binary files /dev/null and b/images/Transmitter_1.jpg differ diff --git a/images/Transmitter_2.jpg b/images/Transmitter_2.jpg new file mode 100644 index 0000000..d048cc9 Binary files /dev/null and b/images/Transmitter_2.jpg differ diff --git a/images/Transmitter_DM_Switch.jpg b/images/Transmitter_DM_Switch.jpg new file mode 100644 index 0000000..31c9994 Binary files /dev/null and b/images/Transmitter_DM_Switch.jpg differ diff --git a/images/Transmitter_Internals_1.jpg b/images/Transmitter_Internals_1.jpg new file mode 100644 index 0000000..3917248 Binary files /dev/null and b/images/Transmitter_Internals_1.jpg differ diff --git a/images/Transmitter_Internals_2.jpg b/images/Transmitter_Internals_2.jpg new file mode 100644 index 0000000..e58f79a Binary files /dev/null and b/images/Transmitter_Internals_2.jpg differ diff --git a/images/TriggerMech_OLD.jpg b/images/TriggerMech_OLD.jpg new file mode 100644 index 0000000..e895f23 Binary files /dev/null and b/images/TriggerMech_OLD.jpg differ diff --git a/images/USB_PortAlign.jpg b/images/USB_PortAlign.jpg new file mode 100644 index 0000000..01aabbe Binary files /dev/null and b/images/USB_PortAlign.jpg differ diff --git a/images/electronics_image_tp4056.png b/images/electronics_image_tp4056.png deleted file mode 100644 index 0da7a79..0000000 Binary files a/images/electronics_image_tp4056.png and /dev/null differ diff --git a/images/electronics_schematic_part1.png b/images/electronics_schematic_part1.png deleted file mode 100644 index 98a4672..0000000 Binary files a/images/electronics_schematic_part1.png and /dev/null differ diff --git a/images/electronics_schematic_part2.png b/images/electronics_schematic_part2.png deleted file mode 100644 index 1641884..0000000 Binary files a/images/electronics_schematic_part2.png and /dev/null differ diff --git a/images/image_remote.jpg b/images/image_remote.jpg deleted file mode 100644 index 031765b..0000000 Binary files a/images/image_remote.jpg and /dev/null differ diff --git a/images/images.txt b/images/images.txt deleted file mode 100644 index 8b13789..0000000 --- a/images/images.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/images/remote_3dprint.png b/images/remote_3dprint.png deleted file mode 100644 index 38a8848..0000000 Binary files a/images/remote_3dprint.png and /dev/null differ diff --git a/receiver/receiver.ino b/receiver/receiver.ino deleted file mode 100644 index fb9e81c..0000000 --- a/receiver/receiver.ino +++ /dev/null @@ -1,93 +0,0 @@ -#include -#include -#include "RF24.h" -#include "VescUart.h" - -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; - -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); -} - -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; - } - - 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; - } - } -} diff --git a/receiver_VESC6/receiver_VESC6.ino b/receiver_VESC6/receiver_VESC6.ino new file mode 100644 index 0000000..9988602 --- /dev/null +++ b/receiver_VESC6/receiver_VESC6.ino @@ -0,0 +1,150 @@ +#include +#include +#include "RF24.h" +#include "VescUart.h" +#include +Servo myservo; + +//#define DEBUG + +#ifdef DEBUG +#define DEBUG_PRINT(x) Serial.println (x) +#include "printf.h" +#else +#define DEBUG_PRINT(x) +#endif + +#define SERIALIO Serial + +struct vescValues { + float ampHours; + float inpVoltage; + long rpm; + long tachometerAbs; + float avgMotorCurrent; +}; + +RF24 radio(9, 10); +//int radioChannel = 108; // Above most WiFi frequencies +const uint64_t pipe = 0xA8A8FEFEE1LL; // Please change this to your own pipe address +const uint8_t defaultChannel = 108; +uint32_t timeoutTimer = 0; + +// Last time data was pulled from VESC +unsigned long lastUartPull; + +// Defining struct to handle callback data (auto ack) +struct callback { + float ampHours; + float inpVoltage; + long rpm; + long tachometerAbs; + float avgMotorCurrent; +}; + +struct bldcMeasure uartData; +struct callback returnData; + +bool recievedData = false; +uint32_t lastTimeReceived = 0; + +int motorSpeed = 1500 ; // This is in microseconds +int timeoutMax = 500; +int throttlePin = 5; +//int resetTrigger = 0; + +struct bldcMeasure measuredValues; + +struct vescValues data; +unsigned long lastDataCheck; + +void setup() { + + SetSerialPort(&SERIALIO); + SERIALIO.begin(115200); + + myservo.attach(throttlePin); + myservo.write(motorSpeed); + //pinMode(throttlePin, OUTPUT); // This is the old analogWrite method + //analogWrite(throttlePin, motorSpeed); // This is the old analogWrite method + + initiateReceiver(); +} + +void loop() { + + getVescData(); + + // If transmission is available + while (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; + } + + if (recievedData == true) + { + // A speed is received from the transmitter (remote). + + lastTimeReceived = millis(); + recievedData = false; + + // Write the PWM signal to the ESC (0-255) // This is the old analogWrite method + //analogWrite(throttlePin, motorSpeed); // This is the old analogWrite method + // Maps motorspeed signal from remote from 0-255 to 1000-2000ms + motorSpeed = map(motorSpeed, 0, 255, 1000, 2000); + // Writes microseconds to throttle pin + myservo.writeMicroseconds(motorSpeed); + + } + else if ((millis() - lastTimeReceived) > timeoutMax) + { + // No speed is received within the timeout limit. + //analogWrite(throttlePin, motorSpeed); + myservo.writeMicroseconds(1500); + } +} + +void initiateReceiver() { + + // Start radio communication + radio.begin(); + // radio.setChannel(defaultChannel); + radio.setDataRate(RF24_250KBPS); + //radio.setChannel(108); + radio.enableAckPayload(); + radio.enableDynamicPayloads(); + radio.openReadingPipe(1, pipe); + radio.startListening(); + +} + +void getVescData() { + + if (millis() - lastDataCheck >= 250) { + + lastDataCheck = millis(); + + // Only transmit what we need + if ( VescUartGetValue(uartData) ) + { + data.ampHours = uartData.ampHours; + data.inpVoltage = uartData.inpVoltage; + data.rpm = uartData.rpm; + data.tachometerAbs = uartData.tachometerAbs; + data.avgMotorCurrent = uartData.avgMotorCurrent; + } + else + { + data.ampHours = 0.0; + data.inpVoltage = 0.0; + data.rpm = 0; + data.tachometerAbs = 0; + data.avgMotorCurrent = 0; + } + } +} diff --git a/transmitter/transmitter.ino b/transmitter/transmitter_DmSwitch_VESC6.ino similarity index 74% rename from transmitter/transmitter.ino rename to transmitter/transmitter_DmSwitch_VESC6.ino index 3c5e4be..c153a33 100644 --- a/transmitter/transmitter.ino +++ b/transmitter/transmitter_DmSwitch_VESC6.ino @@ -5,7 +5,7 @@ #include "RF24.h" #include "VescUart.h" -// #define DEBUG +//#define DEBUG #ifdef DEBUG #define DEBUG_PRINT(x) Serial.println (x) @@ -15,7 +15,8 @@ #endif // Defining the type of display used (128x32) -U8G2_SSD1306_128X32_UNIVISION_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE); +U8G2_SSD1306_128X32_UNIVISION_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE); // Right Handed Display +//U8G2_SSD1306_128X32_UNIVISION_1_HW_I2C u8g2(U8G2_R2, U8X8_PIN_NONE); // Left Handed Display 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 }; @@ -40,6 +41,7 @@ struct vescValues { float inpVoltage; long rpm; long tachometerAbs; + float avgMotorCurrent; }; // Defining struct to hold stats @@ -52,17 +54,11 @@ struct stats { // 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; + byte deck; int minHallValue; int centerHallValue; int maxHallValue; + int deadzone; }; // Defining variables for speed and distance calculation @@ -71,43 +67,43 @@ float ratioRpmSpeed; float ratioPulseDistance; byte currentSetting = 0; -const byte numOfSettings = 11; - -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", ""} +const byte numOfSettings = 4; + +String settingPages[numOfSettings]= { + {"Deck Select"}, + {"Throttle min"}, + {"Throttle center"}, + {"Throttle max"} }; // 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, 2}, // 1 - Single Drive, 2 - Dual Drive, 0 - Sparez + {0, 0, 1023}, // Min Throttle + {512, 0, 1023}, // Mid Throttle + {1023, 0, 1023} // Max Throttle +}; + +// Deck Names +String DeckNames[3]= { + {"Single Bam"}, + {"Dual Tessy"}, + {"Spare"} +}; + +// Deck Details (order and number must follow deck names) - Poles, Pulley Teeth, Wheel Teeth, Wheel Diameter +float Decks[3][4]= { + {14,12,36,83}, + {14,12,36,100}, + {14,12,36,83} }; struct vescValues data; struct settings remoteSettings; -// Pin defination -const byte triggerPin = 4; -const int chargeMeasurePin = A1; +// Pin definition +const byte DmPin = 4; +const byte ModePin = 5; const int batteryMeasurePin = A2; const int hallSensorPin = A3; @@ -118,12 +114,13 @@ const float refVoltage = 5.0; // Set to 4.5V if you are testing connected to USB // Defining variables for Hall Effect throttle. short hallMeasurement, throttle; -byte hallCenterMargin = 4; +byte hallCenterMargin = 5; // 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. +//int radioChannel = 108; // Above most WiFi frequencies +const uint64_t pipe = 0xA8A8F0F0E1LL; // If you change the pipe, you will need to update it on the receiver to. unsigned long lastTransmission; // Defining variables for OLED display @@ -132,6 +129,15 @@ String displayString; short displayData = 0; unsigned long lastSignalBlink; unsigned long lastDataRotation; +int displayTrigger = 0; +String tempString; + +// Defining variables for Deck Selection +float motorPoles; +float motorPulley; +float wheelPulley; +float wheelDiameter; +String selectedDeck; // Instantiating RF24 object for NRF24 communication RF24 radio(9, 10); @@ -146,7 +152,8 @@ bool settingsChangeValueFlag = false; void setup() { - // setDefaultEEPROMSettings(); // Call this function if you want to reset settings + + //setDefaultEEPROMSettings(); // Call this function if you want to reset settings #ifdef DEBUG Serial.begin(9600); @@ -154,15 +161,24 @@ void setup() { loadEEPROMSettings(); - pinMode(triggerPin, INPUT_PULLUP); + pinMode(DmPin, INPUT_PULLUP); + pinMode(ModePin, INPUT_PULLUP); pinMode(hallSensorPin, INPUT); pinMode(batteryMeasurePin, INPUT); u8g2.begin(); - drawStartScreen(); + // Load details of decks + selectedDeck = DeckNames[remoteSettings.deck], + motorPoles = Decks[remoteSettings.deck][0]; + motorPulley = Decks[remoteSettings.deck][1]; + wheelPulley = Decks[remoteSettings.deck][2]; + wheelDiameter = Decks[remoteSettings.deck][3]; + + calculateRatios(); + drawStartScreen(); - if (triggerActive()) { + if (ModeActive()) { changeSettings = true; drawTitleScreen("Remote Settings"); } @@ -190,16 +206,39 @@ void loop() { } else { - // Use throttle and trigger to drive motors - if (triggerActive()) + if (ModeActive()) { - throttle = throttle; + if(displayTrigger == 0){ + displayData++; + displayTrigger = 1; + } + }else + { + displayTrigger = 0; } - else + + // TRIGGER ALWAYS ON + //throttle = throttle; + + // Dead Man Switch + + if (DmActive()) { + throttle = throttle; + } + else{ + + if (throttle < 127) + { + throttle = throttle; + } + else + { // 127 is the middle position - no throttle and no brake/reverse throttle = 127; + } } + // Transmit to receiver transmitToVesc(); } @@ -209,7 +248,7 @@ void loop() { } void controlSettingsMenu() { - if (triggerActive()) { + if (ModeActive()) { if (settingsChangeFlag == false) { // Save settings to EEPROM @@ -224,7 +263,7 @@ void controlSettingsMenu() { settingsChangeFlag = false; } - if (hallMeasurement >= (remoteSettings.maxHallValue - 150) && settingsLoopFlag == false) { + if (hallMeasurement >= (remoteSettings.maxHallValue - 200) && settingsLoopFlag == false) { // Up if (changeSelectedSetting == true) { int val = getSettingValue(currentSetting) + 1; @@ -240,7 +279,7 @@ void controlSettingsMenu() { } } } - else if (hallMeasurement <= (remoteSettings.minHallValue + 150) && settingsLoopFlag == false) { + else if (hallMeasurement <= (remoteSettings.minHallValue + 200) && settingsLoopFlag == false) { // Down if (changeSelectedSetting == true) { int val = getSettingValue(currentSetting) - 1; @@ -280,7 +319,7 @@ void drawSettingsMenu() { int x = 0; int y = 10; // Draw setting title - displayString = settingPages[currentSetting][0]; + displayString = settingPages[currentSetting]; displayString.toCharArray(displayBuffer, displayString.length() + 1); u8g2.setFont(u8g2_font_profont12_tr); @@ -288,17 +327,42 @@ void drawSettingsMenu() { int val = getSettingValue(currentSetting); + if (currentSetting == 0) + { + displayString = (String)DeckNames[val]; + displayString.toCharArray(displayBuffer, displayString.length() + 1); + u8g2.setFont(u8g2_font_7x14B_tr); + }else{ + displayString = (String)val; + displayString.toCharArray(displayBuffer, displayString.length() + 1); + u8g2.setFont(u8g2_font_10x20_tr); + } + /* displayString = (String)val + "" + settingPages[currentSetting][1]; displayString.toCharArray(displayBuffer, displayString.length() + 1); - u8g2.setFont(u8g2_font_10x20_tr ); + u8g2.setFont(u8g2_font_10x20_tr );*/ if (changeSelectedSetting == true) { - u8g2.drawStr(x + 10, y + 20, displayBuffer); + u8g2.drawStr(x + 5, y + 20, displayBuffer); + if( inRange(currentSetting, 1, 3) ){ + tempString = "[" + (String)hallMeasurement + "]"; + drawString(tempString, 8, x + 70, y + 20, u8g2_font_profont12_tr ); + } } else { u8g2.drawStr(x, y + 20, displayBuffer); } } +void drawString(String text, uint8_t lenght, uint8_t x, uint8_t y, const uint8_t *font){ + + static char textBuffer[20]; + + text.toCharArray(textBuffer, lenght); + + u8g2.setFont(font); + u8g2.drawStr(x, y, textBuffer); +} + void setDefaultEEPROMSettings() { for (int i = 0; i < numOfSettings; i++) { setSettingValue(i, settingRules[i][0]); @@ -328,7 +392,7 @@ void loadEEPROMSettings() { updateEEPROMSettings(); } else { // Calculate constants - calculateRatios(); + //calculateRatios(); } } @@ -338,30 +402,25 @@ void updateEEPROMSettings() { 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 + gearRatio = motorPulley / wheelPulley; + // ERPM to Km/h + ratioRpmSpeed = (gearRatio * 60 * wheelDiameter * 3.14156) / ((motorPoles / 2) * 1000000); + // Pulses to km travelled + ratioPulseDistance = (gearRatio * wheelDiameter * 3.14156) / ((motorPoles * 3) * 1000000); } // 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; + case 0: value = remoteSettings.deck; break; + case 1: value = remoteSettings.minHallValue; break; + case 2: value = remoteSettings.centerHallValue; break; + case 3: value = remoteSettings.maxHallValue; break; + case 4: value = remoteSettings.deadzone; break; } return value; } @@ -369,17 +428,11 @@ int getSettingValue(int index) { // 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; + case 0: remoteSettings.deck = value; break; + case 1: remoteSettings.minHallValue = value; break; + case 2: remoteSettings.centerHallValue = value; break; + case 3: remoteSettings.maxHallValue = value; break; + case 4: remoteSettings.deadzone = value; break; } } @@ -388,9 +441,16 @@ 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 if Switches are activated, false otherwise +boolean DmActive() { + if (digitalRead(DmPin) == LOW) + return true; + else + return false; +} + +boolean ModeActive() { + if (digitalRead(ModePin) == LOW) return true; else return false; @@ -438,10 +498,10 @@ void transmitToVesc() { void calculateThrottlePosition() { // Hall sensor reading can be noisy, lets make an average reading. int total = 0; - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 25; i++) { total += analogRead(hallSensorPin); } - hallMeasurement = total / 10; + hallMeasurement = total / 25; DEBUG_PRINT( (String)hallMeasurement ); @@ -507,12 +567,12 @@ void drawStartScreen() { do { u8g2.drawXBM( 4, 4, 24, 24, logo_bits); - displayString = "Esk8 remote"; + displayString = selectedDeck; displayString.toCharArray(displayBuffer, 12); - u8g2.setFont(u8g2_font_helvR10_tr ); + u8g2.setFont(u8g2_font_helvR10_tr); u8g2.drawStr(34, 22, displayBuffer); } while ( u8g2.nextPage() ); - delay(1500); + delay(1000); } void drawTitleScreen(String title) { @@ -522,7 +582,7 @@ void drawTitleScreen(String title) { u8g2.setFont(u8g2_font_helvR10_tr ); u8g2.drawStr(12, 20, displayBuffer); } while ( u8g2.nextPage() ); - delay(1500); + delay(500); } void drawPage() { @@ -536,34 +596,39 @@ void drawPage() { int x = 0; int y = 16; - // Rotate the realtime data each 4s. - if ((millis() - lastDataRotation) >= 4000) { - - lastDataRotation = millis(); - displayData++; - - if (displayData > 2) { + if (displayData > 4) { displayData = 0; } - } switch (displayData) { case 0: value = ratioRpmSpeed * data.rpm; - suffix = "KMH"; - prefix = "SPEED"; + suffix = F("KMH"); + prefix = F("SPEED"); decimals = 1; break; case 1: value = ratioPulseDistance * data.tachometerAbs; - suffix = "KM"; - prefix = "DISTANCE"; + suffix = F("KM"); + prefix = F("DISTANCE"); decimals = 2; break; case 2: value = data.inpVoltage; - suffix = "V"; - prefix = "BATTERY"; + suffix = F("V"); + prefix = F("BATTERY"); + decimals = 1; + break; + case 3: + value = data.ampHours; + suffix = F("Ah"); + prefix = F("Ah DRAWN"); + decimals = 2; + break; + case 4: + value = data.avgMotorCurrent; + suffix = F("A"); + prefix = F("CURRENT"); decimals = 1; break; } @@ -641,7 +706,7 @@ void drawSignal() { int x = 114; int y = 17; if (connected == true) { - if (triggerActive()) { + if (!DmActive()) { u8g2.drawXBM(x, y, 12, 12, signal_transmitting_bits); } else { u8g2.drawXBM(x, y, 12, 12, signal_connected_bits); @@ -676,4 +741,4 @@ void drawBatteryLevel() { u8g2.drawBox(x + 4 + (3 * i), y + 2, 2, 5); } } -} +}