diff --git a/CHANGELOG.md b/CHANGELOG.md index 33e84795..c1098605 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Please add a note of your changes below this heading if you make a Pull Request. ### Added +* `dump_errors()` utility function in odrivetool to dump, decode and optionally clear errors. * Second order setpoint input filter. ### Changed diff --git a/Firmware/MotorControl/encoder.cpp b/Firmware/MotorControl/encoder.cpp index 8c0691f8..9b964f21 100644 --- a/Firmware/MotorControl/encoder.cpp +++ b/Firmware/MotorControl/encoder.cpp @@ -271,8 +271,10 @@ bool Encoder::update() { if (delta_enc > 3) delta_enc -= 6; } else { - set_error(ERROR_ILLEGAL_HALL_STATE); - return false; + if (!config_.ignore_illegal_hall_state) { + set_error(ERROR_ILLEGAL_HALL_STATE); + return false; + } } } break; diff --git a/Firmware/MotorControl/encoder.hpp b/Firmware/MotorControl/encoder.hpp index 78f8f4f6..96e1a914 100644 --- a/Firmware/MotorControl/encoder.hpp +++ b/Firmware/MotorControl/encoder.hpp @@ -37,6 +37,7 @@ public: float offset_float = 0.0f; // Sub-count phase alignment offset float calib_range = 0.02f; float bandwidth = 1000.0f; + bool ignore_illegal_hall_state = false; }; Encoder(const EncoderHardwareConfig_t& hw_config, @@ -106,7 +107,8 @@ public: make_protocol_property("offset_float", &config_.offset_float), make_protocol_property("bandwidth", &config_.bandwidth, [](void* ctx) { static_cast(ctx)->update_pll_gains(); }, this), - make_protocol_property("calib_range", &config_.calib_range) + make_protocol_property("calib_range", &config_.calib_range), + make_protocol_property("ignore_illegal_hall_state", &config_.ignore_illegal_hall_state) ) ); } diff --git a/Firmware/MotorControl/low_level.cpp b/Firmware/MotorControl/low_level.cpp index b40b3274..e8fe62a4 100644 --- a/Firmware/MotorControl/low_level.cpp +++ b/Firmware/MotorControl/low_level.cpp @@ -713,4 +713,33 @@ void pwm_in_cb(int channel, uint32_t timestamp) { last_timestamp[gpio_num - 1] = timestamp; last_pin_state[gpio_num - 1] = current_pin_state; last_sample_valid[gpio_num - 1] = true; -} \ No newline at end of file +} + + +/* Analog speed control input */ + +static void update_analog_endpoint(const struct PWMMapping_t *map, int gpio) +{ + float fraction = get_adc_voltage(get_gpio_port_by_pin(gpio), get_gpio_pin_by_pin(gpio)) / 3.3f; + float value = map->min + (fraction * (map->max - map->min)); + get_endpoint(map->endpoint)->set_from_float(value); +} + +static void analog_polling_thread(void *) +{ + while (true) { + for (int i = 0; i < GPIO_COUNT; i++) { + struct PWMMapping_t *map = &board_config.analog_mappings[i]; + + if (is_endpoint_ref_valid(map->endpoint)) + update_analog_endpoint(map, i + 1); + } + osDelay(10); + } +} + +void start_analog_thread() +{ + osThreadDef(thread_def, analog_polling_thread, osPriorityLow, 0, 4*512); + osThreadCreate(osThread(thread_def), NULL); +} diff --git a/Firmware/MotorControl/low_level.h b/Firmware/MotorControl/low_level.h index 3a3225de..503b98e1 100644 --- a/Firmware/MotorControl/low_level.h +++ b/Firmware/MotorControl/low_level.h @@ -51,6 +51,7 @@ void sync_timers(TIM_HandleTypeDef* htim_a, TIM_HandleTypeDef* htim_b, void start_general_purpose_adc(); float get_adc_voltage(GPIO_TypeDef* GPIO_port, uint16_t GPIO_pin); void pwm_in_init(); +void start_analog_thread(); void update_brake_current(); diff --git a/Firmware/MotorControl/main.cpp b/Firmware/MotorControl/main.cpp index 4146850c..b25da149 100644 --- a/Firmware/MotorControl/main.cpp +++ b/Firmware/MotorControl/main.cpp @@ -214,6 +214,8 @@ int odrive_main(void) { axes[i]->start_thread(); } + start_analog_thread(); + system_stats_.fully_booted = true; return 0; } diff --git a/Firmware/MotorControl/odrive_main.h b/Firmware/MotorControl/odrive_main.h index 776f1590..df1bc14b 100644 --- a/Firmware/MotorControl/odrive_main.h +++ b/Firmware/MotorControl/odrive_main.h @@ -82,6 +82,7 @@ struct BoardConfig_t { //make_protocol_definitions()), make_protocol_object("axis1", axes[1]->make_protocol_definitions()), make_protocol_object("can", can1_ctx.make_protocol_definitions()), diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index c05c7f92..c5556d02 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -14,21 +14,9 @@ Table of Contents: ## Error codes -If your ODrive is not working as expected, run `odrivetool` and type `hex(.error)` Enter where `` is the axis that isn't working. This will display a [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) representation of the error code. Each bit represents one error flag. - -
Example
-Say you got this error output: -```python -In [1]: hex(odrv0.axis0.error) -Out[1]: '0x6' -``` - -Written in binary, the number `0x6` corresponds to `110`, that means bits 1 and 2 are set (counting starts at 0). -Looking at the reference below, this means that both `ERROR_DC_BUS_UNDER_VOLTAGE` and `ERROR_DC_BUS_OVER_VOLTAGE` occurred. -
- -The axis error may say that some other component has failed. Say it reports `ERROR_ENCODER_FAILED`, then you need to go check the encoder error: `hex(.encoder.error)`. +If your ODrive is not working as expected, run `odrivetool` and type `dump_errors(odrv0)` Enter. This will dump a list of all the errors that are present. To also clear all the errors, you can run `dump_errors(odrv0, True)`. +The following sections will give some guidance on the most common errors. You may also check the code for the full list of errors: * Axis error flags defined [here](../Firmware/MotorControl/axis.hpp). * Motor error flags defined [here](../Firmware/MotorControl/motor.hpp). * Encoder error flags defined [here](../Firmware/MotorControl/encoder.hpp). diff --git a/tools/odrive/enums.py b/tools/odrive/enums.py index 038b77cc..b82d180c 100644 --- a/tools/odrive/enums.py +++ b/tools/odrive/enums.py @@ -11,17 +11,47 @@ AXIS_STATE_ENCODER_INDEX_SEARCH = 6 AXIS_STATE_ENCODER_OFFSET_CALIBRATION = 7 AXIS_STATE_CLOSED_LOOP_CONTROL = 8 -AXIS_ERROR_NONE = 0 -AXIS_ERROR_INVALID_STATE = 1 -#AXIS_ERROR_DC_BUS_UNDER_VOLTAGE = 2 -#AXIS_ERROR_DC_BUS_OVER_VOLTAGE = 3 -#AXIS_ERROR_CURRENT_MEASUREMENT_TIMEOUT = 4 -#AXIS_ERROR_CONTROL_LOOP_TIMEOUT = 5 -#AXIS_ERROR_MOTOR_FAILED = 6 -#AXIS_ERROR_SENSORLESS_ESTIMATOR_FAILED = 7 -#AXIS_ERROR_ENCODER_FAILED = 8 -#AXIS_ERROR_CONTROLLER_FAILED = 9 -#AXIS_ERROR_POS_CTRL_DURING_SENSORLESS = 10 +class errors: + class axis: + ERROR_NONE = 0x00 + ERROR_INVALID_STATE = 0x01 #