From 32c313578868ddb1cf203ab820c4024de9c0013f Mon Sep 17 00:00:00 2001 From: Julian Oes <julian@oes.ch> Date: Wed, 24 Feb 2016 18:08:56 +0000 Subject: [PATCH] commander: move battery calculations to systemlib The commander used to consume the battery_status topic and write the contents after some calculations into the system state. Instead, the calculations now happen in library calls in systemlib/battery. This moves the battery fields out of the vehicle_status message into the battery_status topic. This brought quite some changes in all modules that need battery information. The current state is compiling but untested. --- msg/battery_status.msg | 11 +- msg/vehicle_status.msg | 8 - src/drivers/blinkm/blinkm.cpp | 53 ++++-- src/drivers/frsky_telemetry/frsky_data.c | 57 +++--- src/drivers/frsky_telemetry/frsky_data.h | 1 + src/drivers/frsky_telemetry/frsky_telemetry.c | 2 + src/drivers/frsky_telemetry/sPort_data.c | 35 ++-- src/drivers/px4io/px4io.cpp | 36 ++-- src/modules/commander/commander.cpp | 152 ++++++++-------- src/modules/commander/commander_helper.cpp | 72 -------- src/modules/commander/commander_helper.h | 17 -- src/modules/commander/commander_params.c | 82 +-------- src/modules/gpio_led/gpio_led.c | 36 ++-- src/modules/mavlink/mavlink_messages.cpp | 34 ++-- src/modules/sdlog2/sdlog2.c | 14 +- src/modules/sdlog2/sdlog2_messages.h | 8 +- src/modules/sensors/sensors.cpp | 80 +++------ src/modules/systemlib/CMakeLists.txt | 7 +- src/modules/systemlib/battery.cpp | 162 ++++++++++++++++++ src/modules/systemlib/battery.h | 97 +++++++++++ src/modules/systemlib/battery_params.c | 123 +++++++++++++ 21 files changed, 661 insertions(+), 426 deletions(-) create mode 100644 src/modules/systemlib/battery.cpp create mode 100644 src/modules/systemlib/battery.h create mode 100644 src/modules/systemlib/battery_params.c diff --git a/msg/battery_status.msg b/msg/battery_status.msg index 75b144c6e8..ff4485378a 100644 --- a/msg/battery_status.msg +++ b/msg/battery_status.msg @@ -3,4 +3,13 @@ float32 voltage_v # Battery voltage in volts, 0 if unknown float32 voltage_filtered_v # Battery voltage in volts, filtered, 0 if unknown float32 current_a # Battery current in amperes, -1 if unknown float32 discharged_mah # Discharged amount in mAh, -1 if unknown -bool is_powering_off # Power off event imminent indication, false if unknown +float32 remaining # From 1 to 0, -1 if unknown +int32 cell_count # Number of cells +#bool is_powering_off # Power off event imminent indication, false if unknown + + +uint8 BATTERY_WARNING_NONE = 0 # no battery low voltage warning active +uint8 BATTERY_WARNING_LOW = 1 # warning of low voltage +uint8 BATTERY_WARNING_CRITICAL = 2 # alerting of critical voltage + +uint8 warning # current battery warning diff --git a/msg/vehicle_status.msg b/msg/vehicle_status.msg index b6a0486456..33503c4e68 100644 --- a/msg/vehicle_status.msg +++ b/msg/vehicle_status.msg @@ -77,7 +77,6 @@ bool is_vtol # True if the system is VTOL capable bool vtol_fw_permanent_stab # True if vtol should stabilize attitude for fw in manual mode bool in_transition_mode # True if VTOL is doing a transition -bool condition_battery_voltage_valid bool condition_system_in_air_restore # true if we can restore in mid air bool condition_system_sensors_initialized bool condition_system_prearm_error_reported # true if errors have already been reported @@ -125,11 +124,4 @@ uint32 onboard_control_sensors_enabled uint32 onboard_control_sensors_health float32 load # processor load from 0 to 1 -float32 battery_voltage -float32 battery_current -float32 battery_remaining -float32 battery_discharged_mah -uint32 battery_cell_count - -uint8 battery_warning # current battery warning mode, as defined by VEHICLE_BATTERY_WARNING enum diff --git a/src/drivers/blinkm/blinkm.cpp b/src/drivers/blinkm/blinkm.cpp index 78fce9162e..b2098f06c5 100644 --- a/src/drivers/blinkm/blinkm.cpp +++ b/src/drivers/blinkm/blinkm.cpp @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (C) 2012 PX4 Development Team. All rights reserved. + * Copyright (C) 2012-2016 PX4 Development Team. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -119,12 +119,12 @@ #include <uORB/uORB.h> #include <uORB/topics/vehicle_status.h> +#include <uORB/topics/battery_status.h> #include <uORB/topics/vehicle_control_mode.h> #include <uORB/topics/actuator_armed.h> #include <uORB/topics/vehicle_gps_position.h> #include <uORB/topics/safety.h> -static const float MAX_CELL_VOLTAGE = 4.3f; static const int LED_ONTIME = 120; static const int LED_OFFTIME = 120; static const int LED_BLINK = 1; @@ -195,6 +195,7 @@ private: bool systemstate_run; int vehicle_status_sub_fd; + int battery_status_sub_fd; int vehicle_control_mode_sub_fd; int vehicle_gps_position_sub_fd; int actuator_armed_sub_fd; @@ -202,7 +203,6 @@ private: int num_of_cells; int detected_cells_runcount; - int t_led_color[8]; int t_led_blink; int led_thread_runcount; @@ -291,6 +291,7 @@ BlinkM::BlinkM(int bus, int blinkm) : led_blink(LED_NOBLINK), systemstate_run(false), vehicle_status_sub_fd(-1), + battery_status_sub_fd(-1), vehicle_control_mode_sub_fd(-1), vehicle_gps_position_sub_fd(-1), actuator_armed_sub_fd(-1), @@ -434,6 +435,9 @@ BlinkM::led() vehicle_status_sub_fd = orb_subscribe(ORB_ID(vehicle_status)); orb_set_interval(vehicle_status_sub_fd, 250); + battery_status_sub_fd = orb_subscribe(ORB_ID(battery_status)); + orb_set_interval(battery_status_sub_fd, 250); + vehicle_control_mode_sub_fd = orb_subscribe(ORB_ID(vehicle_control_mode)); orb_set_interval(vehicle_control_mode_sub_fd, 250); @@ -510,29 +514,33 @@ BlinkM::led() if (led_thread_runcount == 15) { /* obtained data for the first file descriptor */ - struct vehicle_status_s vehicle_status_raw; - struct vehicle_control_mode_s vehicle_control_mode; - struct actuator_armed_s actuator_armed; - struct vehicle_gps_position_s vehicle_gps_position_raw; - struct safety_s safety; + struct vehicle_status_s vehicle_status_raw = {}; + struct battery_status_s battery_status = {}; + struct vehicle_control_mode_s vehicle_control_mode = {}; + struct actuator_armed_s actuator_armed = {}; + struct vehicle_gps_position_s vehicle_gps_position_raw = {}; + struct safety_s safety = {}; memset(&vehicle_status_raw, 0, sizeof(vehicle_status_raw)); memset(&vehicle_gps_position_raw, 0, sizeof(vehicle_gps_position_raw)); memset(&safety, 0, sizeof(safety)); bool new_data_vehicle_status; + bool new_data_battery_status; bool new_data_vehicle_control_mode; bool new_data_actuator_armed; bool new_data_vehicle_gps_position; bool new_data_safety; - orb_check(vehicle_status_sub_fd, &new_data_vehicle_status); int no_data_vehicle_status = 0; + int no_data_battery_status = 0; int no_data_vehicle_control_mode = 0; int no_data_actuator_armed = 0; int no_data_vehicle_gps_position = 0; + orb_check(vehicle_status_sub_fd, &new_data_vehicle_status); + if (new_data_vehicle_status) { orb_copy(ORB_ID(vehicle_status), vehicle_status_sub_fd, &vehicle_status_raw); no_data_vehicle_status = 0; @@ -545,6 +553,19 @@ BlinkM::led() } } + orb_check(battery_status_sub_fd, &new_data_battery_status); + + if (new_data_battery_status) { + orb_copy(ORB_ID(battery_status), battery_status_sub_fd, &battery_status); + + } else { + no_data_battery_status++; + + if (no_data_battery_status >= 3) { + no_data_battery_status = 3; + } + } + orb_check(vehicle_control_mode_sub_fd, &new_data_vehicle_control_mode); if (new_data_vehicle_control_mode) { @@ -597,19 +618,13 @@ BlinkM::led() /* get number of used satellites in navigation */ num_of_used_sats = vehicle_gps_position_raw.satellites_used; - if (new_data_vehicle_status || no_data_vehicle_status < 3) { + if (new_data_battery_status || no_data_battery_status < 3) { if (num_of_cells == 0) { - /* looking for lipo cells that are connected */ - printf("<blinkm> checking cells\n"); - - for (num_of_cells = 2; num_of_cells < 7; num_of_cells++) { - if (vehicle_status_raw.battery_voltage < num_of_cells * MAX_CELL_VOLTAGE) { break; } - } - printf("<blinkm> cells found:%d\n", num_of_cells); + num_of_cells = battery_status.cell_count; } else { - if (vehicle_status_raw.battery_warning == vehicle_status_s::VEHICLE_BATTERY_WARNING_CRITICAL) { + if (battery_status.warning == battery_status_s::BATTERY_WARNING_CRITICAL) { /* LED Pattern for battery critical alerting */ led_color_1 = LED_RED; led_color_2 = LED_RED; @@ -633,7 +648,7 @@ BlinkM::led() led_color_8 = LED_BLUE; led_blink = LED_BLINK; - } else if (vehicle_status_raw.battery_warning == vehicle_status_s::VEHICLE_BATTERY_WARNING_LOW) { + } else if (battery_status.warning == battery_status_s::BATTERY_WARNING_LOW) { /* LED Pattern for battery low warning */ led_color_1 = LED_YELLOW; led_color_2 = LED_YELLOW; diff --git a/src/drivers/frsky_telemetry/frsky_data.c b/src/drivers/frsky_telemetry/frsky_data.c index 70b2c2ab43..723a51415d 100644 --- a/src/drivers/frsky_telemetry/frsky_data.c +++ b/src/drivers/frsky_telemetry/frsky_data.c @@ -53,7 +53,6 @@ #include <uORB/topics/battery_status.h> #include <uORB/topics/sensor_combined.h> #include <uORB/topics/vehicle_global_position.h> -#include <uORB/topics/vehicle_status.h> #include <drivers/drv_hrt.h> @@ -95,12 +94,15 @@ static struct battery_status_s *battery_status; static struct vehicle_global_position_s *global_pos; static struct sensor_combined_s *sensor_data; -static struct vehicle_status_s *vehicle_status; -static int battery_sub = -1; +static int battery_status_sub = -1; static int global_position_sub = -1; static int sensor_sub = -1; -static int vehicle_status_sub = -1; + +static struct battery_status_s battery_status; +static struct sensor_combined_s raw; +static struct vehicle_global_position_s global_pos; + /** * Initializes the uORB subscriptions. @@ -110,16 +112,14 @@ bool frsky_init() battery_status = malloc(sizeof(struct battery_status_s)); global_pos = malloc(sizeof(struct vehicle_global_position_s)); sensor_data = malloc(sizeof(struct sensor_combined_s)); - vehicle_status = malloc(sizeof(struct vehicle_status_s)); - if (battery_status == NULL || global_pos == NULL || sensor_data == NULL || vehicle_status == NULL) { + if (battery_status == NULL || global_pos == NULL || sensor_data == NULL) { return false; } - battery_sub = orb_subscribe(ORB_ID(battery_status)); + battery_status_sub = orb_subscribe(ORB_ID(battery_status)); global_position_sub = orb_subscribe(ORB_ID(vehicle_global_position)); sensor_sub = orb_subscribe(ORB_ID(sensor_combined)); - vehicle_status_sub = orb_subscribe(ORB_ID(vehicle_status)); return true; } @@ -128,7 +128,6 @@ void frsky_deinit() free(battery_status); free(global_pos); free(sensor_data); - free(vehicle_status); } /** @@ -178,18 +177,35 @@ static void frsky_send_data(int uart, uint8_t id, int16_t data) frsky_send_byte(uart, udata >> 8); /* MSB */ } +void frsky_update_topics() +{ + bool updated; + + /* get a local copy of the current sensor values */ + orb_check(sensor_sub, &updated); + if (updated) { + orb_copy(ORB_ID(sensor_combined), sensor_sub, raw); + } + + /* get a local copy of the battery data */ + orb_check(battery_status_sub, &updated); + if (updated) { + orb_copy(ORB_ID(battery_status), battery_status_sub, battery_status); + } + + /* get a local copy of the global position data */ + orb_check(global_position_sub, &updated); + if (updated) { + orb_copy(ORB_ID(vehicle_global_position), global_position_sub, global_pos); + } +} + /** * Sends frame 1 (every 200ms): * acceleration values, barometer altitude, temperature, battery voltage & current */ void frsky_send_frame1(int uart) { - /* get a local copy of the current sensor values */ - orb_copy(ORB_ID(sensor_combined), sensor_sub, sensor_data); - - /* get a local copy of the battery data */ - orb_copy(ORB_ID(battery_status), battery_sub, battery_status); - /* send formatted frame */ frsky_send_data(uart, FRSKY_ID_ACCEL_X, roundf(sensor_data->accelerometer_m_s2[0] * 1000.0f)); @@ -229,12 +245,6 @@ static float frsky_format_gps(float dec) */ void frsky_send_frame2(int uart) { - /* get a local copy of the global position data */ - orb_copy(ORB_ID(vehicle_global_position), global_position_sub, global_pos); - - /* get a local copy of the vehicle status data */ - orb_copy(ORB_ID(vehicle_status), vehicle_status_sub, vehicle_status); - /* send formatted frame */ float course = 0, lat = 0, lon = 0, speed = 0, alt = 0; char lat_ns = 0, lon_ew = 0; @@ -273,7 +283,7 @@ void frsky_send_frame2(int uart) frsky_send_data(uart, FRSKY_ID_GPS_ALT_AP, frac(alt) * 100.0f); frsky_send_data(uart, FRSKY_ID_FUEL, - roundf(vehicle_status->battery_remaining * 100.0f)); + roundf(battery_status->remaining * 100.0f)); frsky_send_data(uart, FRSKY_ID_GPS_SEC, sec); @@ -286,9 +296,6 @@ void frsky_send_frame2(int uart) */ void frsky_send_frame3(int uart) { - /* get a local copy of the battery data */ - orb_copy(ORB_ID(vehicle_global_position), global_position_sub, global_pos); - /* send formatted frame */ time_t time_gps = global_pos->time_utc_usec / 1000000ULL; struct tm *tm_gps = gmtime(&time_gps); diff --git a/src/drivers/frsky_telemetry/frsky_data.h b/src/drivers/frsky_telemetry/frsky_data.h index b3c41d0aa4..a66f939ad7 100644 --- a/src/drivers/frsky_telemetry/frsky_data.h +++ b/src/drivers/frsky_telemetry/frsky_data.h @@ -47,6 +47,7 @@ // Public functions bool frsky_init(void); void frsky_deinit(void); +void frsky_update_topics(void); void frsky_send_frame1(int uart); void frsky_send_frame2(int uart); void frsky_send_frame3(int uart); diff --git a/src/drivers/frsky_telemetry/frsky_telemetry.c b/src/drivers/frsky_telemetry/frsky_telemetry.c index 35b4ed2c47..3cac256ddd 100644 --- a/src/drivers/frsky_telemetry/frsky_telemetry.c +++ b/src/drivers/frsky_telemetry/frsky_telemetry.c @@ -456,6 +456,8 @@ static int frsky_telemetry_thread_main(int argc, char *argv[]) host_frame.ad1, host_frame.ad2, host_frame.linkq); } + frsky_update_topics(); + /* Send frame 1 (every 200ms): acceleration values, altitude (vario), temperatures, current & voltages, RPM */ if (iteration % 2 == 0) { frsky_send_frame1(uart); diff --git a/src/drivers/frsky_telemetry/sPort_data.c b/src/drivers/frsky_telemetry/sPort_data.c index 41d0661c59..c373640a94 100644 --- a/src/drivers/frsky_telemetry/sPort_data.c +++ b/src/drivers/frsky_telemetry/sPort_data.c @@ -51,7 +51,7 @@ #include <uORB/topics/sensor_combined.h> #include <uORB/topics/vehicle_global_position.h> -#include <uORB/topics/vehicle_status.h> +#include <uORB/topics/battery_status.h> #include <drivers/drv_hrt.h> @@ -59,35 +59,35 @@ static int sensor_sub = -1; static int global_position_sub = -1; -static int vehicle_status_sub = -1; -static struct vehicle_status_s *vehicle_status; +static int battery_status_sub = -1; static struct sensor_combined_s *sensor_data; static struct vehicle_global_position_s *global_pos; +static struct battery_status_s *battery_status; /** * Initializes the uORB subscriptions. */ bool sPort_init() { - vehicle_status = malloc(sizeof(struct vehicle_status_s)); sensor_data = malloc(sizeof(struct sensor_combined_s)); global_pos = malloc(sizeof(struct vehicle_global_position_s)); + battery_status = malloc(sizeof(struct battery_status_s)); - if (vehicle_status == NULL || sensor_data == NULL || global_pos == NULL) { + if (sensor_data == NULL || global_pos == NULL || battery_status == NULL) { return false; } - global_position_sub = orb_subscribe(ORB_ID(vehicle_global_position)); sensor_sub = orb_subscribe(ORB_ID(sensor_combined)); - vehicle_status_sub = orb_subscribe(ORB_ID(vehicle_status)); + global_position_sub = orb_subscribe(ORB_ID(vehicle_global_position)); + battery_status_sub = orb_subscribe(ORB_ID(battery_status)); return true; } void sPort_deinit() { - free(vehicle_status); free(sensor_data); free(global_pos); + free(battery_status); } static void update_crc(uint16_t *crc, unsigned char b) @@ -158,19 +158,24 @@ void sPort_send_data(int uart, uint16_t id, uint32_t data) // scaling correct with OpenTX 2.1.7 void sPort_send_BATV(int uart) { - /* get a local copy of the vehicle status data */ - orb_copy(ORB_ID(vehicle_status), vehicle_status_sub, vehicle_status); + /* get a local copy of the battery data */ + orb_copy(ORB_ID(battery_status), battery_status_sub, battery_status); /* send battery voltage as VFAS */ - uint32_t voltage = (int)(100 * vehicle_status->battery_voltage); + uint32_t voltage = (int)(100 * battery_status->voltage_v); + sPort_send_data(uart, SMARTPORT_ID_VFAS, voltage); } // verified scaling void sPort_send_CUR(int uart) { + /* get a local copy of the battery data */ + orb_copy(ORB_ID(battery_status), battery_status_sub, battery_status); + /* send data */ - uint32_t current = (int)(10 * vehicle_status->battery_current); + uint32_t current = (int)(10 * battery_status->current_a); + sPort_send_data(uart, SMARTPORT_ID_CURR, current); } @@ -207,8 +212,12 @@ void sPort_send_VSPD(int uart, float speed) // verified scaling void sPort_send_FUEL(int uart) { + /* get a local copy of the battery data */ + orb_copy(ORB_ID(battery_status), battery_status_sub, battery_status); + /* send data */ - uint32_t fuel = (int)(100 * vehicle_status->battery_remaining); + uint32_t fuel = (int)(100 * vehicle_status->remaining_mah); + sPort_send_data(uart, SMARTPORT_ID_FUEL, fuel); } diff --git a/src/drivers/px4io/px4io.cpp b/src/drivers/px4io/px4io.cpp index f5421b4307..3159154158 100644 --- a/src/drivers/px4io/px4io.cpp +++ b/src/drivers/px4io/px4io.cpp @@ -74,6 +74,7 @@ #include <systemlib/param/param.h> #include <systemlib/circuit_breaker.h> #include <systemlib/mavlink_log.h> +#include <systemlib/battery.h> #include <uORB/topics/actuator_controls.h> #include <uORB/topics/actuator_controls_0.h> @@ -308,10 +309,14 @@ private: bool _cb_flighttermination; ///< true if the flight termination circuit breaker is enabled bool _in_esc_calibration_mode; ///< do not send control outputs to IO (used for esc calibration) + Battery _battery; + int32_t _rssi_pwm_chan; ///< RSSI PWM input channel int32_t _rssi_pwm_max; ///< max RSSI input on PWM channel int32_t _rssi_pwm_min; ///< min RSSI input on PWM channel + float _last_throttle; ///< last throttle value for battery calculation + #ifdef CONFIG_ARCH_BOARD_PX4FMU_V1 bool _dsm_vcc_ctl; ///< true if relay 1 controls DSM satellite RX power #endif @@ -538,9 +543,11 @@ PX4IO::PX4IO(device::Device *interface) : _battery_last_timestamp(0), _cb_flighttermination(true), _in_esc_calibration_mode(false), + _battery{}, _rssi_pwm_chan(0), _rssi_pwm_max(0), - _rssi_pwm_min(0) + _rssi_pwm_min(0), + _last_throttle(0.0f) #ifdef CONFIG_ARCH_BOARD_PX4FMU_V1 , _dsm_vcc_ctl(false) #endif @@ -1188,6 +1195,8 @@ PX4IO::task_main() (PX4IO_P_SETUP_FEATURES_SBUS1_OUT | PX4IO_P_SETUP_FEATURES_SBUS2_OUT), 0); } } + // Also trigger param update in Battery instance. + _battery.updateParams(); } } @@ -1297,6 +1306,11 @@ PX4IO::io_set_control_state(unsigned group) regs[i] = FLOAT_TO_REG(ctrl); } + // save last throttle for battery calculation + if (group == 0) { + _last_throttle = controls.control[3]; + } + /* copy values to registers in IO */ return io_reg_set(PX4IO_PAGE_CONTROLS, group * PX4IO_PROTOCOL_MAX_CONTROL_COUNT, regs, _max_controls); } @@ -1648,29 +1662,19 @@ PX4IO::io_handle_battery(uint16_t vbatt, uint16_t ibatt) } battery_status_s battery_status; - battery_status.timestamp = hrt_absolute_time(); + const hrt_abstime timestamp = hrt_absolute_time(); /* voltage is scaled to mV */ - battery_status.voltage_v = vbatt / 1000.0f; - battery_status.voltage_filtered_v = vbatt / 1000.0f; + const float voltage_v = vbatt / 1000.0f; /* ibatt contains the raw ADC count, as 12 bit ADC value, with full range being 3.3v */ - battery_status.current_a = ibatt * (3.3f / 4096.0f) * _battery_amp_per_volt; - battery_status.current_a += _battery_amp_bias; - - /* - integrate battery over time to get total mAh used - */ - if (_battery_last_timestamp != 0) { - _battery_mamphour_total += battery_status.current_a * - (battery_status.timestamp - _battery_last_timestamp) * 1.0e-3f / 3600; - } + float current_a = ibatt * (3.3f / 4096.0f) * _battery_amp_per_volt; + current_a += _battery_amp_bias; - battery_status.discharged_mah = _battery_mamphour_total; - _battery_last_timestamp = battery_status.timestamp; + _battery.updateBatteryStatus(timestamp, voltage_v, current_a, _last_throttle, &battery_status); /* the announced battery status would conflict with the simulated battery status in HIL */ if (!(_pub_blocked)) { diff --git a/src/modules/commander/commander.cpp b/src/modules/commander/commander.cpp index 1a5476972d..4c659075af 100644 --- a/src/modules/commander/commander.cpp +++ b/src/modules/commander/commander.cpp @@ -255,7 +255,8 @@ bool handle_command(struct vehicle_status_s *status, const struct safety_s *safe */ int commander_thread_main(int argc, char *argv[]); -void control_status_leds(vehicle_status_s *status, const actuator_armed_s *actuator_armed, bool changed); +void control_status_leds(vehicle_status_s *status_local, const actuator_armed_s *actuator_armed, bool changed, + battery_status_s *battery); void get_circuit_breaker_params(); @@ -1224,10 +1225,6 @@ int commander_thread_main(int argc, char *argv[]) mavlink_and_console_log_critical(&mavlink_log_pub, "ERROR: BUZZER INIT FAIL"); } - if (battery_init() != OK) { - mavlink_and_console_log_critical(&mavlink_log_pub, "ERROR: BATTERY INIT FAIL"); - } - /* vehicle status topic */ memset(&status, 0, sizeof(status)); status.condition_landed = true; // initialize to safe value @@ -1255,10 +1252,6 @@ int commander_thread_main(int argc, char *argv[]) status.offboard_control_signal_lost = true; status.data_link_lost = true; - /* set battery warning flag */ - battery_warning = vehicle_battery_warning::NONE; - status.condition_battery_voltage_valid = false; - // XXX for now just set sensors as initialized status.condition_system_sensors_initialized = true; @@ -1471,7 +1464,7 @@ int commander_thread_main(int argc, char *argv[]) vtol_status.vtol_in_rw_mode = true; //default for vtol is rotary wing - control_status_leds(&status, &armed, true); + control_status_leds(&status, &armed, true, &battery); /* now initialized */ commander_initialized = true; @@ -1967,20 +1960,37 @@ int commander_thread_main(int argc, char *argv[]) if (updated) { orb_copy(ORB_ID(battery_status), battery_sub, &battery); - orb_copy(ORB_ID_VEHICLE_ATTITUDE_CONTROLS, actuator_controls_sub, &actuator_controls); /* only consider battery voltage if system has been running 2s and battery voltage is valid */ - if (hrt_absolute_time() > commander_boot_timestamp + 2000000 && battery.voltage_filtered_v > 0.0f) { - status.battery_voltage = battery.voltage_filtered_v; - status.battery_current = battery.current_a; - status.battery_discharged_mah = battery.discharged_mah; - status.condition_battery_voltage_valid = true; - status.battery_cell_count = battery_get_n_cells(); + if (hrt_absolute_time() > commander_boot_timestamp + 2000000 + && battery.voltage_filtered_v > FLT_EPSILON) { + + /* if battery voltage is getting lower, warn using buzzer, etc. */ + if (battery.warning == battery_status_s::BATTERY_WARNING_LOW && + !low_battery_voltage_actions_done) { + low_battery_voltage_actions_done = true; + if (armed.armed) { + mavlink_log_critical(&mavlink_log_pub, "LOW BATTERY, RETURN TO LAND ADVISED"); + } else { + mavlink_log_critical(&mavlink_log_pub, "LOW BATTERY, TAKEOFF DISCOURAGED"); + } - /* get throttle (if armed), as we only care about energy negative throttle also counts */ - float throttle = (armed.armed) ? fabsf(actuator_controls.control[3]) : 0.0f; - status.battery_remaining = battery_remaining_estimate_voltage(battery.voltage_filtered_v, battery.discharged_mah, - throttle); + } else if (!status.usb_connected && + battery.warning == battery_status_s::BATTERY_WARNING_CRITICAL && + !critical_battery_voltage_actions_done && + low_battery_voltage_actions_done) { + critical_battery_voltage_actions_done = true; + + if (armed.armed) { + mavlink_and_console_log_critical(&mavlink_log_pub, "CRITICAL BATTERY, SHUT SYSTEM DOWN"); + } else { + mavlink_and_console_log_emergency(&mavlink_log_pub, "CRITICAL BATTERY, LAND IMMEDIATELY"); + } + + status_changed = true; + } + + /* End battery voltage check */ } } @@ -2037,34 +2047,6 @@ int commander_thread_main(int argc, char *argv[]) last_idle_time = system_load.tasks[0].total_runtime; } - /* if battery voltage is getting lower, warn using buzzer, etc. */ - if (status.condition_battery_voltage_valid && status.battery_remaining < 0.18f && !low_battery_voltage_actions_done) { - low_battery_voltage_actions_done = true; - if (armed.armed) { - mavlink_log_critical(&mavlink_log_pub, "LOW BATTERY, RETURN TO LAND ADVISED"); - } else { - mavlink_log_critical(&mavlink_log_pub, "LOW BATTERY, TAKEOFF DISCOURAGED"); - } - battery_warning = vehicle_battery_warning::LOW; - status_changed = true; - - } else if (!status.usb_connected && status.condition_battery_voltage_valid && status.battery_remaining < 0.09f - && !critical_battery_voltage_actions_done && low_battery_voltage_actions_done) { - /* critical battery voltage, this is rather an emergency, change state machine */ - critical_battery_voltage_actions_done = true; - battery_warning = vehicle_battery_warning::CRITICAL; - - if (armed.armed) { - mavlink_and_console_log_critical(&mavlink_log_pub, "CRITICAL BATTERY, SHUT SYSTEM DOWN"); - } else { - mavlink_and_console_log_emergency(&mavlink_log_pub, "CRITICAL BATTERY, LAND IMMEDIATELY"); - } - - status_changed = true; - } - - /* End battery voltage check */ - /* If in INIT state, try to proceed to STANDBY state */ if (!status.calibration_enabled && status.arming_state == vehicle_status_s::ARMING_STATE_INIT) { arming_ret = arming_state_transition(&status, @@ -2518,33 +2500,41 @@ int commander_thread_main(int argc, char *argv[]) } } - /* Check engine failure - * only for fixed wing for now - */ - if (!circuit_breaker_engaged_enginefailure_check && - status.is_rotary_wing == false && - armed.armed && - ((actuator_controls.control[3] > ef_throttle_thres && - battery.current_a / actuator_controls.control[3] < - ef_current2throttle_thres) || - (status.engine_failure))) { - /* potential failure, measure time */ - if (timestamp_engine_healthy > 0 && - hrt_elapsed_time(×tamp_engine_healthy) > - ef_time_thres * 1e6 && - !status.engine_failure) { - status.engine_failure = true; - status_changed = true; - mavlink_log_critical(&mavlink_log_pub, "Engine Failure"); - } + /* handle commands last, as the system needs to be updated to handle them */ + orb_check(actuator_controls_sub, &updated); - } else { - /* no failure reset flag */ - timestamp_engine_healthy = hrt_absolute_time(); + if (updated) { + /* got command */ + orb_copy(ORB_ID_VEHICLE_ATTITUDE_CONTROLS, actuator_controls_sub, &actuator_controls); - if (status.engine_failure) { - status.engine_failure = false; - status_changed = true; + /* Check engine failure + * only for fixed wing for now + */ + if (!circuit_breaker_engaged_enginefailure_check && + status.is_rotary_wing == false && + armed.armed && + ((actuator_controls.control[3] > ef_throttle_thres && + battery.current_a / actuator_controls.control[3] < + ef_current2throttle_thres) || + (status.engine_failure))) { + /* potential failure, measure time */ + if (timestamp_engine_healthy > 0 && + hrt_elapsed_time(×tamp_engine_healthy) > + ef_time_thres * 1e6 && + !status.engine_failure) { + status.engine_failure = true; + status_changed = true; + mavlink_log_critical(mavlink_fd, "Engine Failure"); + } + + } else { + /* no failure reset flag */ + timestamp_engine_healthy = hrt_absolute_time(); + + if (status.engine_failure) { + status.engine_failure = false; + status_changed = true; + } } } @@ -2711,12 +2701,12 @@ int commander_thread_main(int argc, char *argv[]) arm_tune_played = true; } else if ((status.hil_state != vehicle_status_s::HIL_STATE_ON) && - battery_warning == vehicle_battery_warning::CRITICAL) { + (battery.warning == battery_status_s::BATTERY_WARNING_CRITICAL)) { /* play tune on battery critical */ set_tune(TONE_BATTERY_WARNING_FAST_TUNE); } else if ((status.hil_state != vehicle_status_s::HIL_STATE_ON) && - (battery_warning == vehicle_battery_warning::LOW || status.failsafe)) { + (battery.warning == battery_status_s::BATTERY_WARNING_LOW)) { /* play tune on battery warning or failsafe */ set_tune(TONE_BATTERY_WARNING_SLOW_TUNE); @@ -2758,12 +2748,12 @@ int commander_thread_main(int argc, char *argv[]) /* blinking LED message, don't touch LEDs */ if (blink_state == 2) { /* blinking LED message completed, restore normal state */ - control_status_leds(&status, &armed, true); + control_status_leds(&status, &armed, true, &battery); } } else { /* normal state */ - control_status_leds(&status, &armed, status_changed); + control_status_leds(&status, &armed, status_changed, &battery); } status_changed = false; @@ -2829,7 +2819,7 @@ check_valid(hrt_abstime timestamp, hrt_abstime timeout, bool valid_in, bool *val } void -control_status_leds(vehicle_status_s *status_local, const actuator_armed_s *actuator_armed, bool changed) +control_status_leds(vehicle_status_s *status_local, const actuator_armed_s *actuator_armed, bool changed, battery_status_s *battery) { /* driving rgbled */ if (changed) { @@ -2862,9 +2852,9 @@ control_status_leds(vehicle_status_s *status_local, const actuator_armed_s *actu /* set color */ if (status_local->failsafe) { rgbled_set_color(RGBLED_COLOR_PURPLE); - } else if (battery_warning == vehicle_battery_warning::LOW) { + } else if (battery->warning == battery_status_s::BATTERY_WARNING_LOW) { rgbled_set_color(RGBLED_COLOR_AMBER); - } else if (battery_warning == vehicle_battery_warning::CRITICAL) { + } else if (battery->warning == battery_status_s::BATTERY_WARNING_CRITICAL) { rgbled_set_color(RGBLED_COLOR_RED); } else { if (status_local->condition_home_position_valid && status_local->condition_global_position_valid) { diff --git a/src/modules/commander/commander_helper.cpp b/src/modules/commander/commander_helper.cpp index 30448594be..758c231320 100644 --- a/src/modules/commander/commander_helper.cpp +++ b/src/modules/commander/commander_helper.cpp @@ -105,30 +105,6 @@ static DevHandle h_leds; static DevHandle h_rgbleds; static DevHandle h_buzzer; -static param_t bat_v_empty_h; -static param_t bat_v_full_h; -static param_t bat_n_cells_h; -static param_t bat_capacity_h; -static param_t bat_v_load_drop_h; -static float bat_v_empty = 3.4f; -static float bat_v_full = 4.2f; -static float bat_v_load_drop = 0.06f; -static int bat_n_cells = 3; -static float bat_capacity = -1.0f; -static unsigned int counter = 0; -static float throttle_lowpassed = 0.0f; - -int battery_init() -{ - bat_v_empty_h = param_find("BAT_V_EMPTY"); - bat_v_full_h = param_find("BAT_V_CHARGED"); - bat_n_cells_h = param_find("BAT_N_CELLS"); - bat_capacity_h = param_find("BAT_CAPACITY"); - bat_v_load_drop_h = param_find("BAT_V_LOAD_DROP"); - - return PX4_OK; -} - int buzzer_init() { tune_end = 0; @@ -346,51 +322,3 @@ void rgbled_set_pattern(rgbled_pattern_t *pattern) h_rgbleds.ioctl(RGBLED_SET_PATTERN, (unsigned long)pattern); } - -unsigned battery_get_n_cells() { - return bat_n_cells; -} - -float battery_remaining_estimate_voltage(float voltage, float discharged, float throttle_normalized) -{ - float ret = 0; - - if (counter % 100 == 0) { - param_get(bat_v_empty_h, &bat_v_empty); - param_get(bat_v_full_h, &bat_v_full); - param_get(bat_v_load_drop_h, &bat_v_load_drop); - param_get(bat_n_cells_h, &bat_n_cells); - param_get(bat_capacity_h, &bat_capacity); - } - - counter++; - - // XXX this time constant needs to become tunable - // but really, the right fix are smart batteries. - float val = throttle_lowpassed * 0.97f + throttle_normalized * 0.03f; - if (PX4_ISFINITE(val)) { - throttle_lowpassed = val; - } - - /* remaining charge estimate based on voltage and internal resistance (drop under load) */ - float bat_v_empty_dynamic = bat_v_empty - (bat_v_load_drop * throttle_lowpassed); - /* the range from full to empty is the same for batteries under load and without load, - * since the voltage drop applies to both the full and empty state - */ - float voltage_range = (bat_v_full - bat_v_empty); - float remaining_voltage = (voltage - (bat_n_cells * bat_v_empty_dynamic)) / (bat_n_cells * voltage_range); - - if (bat_capacity > 0.0f) { - /* if battery capacity is known, use discharged current for estimate, but don't show more than voltage estimate */ - ret = fminf(remaining_voltage, 1.0f - discharged / bat_capacity); - - } else { - /* else use voltage */ - ret = remaining_voltage; - } - - /* limit to sane values */ - ret = (ret < 0.0f) ? 0.0f : ret; - ret = (ret > 1.0f) ? 1.0f : ret; - return ret; -} diff --git a/src/modules/commander/commander_helper.h b/src/modules/commander/commander_helper.h index d2ab41f887..f0f5eb49f3 100644 --- a/src/modules/commander/commander_helper.h +++ b/src/modules/commander/commander_helper.h @@ -77,21 +77,4 @@ void rgbled_set_color(rgbled_color_t color); void rgbled_set_mode(rgbled_mode_t mode); void rgbled_set_pattern(rgbled_pattern_t *pattern); -int battery_init(); - -/** - * Estimate remaining battery charge. - * - * Use integral of current if battery capacity known (BAT_CAPACITY parameter set), - * else use simple estimate based on voltage. - * - * @param voltage the current battery voltage - * @param discharged the discharged capacity - * @param throttle_normalized the normalized throttle magnitude from 0 to 1. Negative throttle should be converted to this range as well, as it consumes energy. - * @return the estimated remaining capacity in 0..1 - */ -float battery_remaining_estimate_voltage(float voltage, float discharged, float throttle_normalized); - -unsigned battery_get_n_cells(); - #endif /* COMMANDER_HELPER_H_ */ diff --git a/src/modules/commander/commander_params.c b/src/modules/commander/commander_params.c index 6a4d409103..e559f80ac1 100644 --- a/src/modules/commander/commander_params.c +++ b/src/modules/commander/commander_params.c @@ -93,87 +93,7 @@ PARAM_DEFINE_FLOAT(TRIM_PITCH, 0.0f); PARAM_DEFINE_FLOAT(TRIM_YAW, 0.0f); /** - * Empty cell voltage. - * - * Defines the voltage where a single cell of the battery is considered empty. - * - * @group Battery Calibration - * @unit V - * @decimal 2 - * @increment 0.01 - */ -PARAM_DEFINE_FLOAT(BAT_V_EMPTY, 3.4f); - -/** - * Full cell voltage. - * - * Defines the voltage where a single cell of the battery is considered full. - * - * @group Battery Calibration - * @unit V - * @decimal 2 - * @increment 0.01 - */ -PARAM_DEFINE_FLOAT(BAT_V_CHARGED, 4.2f); - -/** - * Voltage drop per cell on 100% load - * - * This implicitely defines the internal resistance - * to maximum current ratio and assumes linearity. - * - * @group Battery Calibration - * @unit V - * @min 0.0 - * @max 1.5 - * @decimal 2 - * @increment 0.01 - */ -PARAM_DEFINE_FLOAT(BAT_V_LOAD_DROP, 0.07f); - -/** - * Number of cells. - * - * Defines the number of cells the attached battery consists of. - * - * @group Battery Calibration - * @unit S - * @min 2 - * @max 10 - * @value 2 2S Battery - * @value 3 3S Battery - * @value 4 4S Battery - * @value 5 5S Battery - * @value 6 6S Battery - * @value 7 7S Battery - * @value 8 8S Battery - * @value 9 9S Battery - * @value 10 10S Battery - * @value 11 11S Battery - * @value 12 12S Battery - * @value 13 13S Battery - * @value 14 14S Battery - * @value 15 15S Battery - * @value 16 16S Battery - */ -PARAM_DEFINE_INT32(BAT_N_CELLS, 3); - -/** - * Battery capacity. - * - * Defines the capacity of the attached battery. - * - * @group Battery Calibration - * @unit mA - * @decimal 0 - * @min -1.0 - * @max 100000 - * @increment 50 - */ -PARAM_DEFINE_FLOAT(BAT_CAPACITY, -1.0f); - -/** - * Datalink loss failsafe. + * Datalink loss mode enabled. * * Set to 1 to enable actions triggered when the datalink is lost. * diff --git a/src/modules/gpio_led/gpio_led.c b/src/modules/gpio_led/gpio_led.c index 43ff2e5b87..2fffdcb97e 100644 --- a/src/modules/gpio_led/gpio_led.c +++ b/src/modules/gpio_led/gpio_led.c @@ -51,6 +51,7 @@ #include <systemlib/err.h> #include <uORB/uORB.h> #include <uORB/topics/vehicle_status.h> +#include <uORB/topics/battery_status.h> #include <poll.h> #include <drivers/drv_gpio.h> #include <modules/px4iofirmware/protocol.h> @@ -60,8 +61,10 @@ struct gpio_led_s { int gpio_fd; bool use_io; int pin; - struct vehicle_status_s status; + struct vehicle_status_s vehicle_status; + struct battery_status_s battery_status; int vehicle_status_sub; + int battery_status_sub; bool led_state; int counter; }; @@ -238,11 +241,17 @@ void gpio_led_start(FAR void *arg) ioctl(priv->gpio_fd, GPIO_SET_OUTPUT, priv->pin); /* initialize vehicle status structure */ - memset(&priv->status, 0, sizeof(priv->status)); + memset(&priv->vehicle_status, 0, sizeof(priv->vehicle_status)); + + /* initialize battery status structure */ + memset(&priv->battery_status, 0, sizeof(priv->battery_status)); /* subscribe to vehicle status topic */ priv->vehicle_status_sub = orb_subscribe(ORB_ID(vehicle_status)); + /* subscribe to battery status topic */ + priv->battery_status_sub = orb_subscribe(ORB_ID(battery_status)); + /* add worker to queue */ int ret = work_queue(LPWORK, &priv->work, gpio_led_cycle, priv, 0); @@ -258,32 +267,39 @@ void gpio_led_cycle(FAR void *arg) { FAR struct gpio_led_s *priv = (FAR struct gpio_led_s *)arg; - /* check for status updates*/ + /* check for vehicle status updates*/ bool updated; orb_check(priv->vehicle_status_sub, &updated); if (updated) { - orb_copy(ORB_ID(vehicle_status), priv->vehicle_status_sub, &priv->status); + orb_copy(ORB_ID(vehicle_status), priv->vehicle_status_sub, &priv->vehicle_status); + } + + orb_check(priv->battery_status_sub, &updated); + + if (updated) { + orb_copy(ORB_ID(battery_status), priv->battery_status_sub, &priv->battery_status); } - /* select pattern for current status */ + /* select pattern for current vehiclestatus */ int pattern = 0; - if (priv->status.arming_state == ARMING_STATE_ARMED_ERROR) { + if (priv->vehicle_status.arming_state == ARMING_STATE_ARMED_ERROR) { pattern = 0x2A; // *_*_*_ fast blink (armed, error) - } else if (priv->status.arming_state == ARMING_STATE_ARMED) { - if (priv->status.battery_warning == VEHICLE_BATTERY_WARNING_NONE && !priv->status.failsafe) { + } else if (priv->vehicle_status.arming_state == ARMING_STATE_ARMED) { + if (priv->battery_status.warning == BATTERY_WARNING_NONE + && !priv->vehicle_status.failsafe) { pattern = 0x3f; // ****** solid (armed) } else { pattern = 0x3e; // *****_ slow blink (armed, battery low or failsafe) } - } else if (priv->status.arming_state == ARMING_STATE_STANDBY) { + } else if (priv->vehicle_status.arming_state == ARMING_STATE_STANDBY) { pattern = 0x38; // ***___ slow blink (disarmed, ready) - } else if (priv->status.arming_state == ARMING_STATE_STANDBY_ERROR) { + } else if (priv->vehicle_status.arming_state == ARMING_STATE_STANDBY_ERROR) { pattern = 0x28; // *_*___ slow double blink (disarmed, error) } diff --git a/src/modules/mavlink/mavlink_messages.cpp b/src/modules/mavlink/mavlink_messages.cpp index 8b71547c10..5fcc24690a 100644 --- a/src/modules/mavlink/mavlink_messages.cpp +++ b/src/modules/mavlink/mavlink_messages.cpp @@ -557,6 +557,7 @@ public: private: MavlinkOrbSubscription *_status_sub; + MavlinkOrbSubscription *_battery_status_sub; /* do not allow top copying this class */ MavlinkStreamSysStatus(MavlinkStreamSysStatus &); @@ -564,24 +565,28 @@ private: protected: explicit MavlinkStreamSysStatus(Mavlink *mavlink) : MavlinkStream(mavlink), - _status_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_status))) + _status_sub(_mavlink->add_orb_subscription(ORB_ID(vehicle_status))), + _battery_status_sub(_mavlink->add_orb_subscription(ORB_ID(battery_status))) {} void send(const hrt_abstime t) { struct vehicle_status_s status; + struct battery_status_s battery_status; - if (_status_sub->update(&status)) { + bool updated = _status_sub->update(&status); + updated = (updated || _battery_status_sub->update(&battery_status)); + + if (updated) { mavlink_sys_status_t msg; msg.onboard_control_sensors_present = status.onboard_control_sensors_present; msg.onboard_control_sensors_enabled = status.onboard_control_sensors_enabled; msg.onboard_control_sensors_health = status.onboard_control_sensors_health; msg.load = status.load * 1000.0f; - msg.voltage_battery = status.battery_voltage * 1000.0f; - msg.current_battery = status.battery_current * 100.0f; - msg.battery_remaining = (status.condition_battery_voltage_valid) ? - status.battery_remaining * 100.0f : -1; + msg.voltage_battery = battery_status.voltage_v * 1000.0f; + msg.current_battery = battery_status.current_a * 100.0f; + msg.battery_remaining = battery_status.remaining >= 0 ? battery_status.remaining * 100.0f : -1; // TODO: fill in something useful in the fields below msg.drop_rate_comm = 0; msg.errors_comm = 0; @@ -595,28 +600,19 @@ protected: /* battery status message with higher resolution */ mavlink_battery_status_t bat_msg; bat_msg.id = 0; + bat_msg.id = 0; bat_msg.battery_function = MAV_BATTERY_FUNCTION_ALL; bat_msg.type = MAV_BATTERY_TYPE_LIPO; bat_msg.temperature = INT16_MAX; for (unsigned i = 0; i < (sizeof(bat_msg.voltages) / sizeof(bat_msg.voltages[0])); i++) { - if (i < status.battery_cell_count) { - bat_msg.voltages[i] = (status.battery_voltage / status.battery_cell_count) * 1000.0f; + if (i < battery_status.cell_count) { + bat_msg.voltages[i] = (battery_status.voltage_v / battery_status.cell_count) * 1000.0f; } else { bat_msg.voltages[i] = UINT16_MAX; } } - if (status.condition_battery_voltage_valid) { - bat_msg.current_battery = (bat_msg.current_battery >= 0.0f) ? - status.battery_current * 100.0f : -1; - bat_msg.current_consumed = (bat_msg.current_consumed >= 0.0f) ? - status.battery_discharged_mah : -1; - bat_msg.battery_remaining = status.battery_remaining * 100.0f; - } else { - bat_msg.current_battery = -1.0f; - bat_msg.current_consumed = -1.0f; - bat_msg.battery_remaining = -1.0f; - } + // TODO: calculate this bat_msg.energy_consumed = -1.0f; _mavlink->send_message(MAVLINK_MSG_ID_BATTERY_STATUS, &bat_msg); diff --git a/src/modules/sdlog2/sdlog2.c b/src/modules/sdlog2/sdlog2.c index f6d24fbd30..c89cab2fd4 100644 --- a/src/modules/sdlog2/sdlog2.c +++ b/src/modules/sdlog2/sdlog2.c @@ -1447,8 +1447,6 @@ int sdlog2_thread_main(int argc, char *argv[]) log_msg.body.log_STAT.main_state = buf_status.main_state; log_msg.body.log_STAT.arming_state = buf_status.arming_state; log_msg.body.log_STAT.failsafe = (uint8_t) buf_status.failsafe; - log_msg.body.log_STAT.battery_remaining = buf_status.battery_remaining; - log_msg.body.log_STAT.battery_warning = buf_status.battery_warning; log_msg.body.log_STAT.landed = (uint8_t) buf_status.condition_landed; log_msg.body.log_STAT.load = buf_status.load; LOGBUFFER_WRITE_AND_COUNT(STAT); @@ -1794,6 +1792,18 @@ int sdlog2_thread_main(int argc, char *argv[]) LOGBUFFER_WRITE_AND_COUNT(GPOS); } + /* --- BATTERY --- */ + if (copy_if_updated(ORB_ID(battery_status), &subs.battery_sub, &buf.battery)) { + log_msg.msg_type = LOG_BATT_MSG; + log_msg.body.log_BATT.voltage = buf.battery.voltage_v; + log_msg.body.log_BATT.voltage_filtered = buf.battery.voltage_filtered_v; + log_msg.body.log_BATT.current = buf.battery.current_a; + log_msg.body.log_BATT.discharged = buf.battery.discharged_mah; + log_msg.body.log_BATT.remaining = buf.battery.remaining; + log_msg.body.log_BATT.warning = buf.battery.warning; + LOGBUFFER_WRITE_AND_COUNT(BATT); + } + /* --- GLOBAL POSITION SETPOINT --- */ if (copy_if_updated(ORB_ID(position_setpoint_triplet), &subs.triplet_sub, &buf.triplet)) { diff --git a/src/modules/sdlog2/sdlog2_messages.h b/src/modules/sdlog2/sdlog2_messages.h index 3eec110ac8..5505998400 100644 --- a/src/modules/sdlog2/sdlog2_messages.h +++ b/src/modules/sdlog2/sdlog2_messages.h @@ -180,8 +180,6 @@ struct log_STAT_s { uint8_t main_state; uint8_t arming_state; uint8_t failsafe; - float battery_remaining; - uint8_t battery_warning; uint8_t landed; float load; }; @@ -295,6 +293,8 @@ struct log_BATT_s { float voltage_filtered; float current; float discharged; + float remaining; + uint8_t warning; }; /* --- DIST - RANGE SENSOR DISTANCE --- */ @@ -623,7 +623,7 @@ static const struct log_format_s log_formats[] = { LOG_FORMAT(GPS, "QBffLLfffffBHHH", "GPSTime,Fix,EPH,EPV,Lat,Lon,Alt,VelN,VelE,VelD,Cog,nSat,SNR,N,J"), LOG_FORMAT_S(ATTC, ATTC, "ffff", "Roll,Pitch,Yaw,Thrust"), LOG_FORMAT_S(ATC1, ATTC, "ffff", "Roll,Pitch,Yaw,Thrust"), - LOG_FORMAT(STAT, "BBBfBBf", "MainState,ArmS,Failsafe,BatRem,BatWarn,Landed,Load"), + LOG_FORMAT(STAT, "BBBBf", "MainState,ArmS,Failsafe,Landed,Load"), LOG_FORMAT(VTOL, "fBBB", "Arsp,RwMode,TransMode,Failsafe"), LOG_FORMAT(CTS, "fffffff", "Vx_b,Vy_b,Vz_b,Vinf,P,Q,R"), LOG_FORMAT(RC, "ffffffffffffBBBL", "C0,C1,C2,C3,C4,C5,C6,C7,C8,C9,C10,C11,RSSI,CNT,Lost,Drop"), @@ -636,7 +636,7 @@ static const struct log_format_s log_formats[] = { LOG_FORMAT(GPSP, "BLLffBfbf", "NavState,Lat,Lon,Alt,Yaw,Type,LoitR,LoitDir,PitMin"), LOG_FORMAT(ESC, "HBBBHHffiffH", "count,nESC,Conn,N,Ver,Adr,Volt,Amp,RPM,Temp,SetP,SetPRAW"), LOG_FORMAT(GVSP, "fff", "VX,VY,VZ"), - LOG_FORMAT(BATT, "ffff", "V,VFilt,C,Discharged"), + LOG_FORMAT(BATT, "fffffB", "V,VFilt,C,Discharged,Remaining,Warning"), LOG_FORMAT(DIST, "BBBff", "Id,Type,Orientation,Distance,Covariance"), LOG_FORMAT_S(TEL0, TEL, "BBBBHHBQ", "RSSI,RemRSSI,Noise,RemNoise,RXErr,Fixed,TXBuf,HbTime"), LOG_FORMAT_S(TEL1, TEL, "BBBBHHBQ", "RSSI,RemRSSI,Noise,RemNoise,RXErr,Fixed,TXBuf,HbTime"), diff --git a/src/modules/sensors/sensors.cpp b/src/modules/sensors/sensors.cpp index 5cb035ff9c..31c7211f7e 100644 --- a/src/modules/sensors/sensors.cpp +++ b/src/modules/sensors/sensors.cpp @@ -83,6 +83,7 @@ #include <systemlib/param/param.h> #include <systemlib/err.h> #include <systemlib/perf_counter.h> +#include <systemlib/battery.h> #include <conversion/rotation.h> #include <systemlib/airspeed.h> @@ -128,9 +129,6 @@ using namespace DriverFramework; */ -#define BATT_V_LOWPASS 0.001f -#define BATT_V_IGNORE_THRESHOLD 2.1f - /** * HACK - true temperature is much less than indicated temperature in baro, * subtract 5 degrees in an attempt to account for the electrical upheating of the PCB @@ -257,6 +255,8 @@ private: uint64_t _battery_discharged; /**< battery discharged current in mA*ms */ hrt_abstime _battery_current_timestamp; /**< timestamp of last battery current reading */ + Battery _battery; /**< Helper lib to publish battery_status topic. */ + struct { float min[_rc_max_chan_count]; float trim[_rc_max_chan_count]; @@ -1518,6 +1518,7 @@ Sensors::parameter_update_poll(bool forced) /* do not output this for now, as its covered in preflight checks */ // warnx("valid configs: %u gyros, %u mags, %u accels", gyro_count, mag_count, accel_count); + _battery.updateParams(); } } @@ -1644,6 +1645,10 @@ Sensors::adc_poll(struct sensor_combined_s &raw) /* read all channels available */ int ret = _h_adc.read(&buf_adc, sizeof(buf_adc)); + float bat_voltage_v = 0.0f; + float bat_current_a = 0.0f; + bool updated_battery = false; + if (ret >= (int)sizeof(buf_adc[0])) { /* Read add channels we got */ @@ -1657,48 +1662,12 @@ Sensors::adc_poll(struct sensor_combined_s &raw) /* look for specific channels and process the raw voltage to measurement data */ if (ADC_BATTERY_VOLTAGE_CHANNEL == buf_adc[i].am_channel) { /* Voltage in volts */ - float voltage = (buf_adc[i].am_data * _parameters.battery_voltage_scaling); - - if (voltage > BATT_V_IGNORE_THRESHOLD) { - _battery_status.voltage_v = voltage; - - /* one-time initialization of low-pass value to avoid long init delays */ - if (_battery_status.voltage_filtered_v < BATT_V_IGNORE_THRESHOLD) { - _battery_status.voltage_filtered_v = voltage; - } - - _battery_status.timestamp = t; - _battery_status.voltage_filtered_v += (voltage - _battery_status.voltage_filtered_v) * BATT_V_LOWPASS; - - } else { - /* mark status as invalid */ - _battery_status.voltage_v = -1.0f; - _battery_status.voltage_filtered_v = -1.0f; - } + bat_voltage_v = (buf_adc[i].am_data * _parameters.battery_voltage_scaling); + updated_battery = true; } else if (ADC_BATTERY_CURRENT_CHANNEL == buf_adc[i].am_channel) { - /* handle current only if voltage is valid */ - if (_battery_status.voltage_v > 0.0f) { - float current = ((buf_adc[i].am_data - _parameters.battery_current_offset) * _parameters.battery_current_scaling); - - /* check measured current value */ - if (current >= 0.0f) { - _battery_status.timestamp = t; - _battery_status.current_a = current; - - if (_battery_current_timestamp != 0) { - /* initialize discharged value */ - if (_battery_status.discharged_mah < 0.0f) { - _battery_status.discharged_mah = 0.0f; - } - - _battery_discharged += current * (t - _battery_current_timestamp); - _battery_status.discharged_mah = ((float) _battery_discharged) / 3600000.0f; - } - } - } - - _battery_current_timestamp = t; + bat_current_a = (buf_adc[i].am_data * _parameters.battery_current_scaling); + updated_battery = true; #ifdef ADC_AIRSPEED_VOLTAGE_CHANNEL @@ -1735,16 +1704,21 @@ Sensors::adc_poll(struct sensor_combined_s &raw) } } + if (updated_battery) { + // XXX TODO: throttle is hardcoded here. The dependency to throttle would need to be + // removed, or it needs to be subscribed to actuator controls. + const float throttle = 0.0f; + _battery.updateBatteryStatus(t, bat_voltage_v, bat_current_a, throttle, &_battery_status); + } + _last_adc = t; - if (_battery_status.voltage_filtered_v > BATT_V_IGNORE_THRESHOLD) { - /* announce the battery status if needed, just publish else */ - if (_battery_pub != nullptr) { - orb_publish(ORB_ID(battery_status), _battery_pub, &_battery_status); + /* announce the battery status if needed, just publish else */ + if (_battery_pub != nullptr) { + orb_publish(ORB_ID(battery_status), _battery_pub, &_battery_status); - } else { - _battery_pub = orb_advertise(ORB_ID(battery_status), &_battery_status); - } + } else { + _battery_pub = orb_advertise(ORB_ID(battery_status), &_battery_status); } } } @@ -2158,11 +2132,7 @@ Sensors::task_main() raw.adc_voltage_v[2] = 0.0f; raw.adc_voltage_v[3] = 0.0f; - memset(&_battery_status, 0, sizeof(_battery_status)); - _battery_status.voltage_v = -1.0f; - _battery_status.voltage_filtered_v = -1.0f; - _battery_status.current_a = -1.0f; - _battery_status.discharged_mah = -1.0f; + _battery.reset(&_battery_status); /* get a set of initial values */ accel_poll(raw); diff --git a/src/modules/systemlib/CMakeLists.txt b/src/modules/systemlib/CMakeLists.txt index 25f7d26a50..4507974e85 100644 --- a/src/modules/systemlib/CMakeLists.txt +++ b/src/modules/systemlib/CMakeLists.txt @@ -48,6 +48,7 @@ set(SRCS mcu_version.c bson/tinybson.c circuit_breaker.cpp + battery.cpp ) if(${OS} STREQUAL "nuttx") @@ -55,7 +56,7 @@ if(${OS} STREQUAL "nuttx") err.c printload.c param/param.c - up_cxxinitialize.c + up_cxxinitialize.c ) elseif ("${CONFIG_SHMEM}" STREQUAL "1") list(APPEND SRCS @@ -66,7 +67,7 @@ else() list(APPEND SRCS param/param.c print_load_posix.c - ) + ) endif() if(NOT ${OS} STREQUAL "qurt") @@ -85,4 +86,4 @@ px4_add_module( platforms__common modules__param ) -# vim: set noet ft=cmake fenc=utf-8 ff=unix : +# vim: set noet ft=cmake fenc=utf-8 ff=unix : diff --git a/src/modules/systemlib/battery.cpp b/src/modules/systemlib/battery.cpp new file mode 100644 index 0000000000..91b08812bb --- /dev/null +++ b/src/modules/systemlib/battery.cpp @@ -0,0 +1,162 @@ +/**************************************************************************** + * + * Copyright (c) 2016 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file battery.cpp + * + * Library calls for battery functionality. + * + * @author Julian Oes <julian@oes.ch> + */ + +#include "battery.h" + +Battery::Battery() : + SuperBlock(NULL, NULL), + _param_v_empty(this, "BAT_V_EMPTY", false), + _param_v_full(this, "BAT_V_CHARGED", false), + _param_n_cells(this, "BAT_N_CELLS", false), + _param_capacity(this, "BAT_CAPACITY", false), + _param_v_load_drop(this, "BAT_V_LOAD_DROP", false), + _voltage_filtered_v(0.0f), + _throttle_filtered(0.0f), + _discharged_mah(0.0f), + _remaining(1.0f), + _warning(battery_status_s::BATTERY_WARNING_NONE), + _last_timestamp(0) +{ + /* load initial params */ + updateParams(); +} + +Battery::~Battery() +{ +} + +void +Battery::reset(battery_status_s *battery_status) +{ + battery_status->voltage_v = 0.0f; + battery_status->voltage_filtered_v = 0.0f; + battery_status->current_a = -1.0f; + battery_status->discharged_mah = -1.0f; + battery_status->cell_count = _param_n_cells.get(); + // TODO: check if it is sane to reset warning to NONE + battery_status->warning = battery_status_s::BATTERY_WARNING_NONE; +} + +void +Battery::updateBatteryStatus(hrt_abstime timestamp, float voltage_v, float current_a, float throttle_normalized, + battery_status_s *battery_status) +{ + filterVoltage(voltage_v); + sumDischarged(timestamp, current_a); + estimateRemaining(voltage_v, throttle_normalized); + determineWarning(); + + if (_voltage_filtered_v > 2.1f) { + battery_status->voltage_v = voltage_v; + battery_status->voltage_filtered_v = _voltage_filtered_v; + battery_status->current_a = current_a; + battery_status->discharged_mah = _discharged_mah; + battery_status->cell_count = _param_n_cells.get(); + battery_status->warning = _warning; + } else { + reset(battery_status); + } +} + +void +Battery::filterVoltage(float voltage_v) +{ + // TODO: inspect that filter performance + const float filtered_next = _voltage_filtered_v * 0.999f + voltage_v * 0.001f; + if (PX4_ISFINITE(filtered_next)) { + _voltage_filtered_v = filtered_next; + } +} + +void +Battery::sumDischarged(hrt_abstime timestamp, float current_a) +{ + // Ignore first update because we don't know dT. + if (_last_timestamp != 0) { + _discharged_mah = current_a * (timestamp - _last_timestamp) * 1.0e-3f / 3600.0f; + } + _last_timestamp = timestamp; +} + +void +Battery::estimateRemaining(float voltage_v, float throttle_normalized) +{ + // XXX this time constant needs to become tunable but really, the right fix are smart batteries. + const float filtered_next = _throttle_filtered * 0.97f + throttle_normalized * 0.03f; + + if (PX4_ISFINITE(filtered_next)) { + _throttle_filtered = filtered_next; + } + + /* remaining charge estimate based on voltage and internal resistance (drop under load) */ + const float bat_v_empty_dynamic = _param_v_empty.get() - (_param_v_load_drop.get() * _throttle_filtered); + /* the range from full to empty is the same for batteries under load and without load, + * since the voltage drop applies to both the full and empty state + */ + const float voltage_range = (_param_v_full.get() - _param_v_empty.get()); + const float remaining_voltage = (voltage_v - (_param_n_cells.get() * bat_v_empty_dynamic)) + / (_param_n_cells.get() * voltage_range); + + if (_param_capacity.get() > 0.0f) { + /* if battery capacity is known, use discharged current for estimate, but don't show more than voltage estimate */ + _remaining = fminf(remaining_voltage, 1.0f - _discharged_mah / _param_capacity.get()); + + } else { + /* else use voltage */ + _remaining = remaining_voltage; + } + + /* limit to sane values */ + _remaining = (_remaining < 0.0f) ? 0.0f : _remaining; + _remaining = (_remaining > 1.0f) ? 1.0f : _remaining; +} + +void +Battery::determineWarning() +{ + // TODO: Determine threshold or make params. + if (_remaining < 0.18f) { + _warning = battery_status_s::BATTERY_WARNING_LOW; + + } else if (_remaining < 0.09f) { + _warning = battery_status_s::BATTERY_WARNING_CRITICAL; + } +} diff --git a/src/modules/systemlib/battery.h b/src/modules/systemlib/battery.h new file mode 100644 index 0000000000..e85c19b775 --- /dev/null +++ b/src/modules/systemlib/battery.h @@ -0,0 +1,97 @@ +/**************************************************************************** + * + * Copyright (c) 2016 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file battery.h + * + * Library calls for battery functionality. + * + * @author Julian Oes <julian@oes.ch> + */ + +#pragma once + +#include <controllib/blocks.hpp> +#include <controllib/block/BlockParam.hpp> +#include <uORB/topics/battery_status.h> +#include <drivers/drv_hrt.h> + + +class Battery : public control::SuperBlock +{ +public: + /** + * Constructor + */ + Battery(); + + /** + * Destructor + */ + ~Battery(); + + /** + * Reset all battery stats and report invalid/nothing. + */ + void reset(battery_status_s *battery_status); + + /** + * Update current battery status message. + * + * @param voltage_v: current voltage in V + * @param current_a: current current in A + * @param throttle_normalized: throttle from 0 to 1 + */ + void updateBatteryStatus(hrt_abstime timestamp, float voltage_v, float current_a, float throttle_normalized, + battery_status_s *status); + +private: + void filterVoltage(float voltage_v); + void sumDischarged(hrt_abstime timestamp, float current_a); + void estimateRemaining(float voltage_v, float throttle_normalized); + void determineWarning(); + + control::BlockParamFloat _param_v_empty; + control::BlockParamFloat _param_v_full; + control::BlockParamFloat _param_n_cells; + control::BlockParamFloat _param_capacity; + control::BlockParamFloat _param_v_load_drop; + + float _voltage_filtered_v; + float _throttle_filtered; + float _discharged_mah; + float _remaining; + uint8_t _warning; + hrt_abstime _last_timestamp; +}; + diff --git a/src/modules/systemlib/battery_params.c b/src/modules/systemlib/battery_params.c new file mode 100644 index 0000000000..bc7bb77347 --- /dev/null +++ b/src/modules/systemlib/battery_params.c @@ -0,0 +1,123 @@ +/**************************************************************************** + * + * Copyright (c) 2013-2016 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file battery_params.c + * + * Parameters defined by the battery lib. + * + * @author Julian Oes <julian@oes.ch> + */ + +#include <px4_config.h> +#include <systemlib/param/param.h> + +/** + * Empty cell voltage. + * + * Defines the voltage where a single cell of the battery is considered empty. + * + * @group Battery Calibration + * @unit V + * @decimal 2 + * @increment 0.01 + */ +PARAM_DEFINE_FLOAT(BAT_V_EMPTY, 3.4f); + +/** + * Full cell voltage. + * + * Defines the voltage where a single cell of the battery is considered full. + * + * @group Battery Calibration + * @unit V + * @decimal 2 + * @increment 0.01 + */ +PARAM_DEFINE_FLOAT(BAT_V_CHARGED, 4.2f); + +/** + * Voltage drop per cell on 100% load + * + * This implicitely defines the internal resistance + * to maximum current ratio and assumes linearity. + * + * @group Battery Calibration + * @unit V + * @min 0.0 + * @max 1.5 + * @decimal 2 + * @increment 0.01 + */ +PARAM_DEFINE_FLOAT(BAT_V_LOAD_DROP, 0.07f); + +/** + * Number of cells. + * + * Defines the number of cells the attached battery consists of. + * + * @group Battery Calibration + * @unit S + * @min 2 + * @max 10 + * @value 2 2S Battery + * @value 3 3S Battery + * @value 4 4S Battery + * @value 5 5S Battery + * @value 6 6S Battery + * @value 7 7S Battery + * @value 8 8S Battery + * @value 9 9S Battery + * @value 10 10S Battery + * @value 11 11S Battery + * @value 12 12S Battery + * @value 13 13S Battery + * @value 14 14S Battery + * @value 15 15S Battery + * @value 16 16S Battery + */ +PARAM_DEFINE_INT32(BAT_N_CELLS, 3); + +/** + * Battery capacity. + * + * Defines the capacity of the attached battery. + * + * @group Battery Calibration + * @unit mA + * @decimal 0 + * @min -1.0 + * @max 100000 + * @increment 50 + */ +PARAM_DEFINE_FLOAT(BAT_CAPACITY, -1.0f); -- GitLab