Skip to content
5 changes: 4 additions & 1 deletion ArduCopter/AP_Arming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ bool AP_Arming_Copter::pre_arm_proximity_check(bool display_failure)
// has side-effect that logging is started
bool AP_Arming_Copter::arm_checks(bool display_failure, bool arming_from_gcs)
{
/*
// always check if inertial nav has started and is ready
if (!ahrs.healthy()) {
check_failed(ARMING_CHECK_NONE, display_failure, "Waiting for Nav Checks");
Expand All @@ -544,7 +545,6 @@ bool AP_Arming_Copter::arm_checks(bool display_failure, bool arming_from_gcs)
return false;
}
#endif

if (_compass.is_calibrating()) {
check_failed(ARMING_CHECK_NONE, display_failure, "Compass calibration running");
return false;
Expand Down Expand Up @@ -589,6 +589,7 @@ bool AP_Arming_Copter::arm_checks(bool display_failure, bool arming_from_gcs)
return false;
}
}
*/

control_mode_t control_mode = copter.control_mode;

Expand Down Expand Up @@ -709,6 +710,7 @@ bool AP_Arming_Copter::pre_takeoff_checks(void)
gcs().send_text(MAV_SEVERITY_CRITICAL,"Takeoff: not armed");
return false;
}
/*
float pos_change, alt_change;
if (!copter.gps.get_pre_arm_pos_change(pos_change, alt_change)) {
gcs().send_text(MAV_SEVERITY_CRITICAL,"Takeoff: no GPS data");
Expand All @@ -722,5 +724,6 @@ bool AP_Arming_Copter::pre_takeoff_checks(void)
gcs().send_text(MAV_SEVERITY_CRITICAL,"Takeoff: alt change %.2f", alt_change);
return false;
}
*/
return true;
}
6 changes: 5 additions & 1 deletion ArduCopter/Copter.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@
#include <AP_Devo_Telem/AP_Devo_Telem.h>
#endif

#include <AP_ESC_Telem/AP_ESC_Telem.h>

