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/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/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 new file mode 100644 index 0000000..95fa42a --- /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(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.getLocalVescPPM() ) { + + Serial.println(UART.data.throttle); + + } + else + { + Serial.println("Failed to get data!"); + } + + delay(100); +} 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 new file mode 100644 index 0000000..584261d --- /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(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.getMasterVescPPM(masterVescCANID) ) { + + Serial.println(UART.data.throttle); + + } + else + { + Serial.println("Failed to get data!"); + } + + delay(100); +} 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 ac45b19..7c0cda4 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,12 +131,12 @@ bool VescUart::unpackPayload(uint8_t * message, int lenMes, uint8_t * payload) { } return true; - }else{ + } + else { return false; } } - int VescUart::packSendPayload(uint8_t * payload, int lenPay) { uint16_t crcPayload = crc16(payload, lenPay); @@ -172,43 +174,309 @@ int VescUart::packSendPayload(uint8_t * payload, int lenPay) { return count; } - -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) + 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: + 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: + + 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: - switch (packetId){ - case COMM_GET_VALUES: // Structure defined here: https://github.com/vedderb/bldc/blob/43c3bbaf91f5052a35b75c2ff17b5fe99fad94d1/commands.c#L164 + data.throttle = (float)(buffer_get_int32(message, &ind) / 10000.0); - ind = 4; // Skip the first 4 bytes - 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.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); - return true; + return true; + break; - 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 = 45; + // DieBieMSdata.packVoltage = buffer_get_float32(message, 1000.0, &ind); + // DieBieMSdata.packCurrent = buffer_get_float32(message, 1000.0, &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); + } - default: - return false; - break; + return true; + break; + + default: + return false; + break; + } } } 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 }; + 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::getLocalVescPPM(void) { + + uint8_t command[1] = { COMM_GET_DECODED_PPM }; + 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; + } +} - uint8_t command[1] = { COMM_GET_VALUES }; +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(false, payload); //returns true if sucessful + return read; + } + else + { + return false; + } +} + +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 }; uint8_t payload[256]; packSendPayload(command, 1); @@ -216,8 +484,31 @@ bool VescUart::getVescValues(void) { int lenPayload = receiveUartMessage(payload); - if (lenPayload > 55) { - bool read = processReadPacket(payload); //returns true if sucessful + if (lenPayload > 0) { //&& lenPayload < 55 + 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 @@ -226,6 +517,30 @@ bool VescUart::getVescValues(void) { } } +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 + { + return false; + } +} + + void VescUart::setNunchuckValues() { int32_t ind = 0; uint8_t payload[11]; @@ -235,7 +550,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; @@ -293,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++) @@ -317,4 +653,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..86d7fd1 100644 --- a/src/VescUart.h +++ b/src/VescUart.h @@ -10,15 +10,57 @@ 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; float ampHours; float ampHoursCharged; + float watt_hours; + float watt_hours_charged; long tachometer; long tachometerAbs; + uint8_t fault; + float throttle; + }; + + /** 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 { + uint8_t major; + uint8_t minor; }; /** Struct to hold the nunchuck values to send over UART */ @@ -37,30 +79,53 @@ class VescUart VescUart(void); /** Variabel to hold measurements returned from VESC */ - dataPackage data; + dataPackage data; + + /** Variable to hold measurements returned from VESC */ + FWversionPackage fw_version; /** Variabel to hold nunchuck values */ - nunchuckPackage nunchuck; + 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) + * @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); /** * @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 */ @@ -95,12 +160,68 @@ class VescUart */ void printVescValues(void); - private: + /** + * @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 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 + * + * @return True if successfull otherwise false + */ + 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); + + /** + * @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 */ 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; @@ -134,10 +255,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 @@ -147,6 +269,8 @@ class VescUart */ void serialPrint(uint8_t * data, int len); + + }; #endif diff --git a/src/datatypes.h b/src/datatypes.h index 61b9c64..526d69a 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,9 +498,78 @@ 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; +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,