Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/Tools/AP_Periph/hwing_esc.cpp
Views: 1798
/*1ESC Telemetry for Hobbywing Pro 80A HV ESC. This will be2incorporated into a broader ESC telemetry library in ArduPilot3master in the future45This protocol only allows for one ESC per UART RX line, so using a6CAN node per ESC works well.7*/89#include "AP_Periph.h"10#include "hwing_esc.h"11#include <AP_HAL/utility/sparse-endian.h>12#include <dronecan_msgs.h>1314#ifdef HAL_PERIPH_ENABLE_HWESC1516#include <SITL/SITL.h>1718extern const AP_HAL::HAL& hal;1920#define TELEM_HEADER 0x9B21#define TELEM_LEN 0x162223// constructor24HWESC_Telem::HWESC_Telem(void)25{26}2728void HWESC_Telem::init(AP_HAL::UARTDriver *_uart)29{30uart = _uart;31uart->begin(19200);32uart->set_options(AP_HAL::UARTDriver::OPTION_PULLDOWN_RX);33}3435/*36update ESC telemetry37*/38bool HWESC_Telem::update()39{40uint32_t n = uart->available();41if (n == 0) {42return false;43}4445// we expect at least 50ms idle between frames46uint32_t now = AP_HAL::millis();47bool frame_gap = (now - last_read_ms) > 10;4849last_read_ms = now;5051// don't read too much in one loop to prevent too high CPU load52if (n > 500) {53n = 500;54}55if (len == 0 && !frame_gap) {56uart->discard_input();57return false;58}5960if (frame_gap) {61len = 0;62}6364bool ret = false;6566while (n--) {67uint8_t b = uart->read();68//hal.console->printf("t=%u 0x%02x\n", now, b);69if (len == 0 && b != TELEM_HEADER) {70continue;71}72if (len == 1 && b != TELEM_LEN) {73continue;74}75uint8_t *buf = (uint8_t *)&pkt;76buf[len++] = b;77if (len == sizeof(pkt)) {78ret = parse_packet();79len = 0;80}81}82return ret;83}8485static uint16_t calc_crc(const uint8_t *buf, uint8_t len)86{87uint16_t crc = 0;88while (len--) {89crc += *buf++;90}91return crc;92}9394static const struct {95uint8_t adc_temp;96uint8_t temp_C;97} temp_table[] = {98{ 241, 0}, { 240, 1}, { 239, 2}, { 238, 3}, { 237, 4}, { 236, 5}, { 235, 6}, { 234, 7}, { 233, 8}, { 232, 9},99{ 231, 10}, { 230, 11}, { 229, 12}, { 228, 13}, { 227, 14}, { 226, 15}, { 224, 16}, { 223, 17}, { 222, 18}, { 220, 19},100{ 219, 20}, { 217, 21}, { 216, 22}, { 214, 23}, { 213, 24}, { 211, 25}, { 209, 26}, { 208, 27}, { 206, 28}, { 204, 29},101{ 202, 30}, { 201, 31}, { 199, 32}, { 197, 33}, { 195, 34}, { 193, 35}, { 191, 36}, { 189, 37}, { 187, 38}, { 185, 39},102{ 183, 40}, { 181, 41}, { 179, 42}, { 177, 43}, { 174, 44}, { 172, 45}, { 170, 46}, { 168, 47}, { 166, 48}, { 164, 49},103{ 161, 50}, { 159, 51}, { 157, 52}, { 154, 53}, { 152, 54}, { 150, 55}, { 148, 56}, { 146, 57}, { 143, 58}, { 141, 59},104{ 139, 60}, { 136, 61}, { 134, 62}, { 132, 63}, { 130, 64}, { 128, 65}, { 125, 66}, { 123, 67}, { 121, 68}, { 119, 69},105{ 117, 70}, { 115, 71}, { 113, 72}, { 111, 73}, { 109, 74}, { 106, 75}, { 105, 76}, { 103, 77}, { 101, 78}, { 99, 79},106{ 97, 80}, { 95, 81}, { 93, 82}, { 91, 83}, { 90, 84}, { 88, 85}, { 85, 86}, { 84, 87}, { 82, 88}, { 81, 89},107{ 79, 90}, { 77, 91}, { 76, 92}, { 74, 93}, { 73, 94}, { 72, 95}, { 69, 96}, { 68, 97}, { 66, 98}, { 65, 99},108{ 64, 100}, { 62, 101}, { 62, 102}, { 61, 103}, { 59, 104}, { 58, 105}, { 56, 106}, { 54, 107}, { 54, 108}, { 53, 109},109{ 51, 110}, { 51, 111}, { 50, 112}, { 48, 113}, { 48, 114}, { 46, 115}, { 46, 116}, { 44, 117}, { 43, 118}, { 43, 119},110{ 41, 120}, { 41, 121}, { 39, 122}, { 39, 123}, { 39, 124}, { 37, 125}, { 37, 126}, { 35, 127}, { 35, 128}, { 33, 129},111};112113uint8_t HWESC_Telem::temperature_decode(uint8_t temp_raw) const114{115for (uint8_t i=0; i<ARRAY_SIZE(temp_table); i++) {116if (temp_table[i].adc_temp <= temp_raw) {117return temp_table[i].temp_C;118}119}120return 130U;121}122123/*124parse packet125*/126bool HWESC_Telem::parse_packet(void)127{128uint16_t crc = calc_crc((uint8_t *)&pkt, sizeof(pkt)-2);129if (crc != pkt.crc) {130return false;131}132133decoded.counter = be32toh(pkt.counter);134decoded.throttle_req = be16toh(pkt.throttle_req);135decoded.throttle = be16toh(pkt.throttle);136decoded.rpm = be16toh(pkt.rpm) * 5.0 / 7.0; // scale from eRPM to RPM137decoded.voltage = be16toh(pkt.voltage) * 0.1;138decoded.phase_current = int16_t(be16toh(pkt.phase_current)) * 0.01;139decoded.current = int16_t(be16toh(pkt.current)) * 0.01;140decoded.mos_temperature = temperature_decode(pkt.mos_temperature);141decoded.cap_temperature = temperature_decode(pkt.cap_temperature);142decoded.status = be16toh(pkt.status);143if (decoded.status != 0) {144decoded.error_count++;145}146147return true;148}149150void AP_Periph_FW::hwesc_telem_update()151{152if (!hwesc_telem.update()) {153return;154}155const HWESC_Telem::HWESC &t = hwesc_telem.get_telem();156157uavcan_equipment_esc_Status pkt {};158pkt.esc_index = g.esc_number[0]; // only supports a single ESC159pkt.voltage = t.voltage;160pkt.current = t.current;161pkt.temperature = C_TO_KELVIN(MAX(t.mos_temperature, t.cap_temperature));162pkt.rpm = t.rpm;163pkt.power_rating_pct = t.phase_current;164pkt.error_count = t.error_count;165166uint8_t buffer[UAVCAN_EQUIPMENT_ESC_STATUS_MAX_SIZE];167uint16_t total_size = uavcan_equipment_esc_Status_encode(&pkt, buffer, !canfdout());168canard_broadcast(UAVCAN_EQUIPMENT_ESC_STATUS_SIGNATURE,169UAVCAN_EQUIPMENT_ESC_STATUS_ID,170CANARD_TRANSFER_PRIORITY_LOW,171&buffer[0],172total_size);173}174175#endif // HAL_PERIPH_ENABLE_HWESC176177178179