#if OSD_ENABLED == ENABLED
#include <AP_OSD/AP_OSD.h>
#endif
Expand Down Expand Up @@ -466,7 +468,9 @@ class Copter : public AP_HAL::HAL::Callbacks {
#if OSD_ENABLED == ENABLED
AP_OSD osd;
#endif


AP_ESC_Telem esc_telem;

// Variables for extended status MAVLink messages
uint32_t control_sensors_present;
uint32_t control_sensors_enabled;
Expand Down
1 change: 0 additions & 1 deletion ArduCopter/Parameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,6 @@ class ParametersG2 {
// follow
AP_Follow follow;
#endif

};

/*
Expand Down
3 changes: 3 additions & 0 deletions ArduCopter/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,9 @@ void Copter::init_ardupilot()
// disable safety if requested
BoardConfig.init_safety();

// init ESC telemetry
esc_telem.init();

// default enable RC override
copter.ap.rc_override_enable = true;

Expand Down
1 change: 1 addition & 0 deletions ArduCopter/wscript
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def build(bld):
'AP_Follow',
'AP_Devo_Telem',
'AP_OSD',
'AP_ESC_Telem',
],
)

Expand Down
205 changes: 205 additions & 0 deletions libraries/AP_ESC_Telem/AP_ESC_Telem.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/*
ESC Telemetry for Hobbywing Pro 80A HV ESC. This will be
incorporated into a broader ESC telemetry library in ArduPilot
master in the future
*/
#include "AP_ESC_Telem.h"
#include <AP_SerialManager/AP_SerialManager.h>
#include <stdio.h>
#include <AP_HAL/utility/sparse-endian.h>
#include <DataFlash/DataFlash.h>
#include <GCS_MAVLink/GCS_MAVLink.h>
#include <GCS_MAVLink/GCS.h>

extern const AP_HAL::HAL& hal;

#define TELEM_HEADER 0x9B
#define TELEM_LEN 0x16

AP_ESC_Telem *AP_ESC_Telem::singleton;

// constructor
AP_ESC_Telem::AP_ESC_Telem(void)
{
singleton = this;
}

void AP_ESC_Telem::init()
{
AP_SerialManager *serial_manager = AP_SerialManager::get_instance();
if (!serial_manager) {
return;
}
uart = serial_manager->find_serial(AP_SerialManager::SerialProtocol_ESCTelemetry, 0);
if (uart) {
sem = hal.util->new_semaphore();
hal.scheduler->register_timer_process(FUNCTOR_BIND(this, &AP_ESC_Telem::timer_update, void));
}
}

/*
update ESC telemetry
*/
void AP_ESC_Telem::timer_update()
{
if (!initialised) {
initialised = true;
uart->begin(19200);
}

uint32_t n = uart->available();
if (n == 0) {
return;
}

// we expect at least 50ms idle between frames
uint32_t now = AP_HAL::millis();
bool frame_gap = (now - last_read_ms) > 10;

last_read_ms = now;

// don't read too much in one loop to prevent too high CPU load
n = MIN(n, 500U);
if (len == 0 && !frame_gap) {
// discard
while (n--) {
uart->read();
}
return;
}

if (frame_gap) {
len = 0;
}

while (n--) {
uint8_t b = uart->read();
//hal.console->printf("t=%u 0x%02x\n", now, b);
if (len == 0 && b != TELEM_HEADER) {
continue;
}
if (len == 1 && b != TELEM_LEN) {
continue;
}
uint8_t *buf = (uint8_t *)&pkt;
buf[len++] = b;
if (len == sizeof(pkt)) {
parse_packet();
len = 0;
}
}
}

static uint16_t calc_crc(const uint8_t *buf, uint8_t len)
{
uint16_t crc = 0;
while (len--) {
crc += *buf++;
}
return crc;
}

static const struct {
uint8_t adc_temp;
uint8_t temp_C;
} temp_table[] = {
{ 241, 0}, { 240, 1}, { 239, 2}, { 238, 3}, { 237, 4}, { 236, 5}, { 235, 6}, { 234, 7}, { 233, 8}, { 232, 9},
{ 231, 10}, { 230, 11}, { 229, 12}, { 228, 13}, { 227, 14}, { 226, 15}, { 224, 16}, { 223, 17}, { 222, 18}, { 220, 19},
{ 219, 20}, { 217, 21}, { 216, 22}, { 214, 23}, { 213, 24}, { 211, 25}, { 209, 26}, { 208, 27}, { 206, 28}, { 204, 29},
{ 202, 30}, { 201, 31}, { 199, 32}, { 197, 33}, { 195, 34}, { 193, 35}, { 191, 36}, { 189, 37}, { 187, 38}, { 185, 39},
{ 183, 40}, { 181, 41}, { 179, 42}, { 177, 43}, { 174, 44}, { 172, 45}, { 170, 46}, { 168, 47}, { 166, 48}, { 164, 49},
{ 161, 50}, { 159, 51}, { 157, 52}, { 154, 53}, { 152, 54}, { 150, 55}, { 148, 56}, { 146, 57}, { 143, 58}, { 141, 59},
{ 139, 60}, { 136, 61}, { 134, 62}, { 132, 63}, { 130, 64}, { 128, 65}, { 125, 66}, { 123, 67}, { 121, 68}, { 119, 69},
{ 117, 70}, { 115, 71}, { 113, 72}, { 111, 73}, { 109, 74}, { 106, 75}, { 105, 76}, { 103, 77}, { 101, 78}, { 99, 79},
{ 97, 80}, { 95, 81}, { 93, 82}, { 91, 83}, { 90, 84}, { 88, 85}, { 85, 86}, { 84, 87}, { 82, 88}, { 81, 89},
{ 79, 90}, { 77, 91}, { 76, 92}, { 74, 93}, { 73, 94}, { 72, 95}, { 69, 96}, { 68, 97}, { 66, 98}, { 65, 99},
{ 64, 100}, { 62, 101}, { 62, 102}, { 61, 103}, { 59, 104}, { 58, 105}, { 56, 106}, { 54, 107}, { 54, 108}, { 53, 109},
{ 51, 110}, { 51, 111}, { 50, 112}, { 48, 113}, { 48, 114}, { 46, 115}, { 46, 116}, { 44, 117}, { 43, 118}, { 43, 119},
{ 41, 120}, { 41, 121}, { 39, 122}, { 39, 123}, { 39, 124}, { 37, 125}, { 37, 126}, { 35, 127}, { 35, 128}, { 33, 129},
};

uint8_t AP_ESC_Telem::temperature_decode(uint8_t temp_raw) const
{
for (uint8_t i=0; i<ARRAY_SIZE(temp_table); i++) {
if (temp_table[i].adc_temp <= temp_raw) {
return temp_table[i].temp_C;
}
}
return 130U;
}

/*
parse packet
*/
void AP_ESC_Telem::parse_packet(void)
{
uint16_t crc = calc_crc((uint8_t *)&pkt, sizeof(pkt)-2);
if (crc != pkt.crc) {
return;
}

sem->take_blocking();
decoded.counter = be32toh(pkt.counter);
decoded.throttle_req = be16toh(pkt.throttle_req) * 100.0 / 1024.0;
decoded.throttle = be16toh(pkt.throttle) * 100.0 / 1024.0;
decoded.rpm = be16toh(pkt.erpm) * 10.0 / 14.0;
decoded.voltage = be16toh(pkt.voltage) * 0.1;
decoded.current = int16_t(be16toh(pkt.current)) / 64.0;
decoded.phase_current = int16_t(be16toh(pkt.phase_current)) / 64.0;
decoded.mos_temperature = temperature_decode(pkt.mos_temperature);
decoded.cap_temperature = temperature_decode(pkt.cap_temperature);
decoded.status = be16toh(pkt.status);
sem->give();

#if 0
uint32_t now = AP_HAL::millis();
static uint32_t last_ms;
uint32_t dt = now - last_ms;
last_ms = now;
hal.console->printf("dt=%u %u RPM:%.1f THR:%.1f:%.1f V:%.2f C:%.1f CP:%.1f\n", dt,
unsigned(decoded.counter),
decoded.rpm,
decoded.throttle_req, decoded.throttle,
decoded.voltage, decoded.current, decoded.phase_current);
#endif

DataFlash_Class::instance()->Log_Write("HESC", "TimeUS,CNT,RPM,ThrR,Thr,Volt,Curr,CurrP,TempM,TempC,Status",
"QIffffffBBH",
AP_HAL::micros64(),
decoded.counter,
decoded.rpm,
decoded.throttle_req,
decoded.throttle,
decoded.voltage,
decoded.current,
decoded.phase_current,
decoded.mos_temperature,
decoded.cap_temperature,
decoded.status);
}

/*
send telemetry on mavlink
*/
void AP_ESC_Telem::send_esc_telemetry_mavlink(uint8_t chan)
{
if (!uart) {
return;
}
uint8_t temperature[4] {};
uint16_t voltage[4] {};
uint16_t current[4] {};
uint16_t totalcurrent[4] {};
uint16_t rpm[4] {};
uint16_t count[4] {};
if (!HAVE_PAYLOAD_SPACE((mavlink_channel_t)chan, ESC_TELEMETRY_1_TO_4)) {
return;
}
sem->take_blocking();
voltage[0] = decoded.voltage * 1000;
current[0] = decoded.current;
rpm[0] = decoded.rpm;
temperature[0] = MAX(decoded.mos_temperature, decoded.cap_temperature);
sem->give();
mavlink_msg_esc_telemetry_1_to_4_send((mavlink_channel_t)chan, temperature, voltage, current, totalcurrent, rpm, count);
}
74 changes: 74 additions & 0 deletions libraries/AP_ESC_Telem/AP_ESC_Telem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
ESC Telemetry for Hobbywing Pro 80A HV ESC. This will be
incorporated into a broader ESC telemetry library in ArduPilot
master in the future
*/

#pragma once

#include <AP_HAL/AP_HAL.h>
#include <AP_SerialManager/AP_SerialManager.h>
#include <AP_Param/AP_Param.h>

class AP_ESC_Telem {
public:
AP_ESC_Telem();

/* Do not allow copies */
AP_ESC_Telem(const AP_ESC_Telem &other) = delete;
AP_ESC_Telem &operator=(const AP_ESC_Telem&) = delete;

void init(void);

void send_esc_telemetry_mavlink(uint8_t chan);

static AP_ESC_Telem *get_singleton(void) {
return singleton;
}

private:
static AP_ESC_Telem *singleton;
AP_HAL::UARTDriver *uart;

void timer_update();

struct PACKED {
uint8_t header; // 0x9B
uint8_t pkt_len; // 0x16
uint32_t counter;
uint16_t throttle_req;
uint16_t throttle;
uint16_t erpm;
uint16_t voltage;
int16_t current;
int16_t phase_current;
uint8_t mos_temperature;
uint8_t cap_temperature;
uint16_t status;
uint16_t crc;
} pkt;

bool initialised;
uint8_t len;
uint32_t last_read_ms;

struct {
uint32_t counter;
float throttle_req;
float throttle;
float rpm;
float voltage;
float current;
float phase_current;
uint8_t mos_temperature;
uint8_t cap_temperature;
uint16_t status;
} decoded;

uint32_t last_mavlink_ms;

AP_HAL::Semaphore *sem;

void parse_packet(void);
uint8_t temperature_decode(uint8_t temp_raw) const;
};
2 changes: 1 addition & 1 deletion libraries/AP_HAL_ChibiOS/hwdef/fmuv3/hwdef.dat
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ PD6 USART2_RX USART2
# the telem2 USART, also with RTS/CTS available
# USART3 serial3 telem2
PD8 USART3_TX USART3
PD9 USART3_RX USART3
PD9 USART3_RX USART3 PULLDOWN
PD11 USART3_CTS USART3
PD12 USART3_RTS USART3

Expand Down
4 changes: 2 additions & 2 deletions libraries/DataFlash/DataFlash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1014,7 +1014,7 @@ bool DataFlash_Class::log_while_disarmed(void) const
if (_params.log_disarmed != 0) {
return true;
}

/*
uint32_t now = AP_HAL::millis();
uint32_t persist_ms = HAL_LOGGER_ARM_PERSIST*1000U;

Expand All @@ -1027,6 +1027,6 @@ bool DataFlash_Class::log_while_disarmed(void) const
if (_last_arming_failure_ms && now - _last_arming_failure_ms < persist_ms) {
return true;
}

*/
return false;
}
Loading