From 8957bb35b1434f6d37b272ce13ab2a90d95d6e76 Mon Sep 17 00:00:00 2001 From: Peemouse Date: Thu, 4 Apr 2019 16:38:34 +0200 Subject: [PATCH 1/7] FW3.49+ compatibility and PPM value request FW3.49 and above compatibility, Use COMM_GET_VALUES_SELECTIVE command. Add functions for requesting PPM to Master VESC over CAN and local VESC (in case of hooking up UART to Master). --- src/VescUart.cpp | 100 +++++++++++++++++++++++++++++++++++++---------- src/VescUart.h | 27 ++++++++++--- src/datatypes.h | 37 ++++++++++++++++-- 3 files changed, 135 insertions(+), 29 deletions(-) diff --git a/src/VescUart.cpp b/src/VescUart.cpp index ac45b19..85a2b9d 100644 --- a/src/VescUart.cpp +++ b/src/VescUart.cpp @@ -1,3 +1,5 @@ +//Compatible with VESC FW3.49 + #include "VescUart.h" #include @@ -28,7 +30,7 @@ int VescUart::receiveUartMessage(uint8_t * payloadReceived) { bool messageRead = false; uint8_t messageReceived[256]; uint16_t lenPayload = 0; - + uint32_t timeout = millis() + 100; // Defining the timestamp for timeout (100ms before timeout) while ( millis() < timeout && messageRead == false) { @@ -78,7 +80,7 @@ int VescUart::receiveUartMessage(uint8_t * payloadReceived) { if(messageRead == false && debugPort != NULL ) { debugPort->println("Timeout"); } - + bool unpacked = false; if (messageRead) { @@ -87,7 +89,7 @@ int VescUart::receiveUartMessage(uint8_t * payloadReceived) { if (unpacked) { // Message was read - return lenPayload; + return lenPayload; } else { // No Message Read @@ -118,10 +120,10 @@ bool VescUart::unpackPayload(uint8_t * message, int lenMes, uint8_t * payload) { if( debugPort != NULL ){ debugPort->print("SRC calc: "); debugPort->println(crcPayload); } - + if (crcPayload == crcMessage) { if( debugPort != NULL ) { - debugPort->print("Received: "); + debugPort->print("Received: "); serialPrint(message, lenMes); debugPort->println(); debugPort->print("Payload : "); @@ -129,7 +131,8 @@ bool VescUart::unpackPayload(uint8_t * message, int lenMes, uint8_t * payload) { } return true; - }else{ + } + else { return false; } } @@ -182,22 +185,29 @@ bool VescUart::processReadPacket(uint8_t * message) { message++; // Removes the packetId from the actual message (payload) switch (packetId){ - case COMM_GET_VALUES: // Structure defined here: https://github.com/vedderb/bldc/blob/43c3bbaf91f5052a35b75c2ff17b5fe99fad94d1/commands.c#L164 + case COMM_GET_VALUES_SETUP_SELECTIVE: // Structure defined here: https://github.com/vedderb/bldc/blob/43c3bbaf91f5052a35b75c2ff17b5fe99fad94d1/commands.c#L164 - ind = 4; // Skip the first 4 bytes + ind = 4; // Skip the mask + data.tempMotor = buffer_get_float16(message, 10.0, &ind); data.avgMotorCurrent = buffer_get_float32(message, 100.0, &ind); data.avgInputCurrent = buffer_get_float32(message, 100.0, &ind); - ind += 8; // Skip the next 8 bytes - data.dutyCycleNow = buffer_get_float16(message, 1000.0, &ind); + //ind += 8; // Skip the next 8 bytes + //data.dutyCycleNow = buffer_get_float16(message, 1000.0, &ind); data.rpm = buffer_get_int32(message, &ind); - data.inpVoltage = buffer_get_float16(message, 10.0, &ind); - data.ampHours = buffer_get_float32(message, 10000.0, &ind); - data.ampHoursCharged = buffer_get_float32(message, 10000.0, &ind); - ind += 8; // Skip the next 8 bytes - data.tachometer = buffer_get_int32(message, &ind); - data.tachometerAbs = buffer_get_int32(message, &ind); + data.inpVoltage = buffer_get_float16(message, 10.0, &ind); + data.watt_hours = buffer_get_float32(message, 10000.0, &ind); + data.watt_hours_charged = buffer_get_float32(message, 10000.0, &ind); + //ind += 8; // Skip the next 8 bytes + //data.tachometer = buffer_get_int32(message, &ind); + //data.tachometerAbs = buffer_get_int32(message, &ind); + data.fault = message[ind]; return true; + case COMM_GET_DECODED_PPM: + + data.throttlePPM = (float)(buffer_get_int32(message, &ind) / 10000.0); + //data.rawValuePPM = buffer_get_float32(message, 100.0, &ind); + return true; break; default: @@ -207,8 +217,34 @@ bool VescUart::processReadPacket(uint8_t * message) { } bool VescUart::getVescValues(void) { + uint8_t command[5]; + command[0] = { COMM_GET_VALUES_SETUP_SELECTIVE }; + //values selected : 0x000118AE + command[1] = { 0x00 }; //mask MSB + command[2] = { 0x01 }; //mask + command[3] = { 0x18 }; //mask + command[4] = { 0xAE }; //mask LSB + uint8_t payload[256]; + + packSendPayload(command, 5); + // delay(1); //needed, otherwise data is not read + + int lenPayload = receiveUartMessage(payload); + + if (lenPayload > 0 && lenPayload < 55) { + bool read = processReadPacket(payload); //returns true if sucessful + return read; + } + else + { + return false; + } +} + +bool VescUart::getLocalVescPPM(void) { + + uint8_t command[1] = { COMM_GET_DECODED_PPM }; - uint8_t command[1] = { COMM_GET_VALUES }; uint8_t payload[256]; packSendPayload(command, 1); @@ -216,7 +252,31 @@ bool VescUart::getVescValues(void) { int lenPayload = receiveUartMessage(payload); - if (lenPayload > 55) { + if (lenPayload > 0) { //&& lenPayload < 55 + bool read = processReadPacket(payload); //returns true if sucessful + return read; + } + else + { + return false; + } +} + +bool VescUart::getMasterVescPPM(uint8_t id) { + + uint8_t command[3]; + command[0] = { COMM_FORWARD_CAN }; + command[1] = id; + command[2] = { COMM_GET_DECODED_PPM }; + + uint8_t payload[256]; + + packSendPayload(command, 3); + // delay(1); //needed, otherwise data is not read + + int lenPayload = receiveUartMessage(payload); + + if (lenPayload > 0) { //&& lenPayload < 55 bool read = processReadPacket(payload); //returns true if sucessful return read; } @@ -235,7 +295,7 @@ void VescUart::setNunchuckValues() { payload[ind++] = nunchuck.valueY; buffer_append_bool(payload, nunchuck.lowerButton, &ind); buffer_append_bool(payload, nunchuck.upperButton, &ind); - + // Acceleration Data. Not used, Int16 (2 byte) payload[ind++] = 0; payload[ind++] = 0; @@ -317,4 +377,4 @@ void VescUart::printVescValues() { debugPort->print("tachometer: "); debugPort->println(data.tachometer); debugPort->print("tachometerAbs: "); debugPort->println(data.tachometerAbs); } -} \ No newline at end of file +} diff --git a/src/VescUart.h b/src/VescUart.h index 6fa88d2..00434c7 100644 --- a/src/VescUart.h +++ b/src/VescUart.h @@ -10,6 +10,7 @@ class VescUart { /** Struct to store the telemetry data returned by the VESC */ struct dataPackage { + float tempMotor; float avgMotorCurrent; float avgInputCurrent; float dutyCycleNow; @@ -17,8 +18,12 @@ class VescUart float inpVoltage; float ampHours; float ampHoursCharged; + float watt_hours; + float watt_hours_charged; long tachometer; long tachometerAbs; + uint8_t fault; + float throttlePPM; }; /** Struct to hold the nunchuck values to send over UART */ @@ -37,20 +42,20 @@ class VescUart VescUart(void); /** Variabel to hold measurements returned from VESC */ - dataPackage data; + dataPackage data; /** Variabel to hold nunchuck values */ - nunchuckPackage nunchuck; + nunchuckPackage nunchuck; /** * @brief Set the serial port for uart communication - * @param port - Reference to Serial port (pointer) + * @param port - Reference to Serial port (pointer) */ void setSerialPort(HardwareSerial* port); /** * @brief Set the serial port for debugging - * @param port - Reference to Serial port (pointer) + * @param port - Reference to Serial port (pointer) */ void setDebugPort(Stream* port); @@ -95,12 +100,22 @@ class VescUart */ void printVescValues(void); - private: + /** + * @brief Request PPM values to local VESC + */ + bool getLocalVescPPM(void); + + /** + * @brief Request PPM values to Master VESC over CANbus + */ + bool getMasterVescPPM(uint8_t id); + + private: /** Variabel to hold the reference to the Serial object to use for UART */ HardwareSerial* serialPort = NULL; - /** Variabel to hold the reference to the Serial object to use for debugging. + /** Variabel to hold the reference to the Serial object to use for debugging. * Uses the class Stream instead of HarwareSerial */ Stream* debugPort = NULL; diff --git a/src/datatypes.h b/src/datatypes.h index 61b9c64..43bdf2f 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -75,7 +75,12 @@ typedef enum { FAULT_CODE_DRV, FAULT_CODE_ABS_OVER_CURRENT, FAULT_CODE_OVER_TEMP_FET, - FAULT_CODE_OVER_TEMP_MOTOR + FAULT_CODE_OVER_TEMP_MOTOR, + FAULT_CODE_GATE_DRIVER_OVER_VOLTAGE, + FAULT_CODE_GATE_DRIVER_UNDER_VOLTAGE, + FAULT_CODE_MCU_UNDER_VOLTAGE, + FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET, + FAULT_CODE_ENCODER } mc_fault_code; typedef enum { @@ -456,7 +461,7 @@ typedef struct { // Communication commands typedef enum { - COMM_FW_VERSION = 0, + COMM_FW_VERSION = 0, COMM_JUMP_TO_BOOTLOADER, COMM_ERASE_NEW_APP, COMM_WRITE_NEW_APP_DATA, @@ -493,7 +498,33 @@ typedef enum { COMM_FORWARD_CAN, COMM_SET_CHUCK_DATA, COMM_CUSTOM_APP_DATA, - COMM_NRF_START_PAIRING + COMM_NRF_START_PAIRING, + COMM_GPD_SET_FSW, + COMM_GPD_BUFFER_NOTIFY, + COMM_GPD_BUFFER_SIZE_LEFT, + COMM_GPD_FILL_BUFFER, + COMM_GPD_OUTPUT_SAMPLE, + COMM_GPD_SET_MODE, + COMM_GPD_FILL_BUFFER_INT8, + COMM_GPD_FILL_BUFFER_INT16, + COMM_GPD_SET_BUFFER_INT_SCALE, + COMM_GET_VALUES_SETUP, + COMM_SET_MCCONF_TEMP, + COMM_SET_MCCONF_TEMP_SETUP, + COMM_GET_VALUES_SELECTIVE, + COMM_GET_VALUES_SETUP_SELECTIVE, + COMM_EXT_NRF_PRESENT, + COMM_EXT_NRF_ESB_SET_CH_ADDR, + COMM_EXT_NRF_ESB_SEND_DATA, + COMM_EXT_NRF_ESB_RX_DATA, + COMM_EXT_NRF_SET_ENABLED, + COMM_DETECT_MOTOR_FLUX_LINKAGE_OPENLOOP, + COMM_DETECT_APPLY_ALL_FOC, + COMM_JUMP_TO_BOOTLOADER_ALL_CAN, + COMM_ERASE_NEW_APP_ALL_CAN, + COMM_WRITE_NEW_APP_DATA_ALL_CAN, + COMM_PING_CAN, + COMM_APP_DISABLE_OUTPUT } COMM_PACKET_ID; // CAN commands From 6b1b22c9250ac95c10f96891f67eeb2022bb1d8e Mon Sep 17 00:00:00 2001 From: Peemouse Date: Thu, 4 Apr 2019 16:40:15 +0200 Subject: [PATCH 2/7] FW3.49+ compatibility and PPM value request FW3.49 and above compatibility, Use COMM_GET_VALUES_SELECTIVE command. Add functions for requesting PPM to Master VESC over CAN and local VESC (in case of hooking up UART to Master). --- examples/getLocalVescPPM/getLocalVescPPM.ino | 42 ++++++++++++++++++ .../getMasterVescPPM/getMasterVescPPM.ino | 43 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 examples/getLocalVescPPM/getLocalVescPPM.ino create mode 100644 examples/getMasterVescPPM/getMasterVescPPM.ino diff --git a/examples/getLocalVescPPM/getLocalVescPPM.ino b/examples/getLocalVescPPM/getLocalVescPPM.ino new file mode 100644 index 0000000..4d19162 --- /dev/null +++ b/examples/getLocalVescPPM/getLocalVescPPM.ino @@ -0,0 +1,42 @@ +/* + Name: getVescValues.ino + Created: 19-08-2018 + Author: SolidGeek + Description: This example is made using a Arduino Micro (Atmega32u4) that has a HardwareSerial port (Serial1) seperated from the Serial port. + A Arduino Nano or Uno that only has one Serial port will not be able to display the data returned. +*/ + +#include + +/** Initiate VescUart class */ +VescUart UART; + +void setup() { + + /** Setup Serial port to display data */ + Serial.begin(9600); + + /** Setup UART port (Serial1 on Atmega32u4) */ + Serial1.begin(19200); + + while (!Serial) {;} + + /** Define which ports to use as UART */ + UART.setSerialPort(&Serial1); +} + +void loop() { + + /** Call the function getVescValues() to acquire data from VESC */ + if ( UART.getLocalVescPPM() ) { + + Serial.println(UART.data.throttlePPM); + + } + else + { + Serial.println("Failed to get data!"); + } + + delay(100); +} diff --git a/examples/getMasterVescPPM/getMasterVescPPM.ino b/examples/getMasterVescPPM/getMasterVescPPM.ino new file mode 100644 index 0000000..5b136ca --- /dev/null +++ b/examples/getMasterVescPPM/getMasterVescPPM.ino @@ -0,0 +1,43 @@ +/* + Name: getVescValues.ino + Created: 19-08-2018 + Author: SolidGeek + Description: This example is made using a Arduino Micro (Atmega32u4) that has a HardwareSerial port (Serial1) seperated from the Serial port. + A Arduino Nano or Uno that only has one Serial port will not be able to display the data returned. +*/ + +#include + +/** Initiate VescUart class */ +VescUart UART; +uint8_t masterVescCANID = 0; + +void setup() { + + /** Setup Serial port to display data */ + Serial.begin(9600); + + /** Setup UART port (Serial1 on Atmega32u4) */ + Serial1.begin(19200); + + while (!Serial) {;} + + /** Define which ports to use as UART */ + UART.setSerialPort(&Serial1); +} + +void loop() { + + /** Call the function getVescValues() to acquire data from VESC */ + if ( UART.getMasterVescPPM(masterVescID) ) { + + Serial.println(UART.data.throttlePPM); + + } + else + { + Serial.println("Failed to get data!"); + } + + delay(100); +} From 4bd7594ee0485323c922471692b43390ddbbd3e7 Mon Sep 17 00:00:00 2001 From: Peemouse Date: Wed, 22 May 2019 16:41:46 +0200 Subject: [PATCH 3/7] Added Firmware version check and code cleaning *Added function for VESC FW version check *Code a bit cleaned --- examples/getFWversion/getFWversion.ino | 45 +++++++++++++++++++ .../getMasterVescPPM/getMasterVescPPM.ino | 6 +-- src/VescUart.cpp | 30 +++++++++++-- src/VescUart.h | 19 ++++++++ 4 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 examples/getFWversion/getFWversion.ino diff --git a/examples/getFWversion/getFWversion.ino b/examples/getFWversion/getFWversion.ino new file mode 100644 index 0000000..60f5500 --- /dev/null +++ b/examples/getFWversion/getFWversion.ino @@ -0,0 +1,45 @@ +/* + Name: getVescValues.ino + Created: 19-08-2018 + Author: SolidGeek + Description: This example is made using a Arduino Micro (Atmega32u4) that has a HardwareSerial port (Serial1) seperated from the Serial port. + A Arduino Nano or Uno that only has one Serial port will not be able to display the data returned. +*/ + +#include + +/** Initiate VescUart class */ +VescUart UART; + +void setup() { + + /** Setup Serial port to display data */ + Serial.begin(115200); + + /** Setup UART port (Serial1 on Atmega32u4) */ + Serial1.begin(115200); + + while (!Serial) {;} + + /** Define which ports to use as UART */ + UART.setSerialPort(&Serial1); + +} + +void loop() { + + /** Call the function getVescValues() to acquire data from VESC */ + if ( UART.getFWversion()) { + Serial.print("FW v"); + Serial.print(UART.fw_version.major); + Serial.print("."); + Serial.println(UART.fw_version.minor); + + } + else + { + Serial.println("Failed to get data!"); + } + + delay(100); +} diff --git a/examples/getMasterVescPPM/getMasterVescPPM.ino b/examples/getMasterVescPPM/getMasterVescPPM.ino index 5b136ca..8463471 100644 --- a/examples/getMasterVescPPM/getMasterVescPPM.ino +++ b/examples/getMasterVescPPM/getMasterVescPPM.ino @@ -15,10 +15,10 @@ uint8_t masterVescCANID = 0; void setup() { /** Setup Serial port to display data */ - Serial.begin(9600); + Serial.begin(115200); /** Setup UART port (Serial1 on Atmega32u4) */ - Serial1.begin(19200); + Serial1.begin(115200); while (!Serial) {;} @@ -29,7 +29,7 @@ void setup() { void loop() { /** Call the function getVescValues() to acquire data from VESC */ - if ( UART.getMasterVescPPM(masterVescID) ) { + if ( UART.getMasterVescPPM(masterVescCANID) ) { Serial.println(UART.data.throttlePPM); diff --git a/src/VescUart.cpp b/src/VescUart.cpp index 85a2b9d..8abfc51 100644 --- a/src/VescUart.cpp +++ b/src/VescUart.cpp @@ -185,19 +185,23 @@ bool VescUart::processReadPacket(uint8_t * message) { message++; // Removes the packetId from the actual message (payload) switch (packetId){ + case COMM_FW_VERSION: // Structure defined here: https://github.com/vedderb/bldc/blob/43c3bbaf91f5052a35b75c2ff17b5fe99fad94d1/commands.c#L164 + + fw_version.major = message[ind++]; + fw_version.minor = message[ind++]; + return true; + case COMM_GET_VALUES_SETUP_SELECTIVE: // Structure defined here: https://github.com/vedderb/bldc/blob/43c3bbaf91f5052a35b75c2ff17b5fe99fad94d1/commands.c#L164 ind = 4; // Skip the mask data.tempMotor = buffer_get_float16(message, 10.0, &ind); data.avgMotorCurrent = buffer_get_float32(message, 100.0, &ind); data.avgInputCurrent = buffer_get_float32(message, 100.0, &ind); - //ind += 8; // Skip the next 8 bytes //data.dutyCycleNow = buffer_get_float16(message, 1000.0, &ind); data.rpm = buffer_get_int32(message, &ind); data.inpVoltage = buffer_get_float16(message, 10.0, &ind); - data.watt_hours = buffer_get_float32(message, 10000.0, &ind); + data.watt_hours = buffer_get_float32(message, 10000.0, &ind); //sum of all VESC if CAN Bus messages 1_2_3_4_5 are exchanged data.watt_hours_charged = buffer_get_float32(message, 10000.0, &ind); - //ind += 8; // Skip the next 8 bytes //data.tachometer = buffer_get_int32(message, &ind); //data.tachometerAbs = buffer_get_int32(message, &ind); data.fault = message[ind]; @@ -286,6 +290,26 @@ bool VescUart::getMasterVescPPM(uint8_t id) { } } +bool VescUart::getFWversion(void){ + + uint8_t command[1] = { COMM_FW_VERSION }; + uint8_t payload[256]; + + packSendPayload(command, 1); + // delay(1); //needed, otherwise data is not read + + int lenPayload = receiveUartMessage(payload); + + if (lenPayload > 0) { //&& lenPayload < 55 + bool read = processReadPacket(payload); //returns true if sucessful + return read; + } + else + { + return false; + } +} + void VescUart::setNunchuckValues() { int32_t ind = 0; uint8_t payload[11]; diff --git a/src/VescUart.h b/src/VescUart.h index 00434c7..b22ffc2 100644 --- a/src/VescUart.h +++ b/src/VescUart.h @@ -26,6 +26,11 @@ class VescUart float throttlePPM; }; + struct FWversionPackage { + uint8_t major; + uint8_t minor; + }; + /** Struct to hold the nunchuck values to send over UART */ struct nunchuckPackage { int valueX; @@ -44,6 +49,9 @@ class VescUart /** Variabel to hold measurements returned from VESC */ dataPackage data; + /** Variable to hold measurements returned from VESC */ + FWversionPackage fw_version; + /** Variabel to hold nunchuck values */ nunchuckPackage nunchuck; @@ -102,14 +110,25 @@ class VescUart /** * @brief Request PPM values to local VESC + * + * @return True if successfull otherwise false */ bool getLocalVescPPM(void); /** * @brief Request PPM values to Master VESC over CANbus + * @param id - CAN ID of the master VESC + * @return True if successfull otherwise false */ bool getMasterVescPPM(uint8_t id); + /** + * @brief Request version of VESC Firmware + * + * @return True if successfull otherwise false + */ + bool getFWversion(void); + private: /** Variabel to hold the reference to the Serial object to use for UART */ From bb9b429fdc2fc063793659687ce7fb8f22399005 Mon Sep 17 00:00:00 2001 From: Peemouse Date: Wed, 22 May 2019 17:50:35 +0200 Subject: [PATCH 4/7] Added all values in deserialization Added all values in deserialization to be uncommented regarding the used mask. --- src/VescUart.cpp | 26 +++++++++++++++++++++++++- src/VescUart.h | 7 +++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/VescUart.cpp b/src/VescUart.cpp index 8abfc51..ca47166 100644 --- a/src/VescUart.cpp +++ b/src/VescUart.cpp @@ -194,19 +194,43 @@ bool VescUart::processReadPacket(uint8_t * message) { case COMM_GET_VALUES_SETUP_SELECTIVE: // Structure defined here: https://github.com/vedderb/bldc/blob/43c3bbaf91f5052a35b75c2ff17b5fe99fad94d1/commands.c#L164 ind = 4; // Skip the mask - data.tempMotor = buffer_get_float16(message, 10.0, &ind); + //data.tempFET = buffer_get_float16(message, 10.0, &ind); + data.tempMotor = buffer_get_float16(message, 10.0, &ind); data.avgMotorCurrent = buffer_get_float32(message, 100.0, &ind); data.avgInputCurrent = buffer_get_float32(message, 100.0, &ind); + //data.avgIdCurrent = buffer_get_float32(message, 100.0, &ind); + //data.avgIqCurrent = buffer_get_float32(message, 100.0, &ind); //data.dutyCycleNow = buffer_get_float16(message, 1000.0, &ind); data.rpm = buffer_get_int32(message, &ind); data.inpVoltage = buffer_get_float16(message, 10.0, &ind); + // data.ampHours = buffer_get_float32(message, 100.0, &ind); //sum of all VESC if CAN Bus messages 1_2_3_4_5 are exchanged + // data.ampHoursCharged = buffer_get_float32(message, 100.0, &ind); //sum of all VESC if CAN Bus messages 1_2_3_4_5 are exchanged data.watt_hours = buffer_get_float32(message, 10000.0, &ind); //sum of all VESC if CAN Bus messages 1_2_3_4_5 are exchanged data.watt_hours_charged = buffer_get_float32(message, 10000.0, &ind); //data.tachometer = buffer_get_int32(message, &ind); //data.tachometerAbs = buffer_get_int32(message, &ind); data.fault = message[ind]; + //data.PIDpos = buffer_get_float32(message, 10000.0, &ind); + //data.tempMOS1 = buffer_get_float16(message, 10.0, &ind); + //data.tempMOS2 = buffer_get_float16(message, 10.0, &ind); + //data.tempMOS3 = buffer_get_float16(message, 10.0, &ind); return true; + float tempMotor; + float avgMotorCurrent; + float avgInputCurrent; + float dutyCycleNow; + long rpm; + float inpVoltage; + float ampHours; + float ampHoursCharged; + float watt_hours; + float watt_hours_charged; + long tachometer; + long tachometerAbs; + uint8_t fault; + float throttlePPM; + case COMM_GET_DECODED_PPM: data.throttlePPM = (float)(buffer_get_int32(message, &ind) / 10000.0); diff --git a/src/VescUart.h b/src/VescUart.h index b22ffc2..3998990 100644 --- a/src/VescUart.h +++ b/src/VescUart.h @@ -10,9 +10,12 @@ class VescUart { /** Struct to store the telemetry data returned by the VESC */ struct dataPackage { + float tempFET; float tempMotor; float avgMotorCurrent; float avgInputCurrent; + float avgIdCurrent; + float avgIqCurrent; float dutyCycleNow; long rpm; float inpVoltage; @@ -24,6 +27,10 @@ class VescUart long tachometerAbs; uint8_t fault; float throttlePPM; + float PIDpos; + float tempMOS1; + float tempMOS2; + float tempMOS3; }; struct FWversionPackage { From 129d385a41495b8df9af662b29471c3b4c14f27f Mon Sep 17 00:00:00 2001 From: Peemouse Date: Wed, 4 Sep 2019 09:43:46 +0200 Subject: [PATCH 5/7] Add DieBieMS communication Added : SoC, cells number and cells voltages values pulled from DieBieMS over CANbus --- src/VescUart.cpp | 208 ++++++++++++++++++++++++++++++++--------------- src/VescUart.h | 62 ++++++++++++-- src/datatypes.h | 43 ++++++++++ 3 files changed, 240 insertions(+), 73 deletions(-) diff --git a/src/VescUart.cpp b/src/VescUart.cpp index ca47166..cb7b337 100644 --- a/src/VescUart.cpp +++ b/src/VescUart.cpp @@ -176,74 +176,106 @@ int VescUart::packSendPayload(uint8_t * payload, int lenPay) { } -bool VescUart::processReadPacket(uint8_t * message) { +bool VescUart::processReadPacket(bool deviceType, uint8_t * message) { COMM_PACKET_ID packetId; + COMM_PACKET_ID_DIEBIEMS packetIdDieBieMS; + int32_t ind = 0; - packetId = (COMM_PACKET_ID)message[0]; - message++; // Removes the packetId from the actual message (payload) - - switch (packetId){ - case COMM_FW_VERSION: // Structure defined here: https://github.com/vedderb/bldc/blob/43c3bbaf91f5052a35b75c2ff17b5fe99fad94d1/commands.c#L164 - - fw_version.major = message[ind++]; - fw_version.minor = message[ind++]; - return true; - - case COMM_GET_VALUES_SETUP_SELECTIVE: // Structure defined here: https://github.com/vedderb/bldc/blob/43c3bbaf91f5052a35b75c2ff17b5fe99fad94d1/commands.c#L164 - - ind = 4; // Skip the mask - //data.tempFET = buffer_get_float16(message, 10.0, &ind); - data.tempMotor = buffer_get_float16(message, 10.0, &ind); - data.avgMotorCurrent = buffer_get_float32(message, 100.0, &ind); - data.avgInputCurrent = buffer_get_float32(message, 100.0, &ind); - //data.avgIdCurrent = buffer_get_float32(message, 100.0, &ind); - //data.avgIqCurrent = buffer_get_float32(message, 100.0, &ind); - //data.dutyCycleNow = buffer_get_float16(message, 1000.0, &ind); - data.rpm = buffer_get_int32(message, &ind); - data.inpVoltage = buffer_get_float16(message, 10.0, &ind); - // data.ampHours = buffer_get_float32(message, 100.0, &ind); //sum of all VESC if CAN Bus messages 1_2_3_4_5 are exchanged - // data.ampHoursCharged = buffer_get_float32(message, 100.0, &ind); //sum of all VESC if CAN Bus messages 1_2_3_4_5 are exchanged - data.watt_hours = buffer_get_float32(message, 10000.0, &ind); //sum of all VESC if CAN Bus messages 1_2_3_4_5 are exchanged - data.watt_hours_charged = buffer_get_float32(message, 10000.0, &ind); - //data.tachometer = buffer_get_int32(message, &ind); - //data.tachometerAbs = buffer_get_int32(message, &ind); - data.fault = message[ind]; - //data.PIDpos = buffer_get_float32(message, 10000.0, &ind); - //data.tempMOS1 = buffer_get_float16(message, 10.0, &ind); - //data.tempMOS2 = buffer_get_float16(message, 10.0, &ind); - //data.tempMOS3 = buffer_get_float16(message, 10.0, &ind); - return true; - - float tempMotor; - float avgMotorCurrent; - float avgInputCurrent; - float dutyCycleNow; - long rpm; - float inpVoltage; - float ampHours; - float ampHoursCharged; - float watt_hours; - float watt_hours_charged; - long tachometer; - long tachometerAbs; - uint8_t fault; - float throttlePPM; - - case COMM_GET_DECODED_PPM: - - data.throttlePPM = (float)(buffer_get_int32(message, &ind) / 10000.0); - //data.rawValuePPM = buffer_get_float32(message, 100.0, &ind); - return true; - break; - - default: - return false; - break; + if (!deviceType) { //device if VESC type + packetId = (COMM_PACKET_ID)message[0]; + message++; // Removes the packetId from the actual message (payload) + + switch (packetId){ + case COMM_FW_VERSION: // Structure defined here: https://github.com/vedderb/bldc/blob/43c3bbaf91f5052a35b75c2ff17b5fe99fad94d1/commands.c#L164 + + fw_version.major = message[ind++]; + fw_version.minor = message[ind++]; + return true; + + case COMM_GET_VALUES_SETUP_SELECTIVE: // Structure defined here: https://github.com/vedderb/bldc/blob/43c3bbaf91f5052a35b75c2ff17b5fe99fad94d1/commands.c#L164 + + ind = 4; // Skip the mask + data.tempMotor = buffer_get_float16(message, 10.0, &ind); + data.avgMotorCurrent = buffer_get_float32(message, 100.0, &ind); + data.avgInputCurrent = buffer_get_float32(message, 100.0, &ind); + //ind += 8; // Skip the next 8 bytes + //data.dutyCycleNow = buffer_get_float16(message, 1000.0, &ind); + data.rpm = buffer_get_int32(message, &ind); + data.inpVoltage = buffer_get_float16(message, 10.0, &ind); + data.watt_hours = buffer_get_float32(message, 10000.0, &ind); + data.watt_hours_charged = buffer_get_float32(message, 10000.0, &ind); + //ind += 8; // Skip the next 8 bytes + //data.tachometer = buffer_get_int32(message, &ind); + //data.tachometerAbs = buffer_get_int32(message, &ind); + data.fault = message[ind]; + return true; + + case COMM_GET_DECODED_PPM: + + data.throttlePPM = (float)(buffer_get_int32(message, &ind) / 10000.0); + //data.rawValuePPM = buffer_get_float32(message, 100.0, &ind); + return true; + break; + + default: + return false; + break; + } + } + else { //device is DieBieMS + packetIdDieBieMS = (COMM_PACKET_ID_DIEBIEMS)message[0]; + message++; // Removes the packetId from the actual message (payload) + + switch (packetIdDieBieMS){ + + case DBMS_COMM_GET_VALUES: // Structure defined here: https://github.com/DieBieEngineering/DieBieMS-Firmware/blob/master/Modules/Src/modCommands.c + + ind = 8; // Skip the first 2 float32 (pack voltage and current) + // DieBieMSdata.packVoltage = buffer_get_float32(message, 1000.0, &ind); + // DieBieMSdata.packCurrent = buffer_get_float32(message, 1000.0, &ind); + DieBieMSdata.soc = message[ind]; + // DieBieMSdata.cellVoltageHigh = buffer_get_float32(message, 1000.0, &ind); + // DieBieMSdata.cellVoltageAverage = buffer_get_float32(message, 1000.0, &ind); + // DieBieMSdata.cellVoltageLow = buffer_get_float32(message, 1000.0, &ind); + // DieBieMSdata.cellVoltageMisMatch = buffer_get_float32(message, 1000.0, &ind); + // DieBieMSdata.loCurrentLoadVoltage = buffer_get_float16(message, 100.0, &ind); + // DieBieMSdata.loCurrentLoadCurrent = buffer_get_float16(message, 100.0, &ind); + // DieBieMSdata.hiCurrentLoadVoltage = buffer_get_float16(message, 100.0, &ind); + // DieBieMSdata.hiCurrentLoadCurrent = buffer_get_float16(message, 100.0, &ind); + // DieBieMSdata.auxVoltage = buffer_get_float16(message, 100.0, &ind); + // DieBieMSdata.auxCurrent = buffer_get_float16(message, 100.0, &ind); + // DieBieMSdata.tempBatteryHigh = buffer_get_float16(message, 10.0, &ind); + // DieBieMSdata.tempBatteryAverage = buffer_get_float16(message, 10.0, &ind); + // DieBieMSdata.tempBMSHigh = buffer_get_float16(message, 10.0, &ind); + // DieBieMSdata.tempBMSAverage = buffer_get_float16(message, 10.0, &ind); + // DieBieMSdata.operationalState = message[ind]; + // DieBieMSdata.chargeBalanceActive = message[ind++]; + // DieBieMSdata.faultState = message[ind++]; + + return true; + break; + + case DBMS_COMM_GET_BMS_CELLS: // Structure defined here: https://github.com/DieBieEngineering/DieBieMS-Firmware/blob/master/Modules/Src/modCommands.c + + DieBieMScells.noOfCells = message[ind++]; + + for (uint8_t i=0; i<12;i++){ + DieBieMScells.cellsVoltage[i] = buffer_get_float16(message, 1000.0, &ind); + } + + return true; + break; + + default: + return false; + break; + } } } + bool VescUart::getVescValues(void) { uint8_t command[5]; command[0] = { COMM_GET_VALUES_SETUP_SELECTIVE }; @@ -260,7 +292,7 @@ bool VescUart::getVescValues(void) { int lenPayload = receiveUartMessage(payload); if (lenPayload > 0 && lenPayload < 55) { - bool read = processReadPacket(payload); //returns true if sucessful + bool read = processReadPacket(false, payload); //returns true if sucessful return read; } else @@ -281,7 +313,7 @@ bool VescUart::getLocalVescPPM(void) { int lenPayload = receiveUartMessage(payload); if (lenPayload > 0) { //&& lenPayload < 55 - bool read = processReadPacket(payload); //returns true if sucessful + bool read = processReadPacket(false, payload); //returns true if sucessful return read; } else @@ -305,7 +337,7 @@ bool VescUart::getMasterVescPPM(uint8_t id) { int lenPayload = receiveUartMessage(payload); if (lenPayload > 0) { //&& lenPayload < 55 - bool read = processReadPacket(payload); //returns true if sucessful + bool read = processReadPacket(false, payload); //returns true if sucessful return read; } else @@ -325,7 +357,53 @@ bool VescUart::getFWversion(void){ int lenPayload = receiveUartMessage(payload); if (lenPayload > 0) { //&& lenPayload < 55 - bool read = processReadPacket(payload); //returns true if sucessful + bool read = processReadPacket(false, payload); //returns true if sucessful + return read; + } + else + { + return false; + } +} + +bool VescUart::getDieBieMSValues(uint8_t id) { + uint8_t command[3]; + command[0] = { COMM_FORWARD_CAN }; //VESC command + command[1] = id; + command[2] = { DBMS_COMM_GET_VALUES }; //DieBieMS command + + uint8_t payload[256]; + + packSendPayload(command, 3); + // delay(1); //needed, otherwise data is not read + + int lenPayload = receiveUartMessage(payload); + + if (lenPayload > 0) { //&& lenPayload < 55 + bool read = processReadPacket(true, payload); //returns true if sucessful + return read; + } + else + { + return false; + } +} + +bool VescUart::getDieBieMSCellsVoltage(uint8_t id) { + uint8_t command[3]; + command[0] = { COMM_FORWARD_CAN }; //VESC command + command[1] = id; + command[2] = { DBMS_COMM_GET_BMS_CELLS }; //DieBieMS command + + uint8_t payload[256]; + + packSendPayload(command, 3); + // delay(1); //needed, otherwise data is not read + + int lenPayload = receiveUartMessage(payload); + + if (lenPayload > 0) { //&& lenPayload < 55 + bool read = processReadPacket(true, payload); //returns true if sucessful return read; } else diff --git a/src/VescUart.h b/src/VescUart.h index 3998990..bd22c4d 100644 --- a/src/VescUart.h +++ b/src/VescUart.h @@ -10,12 +10,9 @@ class VescUart { /** Struct to store the telemetry data returned by the VESC */ struct dataPackage { - float tempFET; float tempMotor; float avgMotorCurrent; float avgInputCurrent; - float avgIdCurrent; - float avgIqCurrent; float dutyCycleNow; long rpm; float inpVoltage; @@ -27,10 +24,35 @@ class VescUart long tachometerAbs; uint8_t fault; float throttlePPM; - float PIDpos; - float tempMOS1; - float tempMOS2; - float tempMOS3; + }; + + /** Struct to store the telemetry data returned by the DieBieMS */ + struct DieBieMSdataPackage { + float packVoltage; + float packCurrent; + uint8_t soc; + float cellVoltageHigh; + float cellVoltageAverage; + float cellVoltageLow; + float cellVoltageMisMatch; + float loCurrentLoadVoltage; + float loCurrentLoadCurrent; + float hiCurrentLoadVoltage; + float hiCurrentLoadCurrent; + float auxVoltage; + float auxCurrent; + float tempBatteryHigh; + float tempBatteryAverage; + float tempBMSHigh; + float tempBMSAverage; + uint8_t operationalState; + uint8_t chargeBalanceActive; + uint8_t faultState; + }; + + struct DieBieMScellsPackage { + uint8_t noOfCells; + float cellsVoltage[11]; }; struct FWversionPackage { @@ -62,6 +84,13 @@ class VescUart /** Variabel to hold nunchuck values */ nunchuckPackage nunchuck; + /** Variabel to hold measurements returned from DieBieMS */ + DieBieMSdataPackage DieBieMSdata; + + /** Variabel to hold cells voltages returned from DieBieMS */ + DieBieMScellsPackage DieBieMScells; + + /** * @brief Set the serial port for uart communication * @param port - Reference to Serial port (pointer) @@ -136,6 +165,20 @@ class VescUart */ bool getFWversion(void); + /** + * @brief Sends a command to DieBieMS over CAN and stores the returned data + * @param id - CAN ID of DieBieMS (default is 10) + * @return True if successfull otherwise false + */ + bool getDieBieMSValues(uint8_t id); + + /** + * @brief Sends a command to DieBieMS over CAN and stores the returned cells voltage + * @param id - CAN ID of DieBieMS (default is 10) + * @return True if successfull otherwise false + */ + bool getDieBieMSCellsVoltage(uint8_t id); + private: /** Variabel to hold the reference to the Serial object to use for UART */ @@ -175,10 +218,11 @@ class VescUart /** * @brief Extracts the data from the received payload * + * @param deviceType - 0 if VESC, 1 if DieBieMS * @param message - The payload to extract data from * @return True if the process was a success */ - bool processReadPacket(uint8_t * message); + bool processReadPacket(bool deviceType, uint8_t * message); /** * @brief Help Function to print uint8_t array over Serial for Debug @@ -188,6 +232,8 @@ class VescUart */ void serialPrint(uint8_t * data, int len); + + }; #endif diff --git a/src/datatypes.h b/src/datatypes.h index 43bdf2f..526d69a 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -527,6 +527,49 @@ typedef enum { COMM_APP_DISABLE_OUTPUT } COMM_PACKET_ID; +typedef enum { + DBMS_COMM_FW_VERSION = 0, + DBMS_COMM_JUMP_TO_BOOTLOADER, + DBMS_COMM_ERASE_NEW_APP, + DBMS_COMM_WRITE_NEW_APP_DATA, + DBMS_COMM_GET_VALUES, + DBMS_COMM_SET_DUTY, + DBMS_COMM_SET_CURRENT, + DBMS_COMM_SET_CURRENT_BRAKE, + DBMS_COMM_SET_RPM, + DBMS_COMM_SET_POS, + DBMS_COMM_SET_HANDBRAKE, + DBMS_COMM_SET_DETECT, + DBMS_COMM_SET_SERVO_POS, + DBMS_COMM_SET_MCCONF, + DBMS_COMM_GET_MCCONF, + DBMS_COMM_GET_MCCONF_DEFAULT, + DBMS_COMM_SET_APPCONF, + DBMS_COMM_GET_APPCONF, + DBMS_COMM_GET_APPCONF_DEFAULT, + DBMS_COMM_SAMPLE_PRINT, + DBMS_COMM_TERMINAL_CMD, + DBMS_COMM_PRINT, + DBMS_COMM_ROTOR_POSITION, + DBMS_COMM_EXPERIMENT_SAMPLE, + DBMS_COMM_DETECT_MOTOR_PARAM, + DBMS_COMM_DETECT_MOTOR_R_L, + DBMS_COMM_DETECT_MOTOR_FLUX_LINKAGE, + DBMS_COMM_DETECT_ENCODER, + DBMS_COMM_DETECT_HALL_FOC, + DBMS_COMM_REBOOT, + DBMS_COMM_ALIVE, + DBMS_COMM_GET_DECODED_PPM, + DBMS_COMM_GET_DECODED_ADC, + DBMS_COMM_GET_DECODED_CHUK, + DBMS_COMM_FORWARD_CAN, + DBMS_COMM_SET_CHUCK_DATA, + DBMS_COMM_CUSTOM_APP_DATA, + DBMS_COMM_NRF_START_PAIRING, + DBMS_COMM_STORE_BMS_CONF = 50, + DBMS_COMM_GET_BMS_CELLS +} COMM_PACKET_ID_DIEBIEMS; + // CAN commands typedef enum { CAN_PACKET_SET_DUTY = 0, From 5b67819f038ea615dd07f71130da5b4952a86901 Mon Sep 17 00:00:00 2001 From: Peemouse Date: Tue, 24 Sep 2019 15:15:23 +0200 Subject: [PATCH 6/7] Add Trampa WAND Remote support Added : - getLocalVescNun() : retrieve the local throttle percentage of the Nunchuk app (used by the Wand) - getMasterVescNun(uint8_t canID) : retrieve the throttle percentage of the Nunchuk app from a VESC on CANbus - Examples sketches for using it --- .../getDieBieMSCellsVoltage.ino | 51 ++++++++++++++++ .../getDieBieMSValues/getDieBieMSValues.ino | 44 ++++++++++++++ examples/getLocalVescNun/getLocalVescNun.ino | 42 ++++++++++++++ examples/getLocalVescPPM/getLocalVescPPM.ino | 6 +- .../getMasterVescNun/getMasterVescNun.ino | 43 ++++++++++++++ .../getMasterVescPPM/getMasterVescPPM.ino | 2 +- keywords.txt | 9 ++- library.properties | 2 +- src/VescUart.cpp | 58 +++++++++++++++++-- src/VescUart.h | 18 +++++- 10 files changed, 263 insertions(+), 12 deletions(-) create mode 100644 examples/getDieBieMSCellsVoltage/getDieBieMSCellsVoltage.ino create mode 100644 examples/getDieBieMSValues/getDieBieMSValues.ino create mode 100644 examples/getLocalVescNun/getLocalVescNun.ino create mode 100644 examples/getMasterVescNun/getMasterVescNun.ino diff --git a/examples/getDieBieMSCellsVoltage/getDieBieMSCellsVoltage.ino b/examples/getDieBieMSCellsVoltage/getDieBieMSCellsVoltage.ino new file mode 100644 index 0000000..26c7af8 --- /dev/null +++ b/examples/getDieBieMSCellsVoltage/getDieBieMSCellsVoltage.ino @@ -0,0 +1,51 @@ +/* + Name: getDieBieMSCellsVoltage.ino + Created: 04-08-2019 + Author: Peemouse + Description: This example is made using a Arduino Micro (Atmega32u4) that has a HardwareSerial port (Serial1) seperated from the Serial port. + A Arduino Nano or Uno that only has one Serial port will not be able to display the data returned. +*/ + +#include + +/** Initiate VescUart class */ +VescUart UART; + +char DieBieMS_CANID = 10; //CAN ID of DieBieMS. Default is 10. + +void setup() { + + /** Setup Serial port to display data */ + Serial.begin(115200); + + /** Setup UART port (Serial1 on Atmega32u4) */ + Serial1.begin(115200); + + while (!Serial) {;} + + /** Define which ports to use as UART */ + UART.setSerialPort(&Serial1); +} + +void loop() { + + /** Call the function getDieBieMSCellsVoltage() to acquire data from DieBieMS */ + if ( UART.getDieBieMSCellsVoltage(DieBieMS_CANID) ) { + + Serial.print("Num of cells "); + Serial.println(UART.DieBieMScells.noOfCells); + + for (uint8_t i=0;i<=UART.DieBieMScells.noOfCells;i++){ + Serial.print("cell #"); + Serial.print(i); + Serial.print(" "); + Serial.print(UART.DieBieMScells.cellsVoltage[i]); + } + } + else + { + Serial.println("Failed to get DieBieMS cells voltage!"); + } + + delay(200); +} diff --git a/examples/getDieBieMSValues/getDieBieMSValues.ino b/examples/getDieBieMSValues/getDieBieMSValues.ino new file mode 100644 index 0000000..bebf5aa --- /dev/null +++ b/examples/getDieBieMSValues/getDieBieMSValues.ino @@ -0,0 +1,44 @@ +/* + Name: getDieBieMSValues.ino + Created: 04-08-2019 + Author: Peemouse + Description: This example is made using a Arduino Micro (Atmega32u4) that has a HardwareSerial port (Serial1) seperated from the Serial port. + A Arduino Nano or Uno that only has one Serial port will not be able to display the data returned. +*/ + +#include + +/** Initiate VescUart class */ +VescUart UART; + +char DieBieMS_CANID = 10; //CAN ID of DieBieMS. Default is 10. + +void setup() { + + /** Setup Serial port to display data */ + Serial.begin(115200); + + /** Setup UART port (Serial1 on Atmega32u4) */ + Serial1.begin(115200); + + while (!Serial) {;} + + /** Define which ports to use as UART */ + UART.setSerialPort(&Serial1); +} + +void loop() { + + /** Call the function getDieBieMSValues() to acquire data from DieBieMS */ + if ( UART.getDieBieMSValues(DieBieMS_CANID) ) { + + Serial.println(UART.DieBieMSdata.soc); + + } + else + { + Serial.println("Failed to get DieBieMS data!"); + } + + delay(50); +} diff --git a/examples/getLocalVescNun/getLocalVescNun.ino b/examples/getLocalVescNun/getLocalVescNun.ino new file mode 100644 index 0000000..41b4e71 --- /dev/null +++ b/examples/getLocalVescNun/getLocalVescNun.ino @@ -0,0 +1,42 @@ +/* + Name: getVescValues.ino + Created: 19-08-2018 + Author: SolidGeek + Description: This example is made using a Arduino Micro (Atmega32u4) that has a HardwareSerial port (Serial1) seperated from the Serial port. + A Arduino Nano or Uno that only has one Serial port will not be able to display the data returned. +*/ + +#include + +/** Initiate VescUart class */ +VescUart UART; + +void setup() { + + /** Setup Serial port to display data */ + Serial.begin(115200); + + /** Setup UART port (Serial1 on Atmega32u4) */ + Serial1.begin(115200); + + while (!Serial) {;} + + /** Define which ports to use as UART */ + UART.setSerialPort(&Serial1); +} + +void loop() { + + /** Call the function getVescValues() to acquire data from VESC */ + if ( UART.getLocalVescNun() ) { + + Serial.println(UART.data.throttle); + + } + else + { + Serial.println("Failed to get data!"); + } + + delay(100); +} diff --git a/examples/getLocalVescPPM/getLocalVescPPM.ino b/examples/getLocalVescPPM/getLocalVescPPM.ino index 4d19162..95fa42a 100644 --- a/examples/getLocalVescPPM/getLocalVescPPM.ino +++ b/examples/getLocalVescPPM/getLocalVescPPM.ino @@ -14,10 +14,10 @@ VescUart UART; void setup() { /** Setup Serial port to display data */ - Serial.begin(9600); + Serial.begin(115200); /** Setup UART port (Serial1 on Atmega32u4) */ - Serial1.begin(19200); + Serial1.begin(115200); while (!Serial) {;} @@ -30,7 +30,7 @@ void loop() { /** Call the function getVescValues() to acquire data from VESC */ if ( UART.getLocalVescPPM() ) { - Serial.println(UART.data.throttlePPM); + Serial.println(UART.data.throttle); } else diff --git a/examples/getMasterVescNun/getMasterVescNun.ino b/examples/getMasterVescNun/getMasterVescNun.ino new file mode 100644 index 0000000..d1b1672 --- /dev/null +++ b/examples/getMasterVescNun/getMasterVescNun.ino @@ -0,0 +1,43 @@ +/* + Name: getVescValues.ino + Created: 19-08-2018 + Author: SolidGeek + Description: This example is made using a Arduino Micro (Atmega32u4) that has a HardwareSerial port (Serial1) seperated from the Serial port. + A Arduino Nano or Uno that only has one Serial port will not be able to display the data returned. +*/ + +#include + +/** Initiate VescUart class */ +VescUart UART; +uint8_t masterVescCANID = 0; + +void setup() { + + /** Setup Serial port to display data */ + Serial.begin(115200); + + /** Setup UART port (Serial1 on Atmega32u4) */ + Serial1.begin(115200); + + while (!Serial) {;} + + /** Define which ports to use as UART */ + UART.setSerialPort(&Serial1); +} + +void loop() { + + /** Call the function getVescValues() to acquire data from VESC */ + if ( UART.getMasterVescNun(masterVescCANID) ) { + + Serial.println(UART.data.throttle); + + } + else + { + Serial.println("Failed to get data!"); + } + + delay(100); +} diff --git a/examples/getMasterVescPPM/getMasterVescPPM.ino b/examples/getMasterVescPPM/getMasterVescPPM.ino index 8463471..584261d 100644 --- a/examples/getMasterVescPPM/getMasterVescPPM.ino +++ b/examples/getMasterVescPPM/getMasterVescPPM.ino @@ -31,7 +31,7 @@ void loop() { /** Call the function getVescValues() to acquire data from VESC */ if ( UART.getMasterVescPPM(masterVescCANID) ) { - Serial.println(UART.data.throttlePPM); + Serial.println(UART.data.throttle); } else diff --git a/keywords.txt b/keywords.txt index 5ec1bcb..acc1c6b 100644 --- a/keywords.txt +++ b/keywords.txt @@ -20,4 +20,11 @@ printVescValues KEYWORD2 setCurrent KEYWORD2 setBrakeCurrent KEYWORD2 setRPM KEYWORD2 -setDuty KEYWORD2 \ No newline at end of file +setDuty KEYWORD2 +getLocalVescPPM KEYWORD2 +getMasterVescPPM KEYWORD2 +getLocalVescNun KEYWORD2 +getMasterVescNun KEYWORD2 +getFWversion KEYWORD2 +getDieBieMSValues KEYWORD2 +getDieBieMSCellsVoltage KEYWORD2 diff --git a/library.properties b/library.properties index 33b9a19..f02e7fb 100644 --- a/library.properties +++ b/library.properties @@ -1,7 +1,7 @@ name=VescUart version=1.0.0 author=SolidGeek -maintainer=SolidGeek +maintainer=Pimousse sentence=Library offering UART communication for VESC paragraph=VESC UART library category=Device Control diff --git a/src/VescUart.cpp b/src/VescUart.cpp index cb7b337..1b63bb0 100644 --- a/src/VescUart.cpp +++ b/src/VescUart.cpp @@ -214,11 +214,18 @@ bool VescUart::processReadPacket(bool deviceType, uint8_t * message) { case COMM_GET_DECODED_PPM: - data.throttlePPM = (float)(buffer_get_int32(message, &ind) / 10000.0); + data.throttle = (float)(buffer_get_int32(message, &ind) / 10000.0); //data.rawValuePPM = buffer_get_float32(message, 100.0, &ind); return true; break; + case COMM_GET_DECODED_CHUK: + + data.throttle = (float)(buffer_get_int32(message, &ind) / 10000.0); + + return true; + break; + default: return false; break; @@ -235,7 +242,8 @@ bool VescUart::processReadPacket(bool deviceType, uint8_t * message) { ind = 8; // Skip the first 2 float32 (pack voltage and current) // DieBieMSdata.packVoltage = buffer_get_float32(message, 1000.0, &ind); // DieBieMSdata.packCurrent = buffer_get_float32(message, 1000.0, &ind); - DieBieMSdata.soc = message[ind]; + DieBieMSdata.soc = message[ind++]; + ind+=36; // DieBieMSdata.cellVoltageHigh = buffer_get_float32(message, 1000.0, &ind); // DieBieMSdata.cellVoltageAverage = buffer_get_float32(message, 1000.0, &ind); // DieBieMSdata.cellVoltageLow = buffer_get_float32(message, 1000.0, &ind); @@ -250,7 +258,7 @@ bool VescUart::processReadPacket(bool deviceType, uint8_t * message) { // DieBieMSdata.tempBatteryAverage = buffer_get_float16(message, 10.0, &ind); // DieBieMSdata.tempBMSHigh = buffer_get_float16(message, 10.0, &ind); // DieBieMSdata.tempBMSAverage = buffer_get_float16(message, 10.0, &ind); - // DieBieMSdata.operationalState = message[ind]; + DieBieMSdata.operationalState = message[ind++]; // DieBieMSdata.chargeBalanceActive = message[ind++]; // DieBieMSdata.faultState = message[ind++]; @@ -304,7 +312,6 @@ bool VescUart::getVescValues(void) { bool VescUart::getLocalVescPPM(void) { uint8_t command[1] = { COMM_GET_DECODED_PPM }; - uint8_t payload[256]; packSendPayload(command, 1); @@ -346,6 +353,49 @@ bool VescUart::getMasterVescPPM(uint8_t id) { } } +bool VescUart::getLocalVescNun(void){ + uint8_t command[1] = { COMM_GET_DECODED_CHUK }; + uint8_t payload[256]; + + packSendPayload(command, 1); + // delay(1); //needed, otherwise data is not read + + int lenPayload = receiveUartMessage(payload); + + if (lenPayload > 0) { //&& lenPayload < 55 + bool read = processReadPacket(false, payload); //returns true if sucessful + return read; + } + else + { + return false; + } +} + + +bool VescUart::getMasterVescNun(uint8_t id){ + uint8_t command[3]; + command[0] = { COMM_FORWARD_CAN }; + command[1] = id; + command[2] = { COMM_GET_DECODED_CHUK }; + + uint8_t payload[256]; + + packSendPayload(command, 3); + // delay(1); //needed, otherwise data is not read + + int lenPayload = receiveUartMessage(payload); + + if (lenPayload > 0) { //&& lenPayload < 55 + bool read = processReadPacket(false, payload); //returns true if sucessful + return read; + } + else + { + return false; + } +} + bool VescUart::getFWversion(void){ uint8_t command[1] = { COMM_FW_VERSION }; diff --git a/src/VescUart.h b/src/VescUart.h index bd22c4d..59e71ef 100644 --- a/src/VescUart.h +++ b/src/VescUart.h @@ -23,7 +23,7 @@ class VescUart long tachometer; long tachometerAbs; uint8_t fault; - float throttlePPM; + float throttle; }; /** Struct to store the telemetry data returned by the DieBieMS */ @@ -158,6 +158,20 @@ class VescUart */ bool getMasterVescPPM(uint8_t id); + /** + * @brief Request PPM values to local VESC + * + * @return True if successfull otherwise false + */ + bool getLocalVescNun(void); + + /** + * @brief Request PPM values to Master VESC over CANbus + * @param id - CAN ID of the master VESC + * @return True if successfull otherwise false + */ + bool getMasterVescNun(uint8_t id); + /** * @brief Request version of VESC Firmware * @@ -171,7 +185,7 @@ class VescUart * @return True if successfull otherwise false */ bool getDieBieMSValues(uint8_t id); - + /** * @brief Sends a command to DieBieMS over CAN and stores the returned cells voltage * @param id - CAN ID of DieBieMS (default is 10) From c4527c2f786d9fdd3800efe186035bff317562b8 Mon Sep 17 00:00:00 2001 From: Peemouse Date: Fri, 24 Apr 2020 18:03:18 +0200 Subject: [PATCH 7/7] Add new commands to match the VESC ones --- src/VescUart.cpp | 154 ++++++++++++++++++++++++++++++++++++++--------- src/VescUart.h | 25 +++++++- 2 files changed, 151 insertions(+), 28 deletions(-) diff --git a/src/VescUart.cpp b/src/VescUart.cpp index 1b63bb0..7c0cda4 100644 --- a/src/VescUart.cpp +++ b/src/VescUart.cpp @@ -137,7 +137,6 @@ bool VescUart::unpackPayload(uint8_t * message, int lenMes, uint8_t * payload) { } } - int VescUart::packSendPayload(uint8_t * payload, int lenPay) { uint16_t crcPayload = crc16(payload, lenPay); @@ -175,7 +174,6 @@ int VescUart::packSendPayload(uint8_t * payload, int lenPay) { return count; } - bool VescUart::processReadPacket(bool deviceType, uint8_t * message) { COMM_PACKET_ID packetId; @@ -194,23 +192,63 @@ bool VescUart::processReadPacket(bool deviceType, uint8_t * message) { fw_version.minor = message[ind++]; return true; - case COMM_GET_VALUES_SETUP_SELECTIVE: // Structure defined here: https://github.com/vedderb/bldc/blob/43c3bbaf91f5052a35b75c2ff17b5fe99fad94d1/commands.c#L164 - - ind = 4; // Skip the mask - data.tempMotor = buffer_get_float16(message, 10.0, &ind); - data.avgMotorCurrent = buffer_get_float32(message, 100.0, &ind); - data.avgInputCurrent = buffer_get_float32(message, 100.0, &ind); - //ind += 8; // Skip the next 8 bytes - //data.dutyCycleNow = buffer_get_float16(message, 1000.0, &ind); - data.rpm = buffer_get_int32(message, &ind); - data.inpVoltage = buffer_get_float16(message, 10.0, &ind); - data.watt_hours = buffer_get_float32(message, 10000.0, &ind); - data.watt_hours_charged = buffer_get_float32(message, 10000.0, &ind); - //ind += 8; // Skip the next 8 bytes - //data.tachometer = buffer_get_int32(message, &ind); - //data.tachometerAbs = buffer_get_int32(message, &ind); - data.fault = message[ind]; + case COMM_GET_VALUES: + case COMM_GET_VALUES_SELECTIVE: { // Structure defined here: https://github.com/vedderb/bldc/blob/43c3bbaf91f5052a35b75c2ff17b5fe99fad94d1/commands.c#L164 + uint32_t mask = 0xFFFFFFFF; + + if (packetId == COMM_GET_VALUES_SELECTIVE){ + mask = buffer_get_uint32(message, &ind); + } + + if (mask & ((uint32_t)1 << 0)) {data.tempFET = buffer_get_float16(message, 10.0, &ind);} + if (mask & ((uint32_t)1 << 1)) {data.tempMotor = buffer_get_float16(message, 10.0, &ind);} + if (mask & ((uint32_t)1 << 2)) {data.avgMotorCurrent = buffer_get_float32(message, 100.0, &ind);} + if (mask & ((uint32_t)1 << 3)) {data.avgInputCurrent = buffer_get_float32(message, 100.0, &ind);} + if (mask & ((uint32_t)1 << 4)) {data.avgIdCurent = buffer_get_float32(message, 100.0, &ind);} + if (mask & ((uint32_t)1 << 5)) {data.avgIqCurent = buffer_get_float32(message, 100.0, &ind);} + if (mask & ((uint32_t)1 << 6)) {data.dutyCycleNow = buffer_get_float16(message, 1000.0, &ind);} + if (mask & ((uint32_t)1 << 7)) {data.rpm = buffer_get_int32(message, &ind);} + if (mask & ((uint32_t)1 << 8)) {data.inpVoltage = buffer_get_float16(message, 10.0, &ind);} + if (mask & ((uint32_t)1 << 9)) {data.ampHours = buffer_get_float32(message, 10000.0, &ind);} + if (mask & ((uint32_t)1 << 10)) {data.ampHoursCharged = buffer_get_float32(message, 10000.0, &ind);} + if (mask & ((uint32_t)1 << 11)) {data.watt_hours = buffer_get_float32(message, 10000.0, &ind);} + if (mask & ((uint32_t)1 << 12)) {data.watt_hours_charged = buffer_get_float32(message, 10000.0, &ind);} + if (mask & ((uint32_t)1 << 13)) {data.tachometer = buffer_get_int32(message, &ind);} + if (mask & ((uint32_t)1 << 14)) {data.tachometerAbs = buffer_get_int32(message, &ind);} + if (mask & ((uint32_t)1 << 15)) {data.fault = message[ind]; } + //Others values are ignored. You can add them here accordingly to commands.c in VESC Firmware. Please add those variables in "struct dataPackage" in VescUart.h file. + return true; + } + + case COMM_GET_VALUES_SETUP_SELECTIVE: { // Structure defined here: https://github.com/vedderb/bldc/blob/43c3bbaf91f5052a35b75c2ff17b5fe99fad94d1/commands.c#L164 + uint32_t mask = 0; + mask += ind++ << 24; + mask += ind++ << 16; + mask += ind++ << 8; + mask += ind++; + + if (mask & ((uint32_t)1 << 0)) {data.tempFET = buffer_get_float16(message, 10.0, &ind);} + if (mask & ((uint32_t)1 << 1)) {data.tempMotor = buffer_get_float16(message, 10.0, &ind);} + if (mask & ((uint32_t)1 << 2)) {data.avgMotorCurrent = buffer_get_float32(message, 100.0, &ind);} + if (mask & ((uint32_t)1 << 3)) {data.avgInputCurrent = buffer_get_float32(message, 100.0, &ind);} + if (mask & ((uint32_t)1 << 4)) {data.dutyCycleNow = buffer_get_float16(message, 1000.0, &ind);} + if (mask & ((uint32_t)1 << 5)) {data.rpm = buffer_get_int32(message, &ind);} + if (mask & ((uint32_t)1 << 6)) { /* speed */}; + if (mask & ((uint32_t)1 << 7)) {data.inpVoltage = buffer_get_float16(message, 10.0, &ind);} + if (mask & ((uint32_t)1 << 8)) { /* batt level */} + if (mask & ((uint32_t)1 << 9)) {data.ampHours = buffer_get_float32(message, 10000.0, &ind);} + if (mask & ((uint32_t)1 << 10)) {data.ampHoursCharged = buffer_get_float32(message, 10000.0, &ind);} + if (mask & ((uint32_t)1 << 11)) {data.watt_hours = buffer_get_float32(message, 10000.0, &ind);} + if (mask & ((uint32_t)1 << 12)) {data.watt_hours_charged = buffer_get_float32(message, 10000.0, &ind);} + if (mask & ((uint32_t)1 << 13)) {/* distance */} + if (mask & ((uint32_t)1 << 14)) {/* distance absolute */} + if (mask & ((uint32_t)1 << 15)) {/* PID pos */} + if (mask & ((uint32_t)1 << 16)) {data.fault = message[ind]; } + //Others values are ignored. You can add them here accordingly to commands.c in VESC Firmware. Please add those variables in "struct dataPackage" in VescUart.h file. + + return true; + } case COMM_GET_DECODED_PPM: @@ -239,11 +277,9 @@ bool VescUart::processReadPacket(bool deviceType, uint8_t * message) { case DBMS_COMM_GET_VALUES: // Structure defined here: https://github.com/DieBieEngineering/DieBieMS-Firmware/blob/master/Modules/Src/modCommands.c - ind = 8; // Skip the first 2 float32 (pack voltage and current) + ind = 45; // DieBieMSdata.packVoltage = buffer_get_float32(message, 1000.0, &ind); // DieBieMSdata.packCurrent = buffer_get_float32(message, 1000.0, &ind); - DieBieMSdata.soc = message[ind++]; - ind+=36; // DieBieMSdata.cellVoltageHigh = buffer_get_float32(message, 1000.0, &ind); // DieBieMSdata.cellVoltageAverage = buffer_get_float32(message, 1000.0, &ind); // DieBieMSdata.cellVoltageLow = buffer_get_float32(message, 1000.0, &ind); @@ -283,15 +319,57 @@ bool VescUart::processReadPacket(bool deviceType, uint8_t * message) { } } - bool VescUart::getVescValues(void) { + uint8_t command[1]; + command[0] = { COMM_GET_VALUES }; + uint8_t payload[256]; + + packSendPayload(command, 1); + // delay(1); //needed, otherwise data is not read + + int lenPayload = receiveUartMessage(payload); + + if (lenPayload > 0 && lenPayload < 55) { + bool read = processReadPacket(false, payload); //returns true if sucessful + return read; + } + else + { + return false; + } +} + +bool VescUart::getVescValuesSelective(uint32_t mask) { + uint8_t command[5]; + command[0] = { COMM_GET_VALUES_SELECTIVE }; + command[1] = { mask >> 24 }; //mask MSB + command[2] = { mask >> 16 & 0xFF }; //mask + command[3] = { mask >> 8 & 0xFF }; //mask + command[4] = { mask & 0xFF }; //mask LSB + uint8_t payload[256]; + + packSendPayload(command, 5); + // delay(1); //needed, otherwise data is not read + + int lenPayload = receiveUartMessage(payload); + + if (lenPayload > 0 && lenPayload < 55) { + bool read = processReadPacket(false, payload); //returns true if sucessful + return read; + } + else + { + return false; + } +} + +bool VescUart::getVescValuesSetupSelective(uint32_t mask) { uint8_t command[5]; command[0] = { COMM_GET_VALUES_SETUP_SELECTIVE }; - //values selected : 0x000118AE - command[1] = { 0x00 }; //mask MSB - command[2] = { 0x01 }; //mask - command[3] = { 0x18 }; //mask - command[4] = { 0xAE }; //mask LSB + command[1] = { mask >> 24 }; //mask MSB + command[2] = { mask >> 16 & 0xFF }; //mask + command[3] = { mask >> 8 & 0xFF }; //mask + command[4] = { mask & 0xFF }; //mask LSB uint8_t payload[256]; packSendPayload(command, 5); @@ -462,6 +540,7 @@ bool VescUart::getDieBieMSCellsVoltage(uint8_t id) { } } + void VescUart::setNunchuckValues() { int32_t ind = 0; uint8_t payload[11]; @@ -529,6 +608,27 @@ void VescUart::setDuty(float duty) { packSendPayload(payload, 5); } +void VescUart::setLocalProfile(bool store, bool forward_can, bool ack, bool divide_by_controllers, float current_min_rel, float current_max_rel, float speed_max_reverse, float speed_max, float duty_min, float duty_max, float watt_min, float watt_max) { + int32_t index = 0; + uint8_t payload[38]; + + payload[index++] = COMM_SET_MCCONF_TEMP_SETUP; + payload[index++] ? store : 1, 0; + payload[index++] ? forward_can : 1, 0; + payload[index++] ? ack : 1, 0; + payload[index++] ? divide_by_controllers : 1, 0; + buffer_append_float32(payload, current_min_rel, 1.0, &index); + buffer_append_float32(payload, current_max_rel, 1.0, &index); + buffer_append_float32(payload, speed_max_reverse, 1.0, &index); + buffer_append_float32(payload, speed_max, 1.0, &index); + buffer_append_float32(payload, duty_min, 1.0, &index); + buffer_append_float32(payload, duty_max, 1.0, &index); + buffer_append_float32(payload, watt_min, 1.0, &index); + buffer_append_float32(payload, watt_max, 1.0, &index); + + packSendPayload(payload, 38); +} + void VescUart::serialPrint(uint8_t * data, int len) { if(debugPort != NULL){ for (int i = 0; i <= len; i++) diff --git a/src/VescUart.h b/src/VescUart.h index 59e71ef..86d7fd1 100644 --- a/src/VescUart.h +++ b/src/VescUart.h @@ -10,9 +10,12 @@ class VescUart { /** Struct to store the telemetry data returned by the VESC */ struct dataPackage { + float tempFET; float tempMotor; float avgMotorCurrent; float avgInputCurrent; + float avgIqCurent; + float avgIdCurent; float dutyCycleNow; long rpm; float inpVoltage; @@ -105,11 +108,24 @@ class VescUart /** * @brief Sends a command to VESC and stores the returned data - * * @return True if successfull otherwise false */ bool getVescValues(void); + /** + * @brief Sends a command to VESC and stores the returned data + * @param mask : select which values are sent back by the VESC + * @return True if successfull otherwise false + */ + bool getVescValuesSelective(uint32_t mask); + + /** + * @brief Sends a command to VESC and stores the returned data + * @param mask : select which values are sent back by the VESC + * @return True if successfull otherwise false + */ + bool getVescValuesSetupSelective(uint32_t mask); + /** * @brief Sends values for joystick and buttons to the nunchuck app */ @@ -193,6 +209,13 @@ class VescUart */ bool getDieBieMSCellsVoltage(uint8_t id); + /** + * @brief Set a profile + * @param + + */ + void setLocalProfile(bool store, bool forward_can, bool ack, bool divide_by_controllers, float current_min_rel, float current_max_rel, float speed_max_reverse, float speed_max, float duty_min, float duty_max, float watt_min, float watt_max); + private: /** Variabel to hold the reference to the Serial object to use for UART */