From df4b0df39969131a7bff9fcd53a8871c1d3d2eb6 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Wed, 3 Jun 2020 10:20:29 -0700 Subject: [PATCH 01/48] Update default.html --- docs/_layouts/default.html | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 9be4b36e..31e0f9d0 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -13,6 +13,7 @@ +
Firmware version v0.5.0 is coming soon. To help beta test it now, please check it out on GitHub.
From e1ef30b4f65afe07d373b2e392cd056abd5bd606 Mon Sep 17 00:00:00 2001 From: samuelsadok Date: Thu, 11 Jun 2020 14:31:45 +0200 Subject: [PATCH 02/48] Update odrivetool.md --- docs/odrivetool.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/odrivetool.md b/docs/odrivetool.md index dddd5ea1..f2e54a91 100644 --- a/docs/odrivetool.md +++ b/docs/odrivetool.md @@ -85,11 +85,12 @@ To compile firmware from source, refer to the [developer guide](developer-guide) ### Troubleshooting * __Windows__: During the update, a new device called "STM32 BOOTLOADER" will appear. Open the [Zadig utility](http://zadig.akeo.ie/) and set the driver for "STM32 BOOTLOADER" to libusb-win32. After that the firmware update will continue. +* __Linux__: Try running `sudo odrivetool dfu` instead of `odrivetool dfu`. * On some machines you will need to unplug and plug back in the USB cable to make the PC understand that we switched from regular mode to bootloader mode. * If the DFU script can't find the device, try forcing it into DFU mode.
How to force DFU mode (ODrive v3.5 and newer)
- Flick the DIP switch that "DFU, RUN" to "DFU" and power cycle the board. After you're done upgrading firmware, don't forget to put the switch back into the "RUN" position and power cycle the board again. + Flick the DIP switch that says "DFU, RUN" to "DFU" and power cycle the board. If that alone doesn't work, also connect the pin "GPIO6" to "GND". After you're done upgrading firmware, don't forget to put the switch back into the "RUN" position and power cycle the board again.
How to force DFU mode (ODrive v3.1, v3.2)
From 306000f46e5d04f21177ee05fcd11469e5282295 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Wed, 1 Jul 2020 20:18:49 -0700 Subject: [PATCH 03/48] Update hoverboard.md --- docs/hoverboard.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hoverboard.md b/docs/hoverboard.md index 730391fd..8bf90eb4 100644 --- a/docs/hoverboard.md +++ b/docs/hoverboard.md @@ -95,7 +95,7 @@ Check the status of the encoder object: odrv0.axis0.encoder ``` -Check that there are no errors. If your hall sensors has a standard timing angle then `offset_float` should be close to 0.5. +Check that there are no errors. If your hall sensors has a standard timing angle then `offset_float` should be close to 0.5 or 1.5. ```txt error = 0x0000 (int) offset_float = 0.5126956701278687 (float) From f93926112020d85004efeef93a288312fda36f7d Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 4 Aug 2020 14:26:50 -0700 Subject: [PATCH 04/48] Update commands.md --- docs/commands.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/commands.md b/docs/commands.md index 1dce7336..d5b65249 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -60,7 +60,7 @@ Possible values are: * `CTRL_MODE_CURRENT_CONTROL` * `CTRL_MODE_VOLTAGE_CONTROL` - this one is not normally used. -# Control Commands +### Control Commands * `.controller.pos_setpoint = ` * `.controller.vel_setpoint = ` * `.controller.current_setpoint = ` From 2aa641ee86327fdcf9e17bb48169b478e0311a1f Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Tue, 4 Aug 2020 22:35:55 -0400 Subject: [PATCH 05/48] Updated banner for new RC --- docs/_layouts/default.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 31e0f9d0..798c19f1 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -13,7 +13,7 @@ -
Firmware version v0.5.0 is coming soon. To help beta test it now, please check it out on GitHub.
+
Firmware version v0.5.1 is coming soon. To help beta test it now, please check it out on GitHub.
From 315fbce32ca20b0cbd5a6633971a6138d07cb3a6 Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Tue, 4 Aug 2020 23:10:02 -0400 Subject: [PATCH 06/48] Docs banner link now points to discourse topic instead of directly to github --- docs/_layouts/default.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 798c19f1..b15ab603 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -13,7 +13,7 @@ -
Firmware version v0.5.1 is coming soon. To help beta test it now, please check it out on GitHub.
+
Firmware version v0.5.1 is coming soon. To help beta test it now, please check it out on GitHub.
From 0250378a9930426aee08625dc6d2a4c3a5678b7f Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Tue, 4 Aug 2020 23:13:24 -0400 Subject: [PATCH 07/48] Revert "Docs banner link now points to discourse topic instead of directly to github" This reverts commit 315fbce32ca20b0cbd5a6633971a6138d07cb3a6. revert link change --- docs/_layouts/default.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index b15ab603..798c19f1 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -13,7 +13,7 @@ -
Firmware version v0.5.1 is coming soon. To help beta test it now, please check it out on GitHub.
+
Firmware version v0.5.1 is coming soon. To help beta test it now, please check it out on GitHub.
From 6050d9b3fb881c8fe0a65d03fafc3f7bfae84664 Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Tue, 4 Aug 2020 23:17:40 -0400 Subject: [PATCH 08/48] Docs banner link updated to point towards discourse thread --- docs/_layouts/default.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 798c19f1..809a739b 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -13,7 +13,7 @@ -
Firmware version v0.5.1 is coming soon. To help beta test it now, please check it out on GitHub.
+
Firmware version v0.5.1 is coming soon. To help beta test it now, please check it out.
From 5b8b7359ce0d70568207ebfb7c1970112a355971 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sun, 9 Aug 2020 17:55:33 -0700 Subject: [PATCH 09/48] Update getting-started.md --- docs/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 909a245d..497f01b9 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -230,7 +230,7 @@ Due to a [known issue](https://github.com/madcowswe/ODrive/issues/183) it is str ## Position control of M0 -Let's get motor 0 up and running. The procedure for motor 1 is exactly the same, so feel free to substitute `axis0` wherever it says `axis0`. +Let's get motor 0 up and running. The procedure for motor 1 is exactly the same, so feel free to substitute `axis1` wherever it says `axis0`. 1. Type `odrv0.axis0.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE` Enter. After about 2 seconds should hear a beep. Then the motor will turn slowly in one direction for a few seconds, then back in the other direction. From 58bc55d835b65c52db40913adce4dacf01496f0f Mon Sep 17 00:00:00 2001 From: Paul Guenette Date: Thu, 13 Aug 2020 21:48:41 -0400 Subject: [PATCH 10/48] Add info about current_control_bandwidth --- docs/control.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/control.md b/docs/control.md index 8af90a91..d75a35e1 100644 --- a/docs/control.md +++ b/docs/control.md @@ -29,6 +29,8 @@ voltage_integral += current_error * current_integrator_gain voltage_cmd = current_error * current_gain + voltage_integral (+ voltage_feedforward when we have motor model) ``` +`current_gain` and `current_integrator_gain` are automatically set according to the `motor.config.current_control_bandwidth` and the measured `phase_resistance` and `phase_inductance` to produce (theoretically) a critically-damped controller at the given bandwidth (in rad/s). + For more detail refer to [controller.cpp](https://github.com/madcowswe/ODrive/blob/master/Firmware/MotorControl/controller.cpp#L86). ## Tuning Tuning the motor controller is an essential step to unlock the full potential of the ODrive. Tuning allows for the controller to quickly respond to disturbances or changes in the system (such as an external force being applied or a change in the setpoint) without becoming unstable. Correctly setting the three tuning parameters (called gains) ensures that ODrive can control your motors in the most effective way possible. The three values are: From ffbeaed61b74cb23c522681b062a0337c601330d Mon Sep 17 00:00:00 2001 From: Paul Guenette Date: Thu, 13 Aug 2020 21:50:18 -0400 Subject: [PATCH 11/48] Update control.md --- docs/control.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/control.md b/docs/control.md index d75a35e1..84319103 100644 --- a/docs/control.md +++ b/docs/control.md @@ -29,7 +29,7 @@ voltage_integral += current_error * current_integrator_gain voltage_cmd = current_error * current_gain + voltage_integral (+ voltage_feedforward when we have motor model) ``` -`current_gain` and `current_integrator_gain` are automatically set according to the `motor.config.current_control_bandwidth` and the measured `phase_resistance` and `phase_inductance` to produce (theoretically) a critically-damped controller at the given bandwidth (in rad/s). +Note: `current_gain` and `current_integrator_gain` are automatically set according to `motor.config.current_control_bandwidth` For more detail refer to [controller.cpp](https://github.com/madcowswe/ODrive/blob/master/Firmware/MotorControl/controller.cpp#L86). ## Tuning From 43cb91b3b1d257a13a5770b44de92ed0064f8d69 Mon Sep 17 00:00:00 2001 From: Shaun Meehan Date: Tue, 18 Aug 2020 23:37:44 -0700 Subject: [PATCH 12/48] Mechanical Brake feature --- Firmware/MotorControl/axis.cpp | 8 ++- Firmware/MotorControl/axis.hpp | 4 +- Firmware/MotorControl/main.cpp | 9 ++- Firmware/MotorControl/mechanical_brake.cpp | 41 ++++++++++++++ Firmware/MotorControl/mechanical_brake.hpp | 36 ++++++++++++ Firmware/MotorControl/odrive_main.h | 1 + Firmware/Tupfile.lua | 1 + Firmware/odrive-interface.yaml | 12 +++- docs/_data/index.yaml | 2 + docs/mechanical-brakes.md | 66 ++++++++++++++++++++++ 10 files changed, 176 insertions(+), 4 deletions(-) create mode 100644 Firmware/MotorControl/mechanical_brake.cpp create mode 100644 Firmware/MotorControl/mechanical_brake.hpp create mode 100644 docs/mechanical-brakes.md diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index f5771cd2..96df5ab0 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -19,7 +19,8 @@ Axis::Axis(int axis_num, Motor& motor, TrapezoidalTrajectory& trap, Endstop& min_endstop, - Endstop& max_endstop) + Endstop& max_endstop, + MechanicalBrake& mechanical_brake) : axis_num_(axis_num), hw_config_(hw_config), config_(config), @@ -32,6 +33,7 @@ Axis::Axis(int axis_num, trap_traj_(trap), min_endstop_(min_endstop), max_endstop_(max_endstop), + mechanical_brake_(mechanical_brake), current_limiters_(make_array( static_cast(&fet_thermistor), static_cast(&motor_thermistor))), @@ -48,6 +50,7 @@ Axis::Axis(int axis_num, trap_traj_.axis_ = this; min_endstop_.axis_ = this; max_endstop_.axis_ = this; + mechanical_brake_.axis_ = this; decode_step_dir_pins(); watchdog_feed(); } @@ -462,6 +465,7 @@ bool Axis::run_idle_loop() { // run_control_loop ignores missed modulation timing updates // if and only if we're in AXIS_STATE_IDLE safety_critical_disarm_motor_pwm(motor_); + mechanical_brake_.engage(); set_step_dir_active(config_.enable_step_dir && config_.step_dir_always_on); run_control_loop([this]() { return true; @@ -474,6 +478,7 @@ void Axis::run_state_machine_loop() { // arm! motor_.arm(); + mechanical_brake_.release(); for (;;) { // Load the task chain if a specific request is pending @@ -575,6 +580,7 @@ void Axis::run_state_machine_loop() { case AXIS_STATE_IDLE: { run_idle_loop(); status = motor_.arm(); // done with idling - try to arm the motor + mechanical_brake_.release(); } break; default: diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index 3271e432..e96ab2ef 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -82,7 +82,8 @@ public: Motor& motor, TrapezoidalTrajectory& trap, Endstop& min_endstop, - Endstop& max_endstop); + Endstop& max_endstop, + MechanicalBrake& mechanical_brake); void setup(); void start_thread(); @@ -210,6 +211,7 @@ public: TrapezoidalTrajectory& trap_traj_; Endstop& min_endstop_; Endstop& max_endstop_; + MechanicalBrake& mechanical_brake_; // List of current_limiters and thermistors to // provide easy iteration. diff --git a/Firmware/MotorControl/main.cpp b/Firmware/MotorControl/main.cpp index 2809f5da..62f7ec1e 100644 --- a/Firmware/MotorControl/main.cpp +++ b/Firmware/MotorControl/main.cpp @@ -21,6 +21,7 @@ Axis::Config_t axis_configs[AXIS_COUNT]; TrapezoidalTrajectory::Config_t trap_configs[AXIS_COUNT]; Endstop::Config_t min_endstop_configs[AXIS_COUNT]; Endstop::Config_t max_endstop_configs[AXIS_COUNT]; +MechanicalBrake::Config_t mechanical_brake_configs[AXIS_COUNT]; std::array axes; ODriveCAN *odCAN = nullptr; @@ -38,6 +39,7 @@ typedef Config< TrapezoidalTrajectory::Config_t[AXIS_COUNT], Endstop::Config_t[AXIS_COUNT], Endstop::Config_t[AXIS_COUNT], + MechanicalBrake::Config_t[AXIS_COUNT], Axis::Config_t[AXIS_COUNT]> ConfigFormat; void ODrive::save_configuration(void) { @@ -53,6 +55,7 @@ void ODrive::save_configuration(void) { &trap_configs, &min_endstop_configs, &max_endstop_configs, + &mechanical_brake_configs, &axis_configs)) { printf("saving configuration failed\r\n"); osDelay(5); } else { @@ -75,6 +78,7 @@ extern "C" int load_configuration(void) { &trap_configs, &min_endstop_configs, &max_endstop_configs, + &mechanical_brake_configs, &axis_configs)) { //If loading failed, restore defaults odrv.config_ = BoardConfig_t(); @@ -93,6 +97,7 @@ extern "C" int load_configuration(void) { Axis::load_default_can_id(i, axis_configs[i]); min_endstop_configs[i] = Endstop::Config_t(); max_endstop_configs[i] = Endstop::Config_t(); + mechanical_brake_configs[i] = MechanicalBrake::Config_t(); controller_configs[i].load_encoder_axis = i; } } else { @@ -194,9 +199,10 @@ extern "C" int construct_objects(){ TrapezoidalTrajectory *trap = new TrapezoidalTrajectory(trap_configs[i]); Endstop *min_endstop = new Endstop(min_endstop_configs[i]); Endstop *max_endstop = new Endstop(max_endstop_configs[i]); + MechanicalBrake *mechanical_brake = new MechanicalBrake(mechanical_brake_configs[i]); axes[i] = new Axis(i, hw_configs[i].axis_config, axis_configs[i], *encoder, *sensorless_estimator, *controller, *fet_thermistor, - *motor_thermistor, *motor, *trap, *min_endstop, *max_endstop); + *motor_thermistor, *motor, *trap, *min_endstop, *max_endstop, *mechanical_brake); controller_configs[i].parent = controller; encoder_configs[i].parent = encoder; @@ -204,6 +210,7 @@ extern "C" int construct_objects(){ motor_configs[i].parent = motor; min_endstop_configs[i].parent = min_endstop; max_endstop_configs[i].parent = max_endstop; + mechanical_brake_configs[i].parent = mechanical_brake; axis_configs[i].parent = axes[i]; } return 0; diff --git a/Firmware/MotorControl/mechanical_brake.cpp b/Firmware/MotorControl/mechanical_brake.cpp new file mode 100644 index 00000000..27707d2a --- /dev/null +++ b/Firmware/MotorControl/mechanical_brake.cpp @@ -0,0 +1,41 @@ +#include + +MechanicalBrake::MechanicalBrake(MechanicalBrake::Config_t& config) + : config_(config) { + update_config(); +} + +bool MechanicalBrake::get_state() { + return mechanical_brake_state_; +} + +void MechanicalBrake::update_config() { + set_enabled(config_.enabled); +} + +void MechanicalBrake::engage() { + uint16_t gpio_pin = get_gpio_pin_by_pin(config_.gpio_num); + GPIO_TypeDef* gpio_port = get_gpio_port_by_pin(config_.gpio_num); + HAL_GPIO_WritePin(gpio_port, gpio_pin, config_.is_active_low ? GPIO_PIN_RESET : GPIO_PIN_SET ); +} + +void MechanicalBrake::release() { + uint16_t gpio_pin = get_gpio_pin_by_pin(config_.gpio_num); + GPIO_TypeDef* gpio_port = get_gpio_port_by_pin(config_.gpio_num); + HAL_GPIO_WritePin(gpio_port, gpio_pin, config_.is_active_low ? GPIO_PIN_SET : GPIO_PIN_RESET ); +} + +void MechanicalBrake::set_enabled(bool enable) { + if (config_.gpio_num != 0) { + uint16_t gpio_pin = get_gpio_pin_by_pin(config_.gpio_num); + GPIO_TypeDef* gpio_port = get_gpio_port_by_pin(config_.gpio_num); + if (enable) { + HAL_GPIO_DeInit(gpio_port, gpio_pin); + GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitStruct.Pin = gpio_pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = config_.pulldown ? GPIO_PULLDOWN : GPIO_PULLUP; + HAL_GPIO_Init(gpio_port, &GPIO_InitStruct); + } + } +} \ No newline at end of file diff --git a/Firmware/MotorControl/mechanical_brake.hpp b/Firmware/MotorControl/mechanical_brake.hpp new file mode 100644 index 00000000..9586f8b3 --- /dev/null +++ b/Firmware/MotorControl/mechanical_brake.hpp @@ -0,0 +1,36 @@ +#ifndef __MECHANICAL_BRAKE_HPP +#define __MECHANICAL_BRAKE_HPP + +class MechanicalBrake { + public: + struct Config_t { + uint16_t gpio_num = 0; + bool enabled = false; + bool is_active_low = true; + bool pulldown = true; + + // custom setters + MechanicalBrake* parent = nullptr; + void set_gpio_num(uint16_t value) { gpio_num = value; parent->update_config(); } + void set_enabled(uint32_t value) { enabled = value; parent->update_config(); } + }; + + explicit MechanicalBrake(MechanicalBrake::Config_t& config); + + MechanicalBrake::Config_t& config_; + Axis* axis_ = nullptr; + + void update_config(); + void set_enabled(bool enabled); + + void update(); + bool get_state(); + void release(); + void engage(); + + bool mechanical_brake_state_ = true; + + private: + bool pin_state_ = false; +}; +#endif // __MECHANICAL_BRAKE_HPP \ No newline at end of file diff --git a/Firmware/MotorControl/odrive_main.h b/Firmware/MotorControl/odrive_main.h index d0dcface..88328993 100644 --- a/Firmware/MotorControl/odrive_main.h +++ b/Firmware/MotorControl/odrive_main.h @@ -210,6 +210,7 @@ enum TimingLog_t { #include #include #include +#include #include #include diff --git a/Firmware/Tupfile.lua b/Firmware/Tupfile.lua index 7f5380ae..f8f6f8ec 100644 --- a/Firmware/Tupfile.lua +++ b/Firmware/Tupfile.lua @@ -194,6 +194,7 @@ build{ 'MotorControl/thermistor.cpp', 'MotorControl/encoder.cpp', 'MotorControl/endstop.cpp', + 'MotorControl/mechanical_brake.cpp', 'MotorControl/controller.cpp', 'MotorControl/sensorless_estimator.cpp', 'MotorControl/trapTraj.cpp', diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index 2c9060eb..2a755275 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -364,6 +364,7 @@ interfaces: trap_traj: TrapezoidalTrajectory min_endstop: Endstop max_endstop: Endstop + mechanical_brake: MechanicalBrake functions: watchdog_feed: doc: Feed the watchdog to prevent watchdog timeouts. @@ -830,7 +831,6 @@ interfaces: accel_limit: float32 decel_limit: float32 - ODrive.Endstop: c_is_class: True attributes: @@ -845,6 +845,16 @@ interfaces: pullup: bool debounce_ms: {type: uint32, c_setter: set_debounce_ms} + ODrive.MechanicalBrake: + c_is_class: True + attributes: + config: + c_is_class: False + attributes: + gpio_num: {type: uint16, c_setter: set_gpio_num} + enabled: {type: bool, c_setter: set_enabled} + is_active_low: bool + pulldown: bool valuetypes: ODrive.Can.Protocol: diff --git a/docs/_data/index.yaml b/docs/_data/index.yaml index 0ff47762..273029b6 100644 --- a/docs/_data/index.yaml +++ b/docs/_data/index.yaml @@ -17,6 +17,8 @@ sections: url: /encoders - title: Homing & Endstops url: /endstops + - title: Mechanical Brakes + url: /mechanical-brakes - title: Thermistors url: /thermistors - title: Control & Tuning diff --git a/docs/mechanical-brakes.md b/docs/mechanical-brakes.md new file mode 100644 index 00000000..dc2cdaf6 --- /dev/null +++ b/docs/mechanical-brakes.md @@ -0,0 +1,66 @@ +# Mechanical Brake + +Some systems employ mechanical brakes on motors as a safety feature. These brakes can also be engaged as a power-saving function if the motor is not moving, but still under load. + +ODrive supports the use of its GPIO pins to connect to external brake drive electronics. + +When the ODrive engages the drive electronics, the brake will be disabled. When the drive enters a fault or idle state, the brake will be re-engaged. + +--- + +## Mechanical Brake Configuration +Each axis supports one mechanical brake. The following properties are accessible through `odrivetool`: + +Name | Type | Default +--- | -- | -- +gpio_num | int | 0 +enabled | boolean | false +is_active_low | boolean | true +pulldown | boolean | true + +### gpio_num +The GPIO pin number, according to the silkscreen labels on ODrive. Set with these commands: +``` +..mechanical_brake.config.gpio_num = <1, 2, 3, 4, 5, 6, 7, 8> +``` + +### enabled +Enables/disables the operation of the mechanical brake. +``` +..mechanical_brake.config.enabled = +``` + +### is_active_low +Most safety braking systems are active low, e.g. when the power is off, the brake is on. If the system uses brake drive electronics which use active high logic, flip this bit then reconsider the safety implications of your design... + +### pulldown +If `true`, it enables the GPIO pulldown resistor. If `false`, it enables the GPIO pullup resistor. + +### Example + +Let's say we're hacking away on an old ABB robotic arm. We've wired a 24V brake drive circuit triggered by GPIO5. When GPIO5 is driven, it will release the brakes on the axis we're moving. + +``` +..mechanical_brake.config.gpio_num = 5 +..mechanical_brake.config.enabled = True +``` + +Don't forget to save and reboot: +``` +.save_configuration() +.reboot() +``` + +### Testing The Mechanical Brakes +Depending on your system this could be a dangerous experiment. Ensure that you have taken all necessary precautions to confirm if the wrong brake were inadvertently released it would not lead to injury or damage to equipment. + +``` +..mechanical_brake.release() +``` +Note: If a brake is enabled, it will be engaged/disengaged during the next state machine step. + +After you're satisfied with the testing, you can re-enable the brake using the command + +``` +..mechanical_brake.engage() +``` From 46c054f3af4d71cfd3ce940fa07f1377a13ed743 Mon Sep 17 00:00:00 2001 From: Shaun Meehan Date: Tue, 18 Aug 2020 23:37:44 -0700 Subject: [PATCH 13/48] Mechanical Brake feature --- Firmware/MotorControl/axis.cpp | 8 ++- Firmware/MotorControl/axis.hpp | 4 +- Firmware/MotorControl/main.cpp | 9 ++- Firmware/MotorControl/mechanical_brake.cpp | 41 ++++++++++++++ Firmware/MotorControl/mechanical_brake.hpp | 36 ++++++++++++ Firmware/MotorControl/odrive_main.h | 1 + Firmware/Tupfile.lua | 1 + Firmware/odrive-interface.yaml | 12 +++- docs/_data/index.yaml | 2 + docs/mechanical-brakes.md | 66 ++++++++++++++++++++++ 10 files changed, 176 insertions(+), 4 deletions(-) create mode 100644 Firmware/MotorControl/mechanical_brake.cpp create mode 100644 Firmware/MotorControl/mechanical_brake.hpp create mode 100644 docs/mechanical-brakes.md diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index f5771cd2..96df5ab0 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -19,7 +19,8 @@ Axis::Axis(int axis_num, Motor& motor, TrapezoidalTrajectory& trap, Endstop& min_endstop, - Endstop& max_endstop) + Endstop& max_endstop, + MechanicalBrake& mechanical_brake) : axis_num_(axis_num), hw_config_(hw_config), config_(config), @@ -32,6 +33,7 @@ Axis::Axis(int axis_num, trap_traj_(trap), min_endstop_(min_endstop), max_endstop_(max_endstop), + mechanical_brake_(mechanical_brake), current_limiters_(make_array( static_cast(&fet_thermistor), static_cast(&motor_thermistor))), @@ -48,6 +50,7 @@ Axis::Axis(int axis_num, trap_traj_.axis_ = this; min_endstop_.axis_ = this; max_endstop_.axis_ = this; + mechanical_brake_.axis_ = this; decode_step_dir_pins(); watchdog_feed(); } @@ -462,6 +465,7 @@ bool Axis::run_idle_loop() { // run_control_loop ignores missed modulation timing updates // if and only if we're in AXIS_STATE_IDLE safety_critical_disarm_motor_pwm(motor_); + mechanical_brake_.engage(); set_step_dir_active(config_.enable_step_dir && config_.step_dir_always_on); run_control_loop([this]() { return true; @@ -474,6 +478,7 @@ void Axis::run_state_machine_loop() { // arm! motor_.arm(); + mechanical_brake_.release(); for (;;) { // Load the task chain if a specific request is pending @@ -575,6 +580,7 @@ void Axis::run_state_machine_loop() { case AXIS_STATE_IDLE: { run_idle_loop(); status = motor_.arm(); // done with idling - try to arm the motor + mechanical_brake_.release(); } break; default: diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index 3271e432..e96ab2ef 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -82,7 +82,8 @@ public: Motor& motor, TrapezoidalTrajectory& trap, Endstop& min_endstop, - Endstop& max_endstop); + Endstop& max_endstop, + MechanicalBrake& mechanical_brake); void setup(); void start_thread(); @@ -210,6 +211,7 @@ public: TrapezoidalTrajectory& trap_traj_; Endstop& min_endstop_; Endstop& max_endstop_; + MechanicalBrake& mechanical_brake_; // List of current_limiters and thermistors to // provide easy iteration. diff --git a/Firmware/MotorControl/main.cpp b/Firmware/MotorControl/main.cpp index 2809f5da..62f7ec1e 100644 --- a/Firmware/MotorControl/main.cpp +++ b/Firmware/MotorControl/main.cpp @@ -21,6 +21,7 @@ Axis::Config_t axis_configs[AXIS_COUNT]; TrapezoidalTrajectory::Config_t trap_configs[AXIS_COUNT]; Endstop::Config_t min_endstop_configs[AXIS_COUNT]; Endstop::Config_t max_endstop_configs[AXIS_COUNT]; +MechanicalBrake::Config_t mechanical_brake_configs[AXIS_COUNT]; std::array axes; ODriveCAN *odCAN = nullptr; @@ -38,6 +39,7 @@ typedef Config< TrapezoidalTrajectory::Config_t[AXIS_COUNT], Endstop::Config_t[AXIS_COUNT], Endstop::Config_t[AXIS_COUNT], + MechanicalBrake::Config_t[AXIS_COUNT], Axis::Config_t[AXIS_COUNT]> ConfigFormat; void ODrive::save_configuration(void) { @@ -53,6 +55,7 @@ void ODrive::save_configuration(void) { &trap_configs, &min_endstop_configs, &max_endstop_configs, + &mechanical_brake_configs, &axis_configs)) { printf("saving configuration failed\r\n"); osDelay(5); } else { @@ -75,6 +78,7 @@ extern "C" int load_configuration(void) { &trap_configs, &min_endstop_configs, &max_endstop_configs, + &mechanical_brake_configs, &axis_configs)) { //If loading failed, restore defaults odrv.config_ = BoardConfig_t(); @@ -93,6 +97,7 @@ extern "C" int load_configuration(void) { Axis::load_default_can_id(i, axis_configs[i]); min_endstop_configs[i] = Endstop::Config_t(); max_endstop_configs[i] = Endstop::Config_t(); + mechanical_brake_configs[i] = MechanicalBrake::Config_t(); controller_configs[i].load_encoder_axis = i; } } else { @@ -194,9 +199,10 @@ extern "C" int construct_objects(){ TrapezoidalTrajectory *trap = new TrapezoidalTrajectory(trap_configs[i]); Endstop *min_endstop = new Endstop(min_endstop_configs[i]); Endstop *max_endstop = new Endstop(max_endstop_configs[i]); + MechanicalBrake *mechanical_brake = new MechanicalBrake(mechanical_brake_configs[i]); axes[i] = new Axis(i, hw_configs[i].axis_config, axis_configs[i], *encoder, *sensorless_estimator, *controller, *fet_thermistor, - *motor_thermistor, *motor, *trap, *min_endstop, *max_endstop); + *motor_thermistor, *motor, *trap, *min_endstop, *max_endstop, *mechanical_brake); controller_configs[i].parent = controller; encoder_configs[i].parent = encoder; @@ -204,6 +210,7 @@ extern "C" int construct_objects(){ motor_configs[i].parent = motor; min_endstop_configs[i].parent = min_endstop; max_endstop_configs[i].parent = max_endstop; + mechanical_brake_configs[i].parent = mechanical_brake; axis_configs[i].parent = axes[i]; } return 0; diff --git a/Firmware/MotorControl/mechanical_brake.cpp b/Firmware/MotorControl/mechanical_brake.cpp new file mode 100644 index 00000000..27707d2a --- /dev/null +++ b/Firmware/MotorControl/mechanical_brake.cpp @@ -0,0 +1,41 @@ +#include + +MechanicalBrake::MechanicalBrake(MechanicalBrake::Config_t& config) + : config_(config) { + update_config(); +} + +bool MechanicalBrake::get_state() { + return mechanical_brake_state_; +} + +void MechanicalBrake::update_config() { + set_enabled(config_.enabled); +} + +void MechanicalBrake::engage() { + uint16_t gpio_pin = get_gpio_pin_by_pin(config_.gpio_num); + GPIO_TypeDef* gpio_port = get_gpio_port_by_pin(config_.gpio_num); + HAL_GPIO_WritePin(gpio_port, gpio_pin, config_.is_active_low ? GPIO_PIN_RESET : GPIO_PIN_SET ); +} + +void MechanicalBrake::release() { + uint16_t gpio_pin = get_gpio_pin_by_pin(config_.gpio_num); + GPIO_TypeDef* gpio_port = get_gpio_port_by_pin(config_.gpio_num); + HAL_GPIO_WritePin(gpio_port, gpio_pin, config_.is_active_low ? GPIO_PIN_SET : GPIO_PIN_RESET ); +} + +void MechanicalBrake::set_enabled(bool enable) { + if (config_.gpio_num != 0) { + uint16_t gpio_pin = get_gpio_pin_by_pin(config_.gpio_num); + GPIO_TypeDef* gpio_port = get_gpio_port_by_pin(config_.gpio_num); + if (enable) { + HAL_GPIO_DeInit(gpio_port, gpio_pin); + GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitStruct.Pin = gpio_pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = config_.pulldown ? GPIO_PULLDOWN : GPIO_PULLUP; + HAL_GPIO_Init(gpio_port, &GPIO_InitStruct); + } + } +} \ No newline at end of file diff --git a/Firmware/MotorControl/mechanical_brake.hpp b/Firmware/MotorControl/mechanical_brake.hpp new file mode 100644 index 00000000..9586f8b3 --- /dev/null +++ b/Firmware/MotorControl/mechanical_brake.hpp @@ -0,0 +1,36 @@ +#ifndef __MECHANICAL_BRAKE_HPP +#define __MECHANICAL_BRAKE_HPP + +class MechanicalBrake { + public: + struct Config_t { + uint16_t gpio_num = 0; + bool enabled = false; + bool is_active_low = true; + bool pulldown = true; + + // custom setters + MechanicalBrake* parent = nullptr; + void set_gpio_num(uint16_t value) { gpio_num = value; parent->update_config(); } + void set_enabled(uint32_t value) { enabled = value; parent->update_config(); } + }; + + explicit MechanicalBrake(MechanicalBrake::Config_t& config); + + MechanicalBrake::Config_t& config_; + Axis* axis_ = nullptr; + + void update_config(); + void set_enabled(bool enabled); + + void update(); + bool get_state(); + void release(); + void engage(); + + bool mechanical_brake_state_ = true; + + private: + bool pin_state_ = false; +}; +#endif // __MECHANICAL_BRAKE_HPP \ No newline at end of file diff --git a/Firmware/MotorControl/odrive_main.h b/Firmware/MotorControl/odrive_main.h index d0dcface..88328993 100644 --- a/Firmware/MotorControl/odrive_main.h +++ b/Firmware/MotorControl/odrive_main.h @@ -210,6 +210,7 @@ enum TimingLog_t { #include #include #include +#include #include #include diff --git a/Firmware/Tupfile.lua b/Firmware/Tupfile.lua index 7f5380ae..f8f6f8ec 100644 --- a/Firmware/Tupfile.lua +++ b/Firmware/Tupfile.lua @@ -194,6 +194,7 @@ build{ 'MotorControl/thermistor.cpp', 'MotorControl/encoder.cpp', 'MotorControl/endstop.cpp', + 'MotorControl/mechanical_brake.cpp', 'MotorControl/controller.cpp', 'MotorControl/sensorless_estimator.cpp', 'MotorControl/trapTraj.cpp', diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index 2c9060eb..2a755275 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -364,6 +364,7 @@ interfaces: trap_traj: TrapezoidalTrajectory min_endstop: Endstop max_endstop: Endstop + mechanical_brake: MechanicalBrake functions: watchdog_feed: doc: Feed the watchdog to prevent watchdog timeouts. @@ -830,7 +831,6 @@ interfaces: accel_limit: float32 decel_limit: float32 - ODrive.Endstop: c_is_class: True attributes: @@ -845,6 +845,16 @@ interfaces: pullup: bool debounce_ms: {type: uint32, c_setter: set_debounce_ms} + ODrive.MechanicalBrake: + c_is_class: True + attributes: + config: + c_is_class: False + attributes: + gpio_num: {type: uint16, c_setter: set_gpio_num} + enabled: {type: bool, c_setter: set_enabled} + is_active_low: bool + pulldown: bool valuetypes: ODrive.Can.Protocol: diff --git a/docs/_data/index.yaml b/docs/_data/index.yaml index 0ff47762..273029b6 100644 --- a/docs/_data/index.yaml +++ b/docs/_data/index.yaml @@ -17,6 +17,8 @@ sections: url: /encoders - title: Homing & Endstops url: /endstops + - title: Mechanical Brakes + url: /mechanical-brakes - title: Thermistors url: /thermistors - title: Control & Tuning diff --git a/docs/mechanical-brakes.md b/docs/mechanical-brakes.md new file mode 100644 index 00000000..dc2cdaf6 --- /dev/null +++ b/docs/mechanical-brakes.md @@ -0,0 +1,66 @@ +# Mechanical Brake + +Some systems employ mechanical brakes on motors as a safety feature. These brakes can also be engaged as a power-saving function if the motor is not moving, but still under load. + +ODrive supports the use of its GPIO pins to connect to external brake drive electronics. + +When the ODrive engages the drive electronics, the brake will be disabled. When the drive enters a fault or idle state, the brake will be re-engaged. + +--- + +## Mechanical Brake Configuration +Each axis supports one mechanical brake. The following properties are accessible through `odrivetool`: + +Name | Type | Default +--- | -- | -- +gpio_num | int | 0 +enabled | boolean | false +is_active_low | boolean | true +pulldown | boolean | true + +### gpio_num +The GPIO pin number, according to the silkscreen labels on ODrive. Set with these commands: +``` +..mechanical_brake.config.gpio_num = <1, 2, 3, 4, 5, 6, 7, 8> +``` + +### enabled +Enables/disables the operation of the mechanical brake. +``` +..mechanical_brake.config.enabled = +``` + +### is_active_low +Most safety braking systems are active low, e.g. when the power is off, the brake is on. If the system uses brake drive electronics which use active high logic, flip this bit then reconsider the safety implications of your design... + +### pulldown +If `true`, it enables the GPIO pulldown resistor. If `false`, it enables the GPIO pullup resistor. + +### Example + +Let's say we're hacking away on an old ABB robotic arm. We've wired a 24V brake drive circuit triggered by GPIO5. When GPIO5 is driven, it will release the brakes on the axis we're moving. + +``` +..mechanical_brake.config.gpio_num = 5 +..mechanical_brake.config.enabled = True +``` + +Don't forget to save and reboot: +``` +.save_configuration() +.reboot() +``` + +### Testing The Mechanical Brakes +Depending on your system this could be a dangerous experiment. Ensure that you have taken all necessary precautions to confirm if the wrong brake were inadvertently released it would not lead to injury or damage to equipment. + +``` +..mechanical_brake.release() +``` +Note: If a brake is enabled, it will be engaged/disengaged during the next state machine step. + +After you're satisfied with the testing, you can re-enable the brake using the command + +``` +..mechanical_brake.engage() +``` From ccf4b17f822007c1ad552851a674082e8a7f59e0 Mon Sep 17 00:00:00 2001 From: Shaun Meehan Date: Wed, 19 Aug 2020 00:15:19 -0700 Subject: [PATCH 14/48] Updated changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31adaf34..50da5f3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased Features Please add a note of your changes below this heading if you make a Pull Request. +### Added +* [Mechanical brake support](docs/mechanical-brakes.md) # Release Candidate ## [0.5.1] - Date TBD From 87ea4a423fa50e9f5a564eab960211b3897366b1 Mon Sep 17 00:00:00 2001 From: Shaun Meehan Date: Wed, 19 Aug 2020 12:31:26 -0700 Subject: [PATCH 15/48] Updated mechanical brake support as per upstream refactor --- Firmware/Board/v3/board.cpp | 3 +++ Firmware/MotorControl/axis.hpp | 1 + Firmware/MotorControl/mechanical_brake.cpp | 30 +++++----------------- Firmware/MotorControl/mechanical_brake.hpp | 18 ++++--------- 4 files changed, 15 insertions(+), 37 deletions(-) diff --git a/Firmware/Board/v3/board.cpp b/Firmware/Board/v3/board.cpp index 5f883809..d2b0afbb 100644 --- a/Firmware/Board/v3/board.cpp +++ b/Firmware/Board/v3/board.cpp @@ -96,6 +96,7 @@ Encoder encoders[AXIS_COUNT] = { // TODO: this has no hardware dependency and should be allocated depending on config Endstop endstops[2 * AXIS_COUNT]; +MechanicalBrake mechanical_brakes[AXIS_COUNT]; SensorlessEstimator sensorless_estimators[AXIS_COUNT]; Controller controllers[AXIS_COUNT]; @@ -116,6 +117,7 @@ std::array axes{{ motors[0], // motor trap[0], // trap endstops[0], endstops[1], // min_endstop, max_endstop + mechanical_brakes[0], // mechanical brake }, { 1, // axis_num @@ -135,6 +137,7 @@ std::array axes{{ motors[1], // motor trap[1], // trap endstops[2], endstops[3], // min_endstop, max_endstop + mechanical_brakes[1], // mechanical brake }, }}; diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index b1611b93..b3965b39 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -8,6 +8,7 @@ class Axis; #include "controller.hpp" #include "trapTraj.hpp" #include "endstop.hpp" +#include "mechanical_brake.hpp" #include "low_level.h" #include "utils.hpp" #include "communication/interface_uart.h" // TODO: remove once uart_poll() is gone diff --git a/Firmware/MotorControl/mechanical_brake.cpp b/Firmware/MotorControl/mechanical_brake.cpp index 27707d2a..591efc62 100644 --- a/Firmware/MotorControl/mechanical_brake.cpp +++ b/Firmware/MotorControl/mechanical_brake.cpp @@ -1,41 +1,23 @@ #include -MechanicalBrake::MechanicalBrake(MechanicalBrake::Config_t& config) - : config_(config) { - update_config(); -} - -bool MechanicalBrake::get_state() { - return mechanical_brake_state_; -} - -void MechanicalBrake::update_config() { +bool MechanicalBrake::apply_config() { set_enabled(config_.enabled); + return true; } void MechanicalBrake::engage() { - uint16_t gpio_pin = get_gpio_pin_by_pin(config_.gpio_num); - GPIO_TypeDef* gpio_port = get_gpio_port_by_pin(config_.gpio_num); - HAL_GPIO_WritePin(gpio_port, gpio_pin, config_.is_active_low ? GPIO_PIN_RESET : GPIO_PIN_SET ); + get_gpio(config_.gpio_num).write(config_.is_active_low ? 0 : 1); } void MechanicalBrake::release() { - uint16_t gpio_pin = get_gpio_pin_by_pin(config_.gpio_num); - GPIO_TypeDef* gpio_port = get_gpio_port_by_pin(config_.gpio_num); - HAL_GPIO_WritePin(gpio_port, gpio_pin, config_.is_active_low ? GPIO_PIN_SET : GPIO_PIN_RESET ); + get_gpio(config_.gpio_num).write(config_.is_active_low ? 1 : 0); } void MechanicalBrake::set_enabled(bool enable) { if (config_.gpio_num != 0) { - uint16_t gpio_pin = get_gpio_pin_by_pin(config_.gpio_num); - GPIO_TypeDef* gpio_port = get_gpio_port_by_pin(config_.gpio_num); + Stm32Gpio gpio = get_gpio(config_.gpio_num); if (enable) { - HAL_GPIO_DeInit(gpio_port, gpio_pin); - GPIO_InitTypeDef GPIO_InitStruct; - GPIO_InitStruct.Pin = gpio_pin; - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStruct.Pull = config_.pulldown ? GPIO_PULLDOWN : GPIO_PULLUP; - HAL_GPIO_Init(gpio_port, &GPIO_InitStruct); + gpio.config(GPIO_MODE_OUTPUT_PP, config_.pulldown ? GPIO_PULLDOWN : GPIO_PULLUP); } } } \ No newline at end of file diff --git a/Firmware/MotorControl/mechanical_brake.hpp b/Firmware/MotorControl/mechanical_brake.hpp index 9586f8b3..240e7ed4 100644 --- a/Firmware/MotorControl/mechanical_brake.hpp +++ b/Firmware/MotorControl/mechanical_brake.hpp @@ -11,26 +11,18 @@ class MechanicalBrake { // custom setters MechanicalBrake* parent = nullptr; - void set_gpio_num(uint16_t value) { gpio_num = value; parent->update_config(); } - void set_enabled(uint32_t value) { enabled = value; parent->update_config(); } + void set_gpio_num(uint16_t value) { gpio_num = value; parent->apply_config(); } + void set_enabled(uint32_t value) { enabled = value; parent->apply_config(); } }; - explicit MechanicalBrake(MechanicalBrake::Config_t& config); + MechanicalBrake() {} - MechanicalBrake::Config_t& config_; + MechanicalBrake::Config_t config_; Axis* axis_ = nullptr; - void update_config(); + bool apply_config(); void set_enabled(bool enabled); - - void update(); - bool get_state(); void release(); void engage(); - - bool mechanical_brake_state_ = true; - - private: - bool pin_state_ = false; }; #endif // __MECHANICAL_BRAKE_HPP \ No newline at end of file From 17860cbadd1ac0c1eb836d6cd42054c4a81e5fee Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Fri, 21 Aug 2020 20:50:26 -0700 Subject: [PATCH 16/48] add updated timing diagram for ODrive v3 --- Firmware/timing_diagram_v3.png | Bin 0 -> 222030 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Firmware/timing_diagram_v3.png diff --git a/Firmware/timing_diagram_v3.png b/Firmware/timing_diagram_v3.png new file mode 100644 index 0000000000000000000000000000000000000000..f36d0af1e8fc9c33b197586242a13c489d90ade3 GIT binary patch literal 222030 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şb3`lvk?IZ1qN_t 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Ē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 Date: Fri, 21 Aug 2020 21:00:07 -0700 Subject: [PATCH 17/48] add link to timing diagram in low_level.cpp --- Firmware/MotorControl/low_level.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/MotorControl/low_level.cpp b/Firmware/MotorControl/low_level.cpp index 6125c99c..cc3dc1d4 100644 --- a/Firmware/MotorControl/low_level.cpp +++ b/Firmware/MotorControl/low_level.cpp @@ -463,7 +463,7 @@ static void decode_hall_samples(Encoder& enc, uint16_t GPIO_samples[num_GPIO]) { } // This is the callback from the ADC that we expect after the PWM has triggered an ADC conversion. -// TODO: Document how the phasing is done, link to timing diagram +// Timing diagram: Firmware/timing_diagram_v3.png void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { #define calib_tau 0.2f //@TOTO make more easily configurable static const float calib_filter_k = CURRENT_MEAS_PERIOD / calib_tau; From 2f3f09e418123cc71053987d3922b0de5097b1e7 Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Mon, 24 Aug 2020 19:00:37 -0400 Subject: [PATCH 18/48] Cleaned up encoder docs page. Added a link to the RC docs page for information about SPI absolute encoders. --- docs/encoders.md | 53 +++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/docs/encoders.md b/docs/encoders.md index cb038850..bfbfd984 100644 --- a/docs/encoders.md +++ b/docs/encoders.md @@ -4,7 +4,7 @@ Be sure to read the [ODrive Encoder Guide](https://docs.google.com/spreadsheets/d/1OBDwYrBb5zUPZLrhL98ezZbg94tUsZcdTuwiVNgVqpU). ## Encoder Calibration -Please take into account that all encoder types supported by ODrive require that you do some sort of encoder calibration. This requires the following: +All encoder types supported by ODrive require that you do some sort of encoder calibration. This requires the following: * Selecting an encoder and mounting it to your motor * Choosing an interface (e.g., AB, ABI or SPI) * Connecting the pins to the odrive @@ -24,11 +24,11 @@ To verify everything went well, check the following variables: * `.motor.config.direction` - This should print 1 or -1. ### Encoder with index signal -If you have an encoder with an index (Z) signal, you may avoid having to do the offset calibration on every startup, and instead use the index signal to re-sync the encoder to a stored calibration. +If you have an encoder with an index (Z) signal, you can avoid doing the offset calibration on every startup, and instead use the index signal to re-sync the encoder to a stored calibration. Below are the steps to do the one-time calibration and configuration. Note that you can follow these steps with one motor at a time, or all motors together, as you wish. -* Since you will only do this once, it is recommended that you mechanically disengage the motor from anything other than the encoder, so it can spin freely. +* Since you will only do this once, it is recommended that you mechanically disengage the motor from anything other than the encoder, so that it can spin freely. * Set `.encoder.config.use_index` to `True`. * Run `.requested_state = AXIS_STATE_ENCODER_INDEX_SEARCH`. This will make the motor turn in one direction until it finds the encoder index. * Follow the calibration instructions for an [encoder without index signal](#encoder-without-index-signal). @@ -43,7 +43,7 @@ That's it, now on every reboot the motor will turn in one direction until it fin * If your motor has problems reaching the index location due to the mechanical load, you can increase `.motor.config.calibration_current`. ### Reversing index search -Sometimes you would like the index search to only happen in a particular direction (the reverse of the default), instead of swapping the motor leads, you can ensure the following three values are negative: +Sometimes you would like the index search to only happen in a particular direction (the reverse of the default). Instead of swapping the motor leads, you can ensure that the following three values are negative: * `.config.calibration_lockin.vel` * `.config.calibration_lockin.accel` * `.config.calibration_lockin.ramp_distance` @@ -57,14 +57,14 @@ The following are variables that MUST be set up for your encoder configuration. * `.encoder.config.cpr = 8192` * `.encoder.config.mode = ENCODER_MODE_INCREMENTAL` -The following are examples of values that MAY impact the success of calibration. These are not all the varibles you have to set for startup. Only change these when you understand why they are needed; your values will vary depending on your setup: -* `.motor.config.motor_type = MOTOR_TYPE_HIGH_CURRENT` select if you have a gimbal or high amp motor -* `.encoder.config.calib_range = 0.05` helps to relax the accuracy of encoder counts during calibration -* `.motor.config.calibration_current = 10.0` _sometimes_ needed if this is a large motor -* `.motor.config.resistance_calib_max_voltage = 12.0` _sometimes_ needed depending on motor +The following are examples of values that can impact the success of calibration. These are not all of the variables you have to set for startup. Only change these when you understand why they are needed; your values will vary depending on your setup: +* `.motor.config.motor_type = MOTOR_TYPE_HIGH_CURRENT` The type of motor you have. Valid choices are high current or gimbal. +* `.encoder.config.calib_range = 0.05` Helps to relax the accuracy of encoder counts during calibration +* `.motor.config.calibration_current = 10.0` The motor current used for calibration. For large motors, this value can be increased to overcome friction and cogging. +* `.motor.config.resistance_calib_max_voltage = 12.0` Max motor voltage used for measuring motor resistance. For motor calibration, it must be possible for the motor current to reach the calibration current without the applied voltage exceeding this config setting. * `.controller.config.vel_limit = 50000` low values result in the spinning motor stopping abruptly during calibration -Lots of other values can get you. It's a process. Thankfully there is a lot of good people that will help you debug calibration problems. +Lots of other values can get you. It's a process. Thankfully there are a lot of good people that will help you debug calibration problems. If calibration works, congratulations. @@ -74,16 +74,16 @@ Now try: let it loop a few times and then set: * `.requested_state = AXIS_STATE_IDLE` -Do you still have no errors? Awesome. Now save the calibration, you can set the below. Note that this only works if you are using an absolute encoder or the encoder index input (see "Encoder with index signal" above). +Do you still have no errors? Awesome. Now, setup the motor and encoder to use known calibration values. This allows you to skip motor calibration and encoder offset calibration before using closed loop control. Note that this only works if you are using an absolute encoder or the encoder index input (see "Encoder with index signal" above). * `.encoder.config.pre_calibrated = True` * `.motor.config.pre_calibrated = True ` -And see if ODrive agrees that calibration worked by just running +And see if ODrive agrees that the calibration worked by just running * `.encoder.config.pre_calibrated` (using no "= True" ). Make sure that 'pre_calibrated' is in fact True. -Also, if you have calibrated and encoder.pre_calibrated is equal to true, and you had no errors so far. Run this: +Also, if you have calibrated and encoder.pre_calibrated is equal to true, and you had no errors so far, run this: * `odrv0.save_configuration()` * `odrv0.reboot()` @@ -106,19 +106,21 @@ Or ODrive may just vibrate in an entertaining way. See: https://www.youtube.com/watch?v=gaRUmwvSyAs ## Encoder Testing -There are things you can test to make sure your encoder is properly connected. -This run the command: +There are things you can test to make sure your encoder is properly connected. `shadow_count` tracks encoder motion, even before the encoder or motor are calibrated. If your encoder is working, you should see this value change when you turn the motor. +Run the command: * `.encoder.shadow_count ` and look at your value. Then turn your motor by hand and see if that value changes. Also, notice that the command: * `.encoder.config.cpr = 4000` -must reflect the number of counts odrive receives after one complete turn of the motor. So use shadow_count to test if that is working properly. +must reflect the number of counts ODrive receives after one complete turn of the motor. So use shadow_count to test if that is working properly. You will probably never be able to properly debug if you have problems unless you use an oscilloscope. If you have one, try the following: Connect to the AB pins, see if you get square waves as you turn the motor. Connect to the I pin, see if you get a pulse on a complete rotation. Sometimes this is hard to see. -If you are using SPI, have a lot at the signal on the CLK, and CS pins. There are many examples on the net for how these should behave. + +If you are using SPI, use a logic analyzer and connect to the CLK, MISO, and CS pins. Set a trigger for the CS pin and ensure that the encoder position is being sent and is increasing/decreasing as you spin the motor. There is extremely cheap hardware that is supported by [Sigrok](https://sigrok.org/) for protocol analysis. + ## Encoder Noise Noise is found in all circuits, life is just about figuring out if it is preventing your system from working. Lots of users have no problems with noise interfering with their odrive operation, others will tell you "_I've been using the same encoder as you with no problems_". Power to 'em, that may be true, but it doesn't mean it will work for you. If you are concerned about noise, there are several possible sources: @@ -127,13 +129,13 @@ Noise is found in all circuits, life is just about figuring out if it is prevent * Long wires between encoder and ODrive * Use of ribbon cable -The following _might_ mitigate noise problems. Use shielded cable, or use twisted pairs, where one side of each twisted pair is tied to ground, the other side is tied to your signal. If you are using SPI, use a 20-50 ohm resistor in series on CLK, which is more susceptible noise. +The following _might_ mitigate noise problems. Use shielded cable, or use twisted pairs, where one side of each twisted pair is tied to ground and the other side is tied to your signal. If you are using SPI, use a 20-50 ohm resistor in series on CLK, which is more susceptible noise. -If you are using an encoder with an index signal, another problem that has been encountered is with noise on the Z input of ODrive. Symptoms for this problem include: +If you are using an encoder with an index signal, another problem that has been encountered is noise on the Z input of ODrive. Symptoms for this problem include: * difficulty with requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE, where your calibration sequence may not complete * strange behavior after performing odrv0.save_configuration() and odrv0.reboot() * when performing an index_search, the motor does not return to the same position each time. -One easy step that _might_ fix the noise on the Z input has been to solder a 22nF-47nF capacitor to the Z pin and the GND pin on the underside of the ODrive board. +One easy step that _might_ fix the noise on the Z input is to solder a 22nF-47nF capacitor to the Z pin and the GND pin on the underside of the ODrive board. ## AS5047/AS5048 Encoders The AS5047/AS5048 encoders are Hall Effect/Magnetic sensors that can serve as rotary encoders for the ODrive. @@ -143,18 +145,13 @@ The AS5048 has 4 independent output interfaces: SPI, ABI, I2C, and PWM. Both chips come with evaluation boards that can simplify mounted the chips to your motor. For our purposes if you are using an evaluation board you should select the settings for 3.3v, and tie MOSI high to 3.3v. -If you are having calibration problems - make sure your magnet is centered on the axis of rotation on the motor, some users report this has a significant impact on calibration. Also make sure your magnet height is within range of the spec sheet. +If you are having calibration problems, make sure that your magnet is centered on the axis of rotation on the motor. Some users report that this has a significant impact on calibration. Also make sure that your magnet height is within range of the spec sheet. #### Using ABI. You can use ABI with the AS5047/AS5048 with the default ODrive firmware. For your wiring, connect A, B, 3.3v, GND to the labeled pins on the odrive The acronym I and Z mean the same thing, connect those as well if you are using an index signal. #### Using SPI. -TobinHall has written a [branch](https://github.com/TobinHall/ODrive/tree/Non-Blocking_Absolute_SPI) that supports the SPI option on the AS5047/AS5048. Use his build to flash firmware on your ODrive and connect MISO, SCK, and CS to the labeled pins on the odrive +SPI is not currently supported on the default ODrive firmware. It is supported on the ODrive release candidate firmware, found [here](https://discourse.odriverobotics.com/t/firmware-v0-5-1-release-candidate-feedback-thread/5210). -Tie MOSI to 3.3v, connect to the SCK, CLK, MISO, GND and 3.2v pins on the ODrive. (note for SPI users, the acronym SCK and CLK mean the same thing, the acronym CSn and CS mean the same thing.) - -Add these commands to your calibration / startup script: -* `.encoder.config.abs_spi_cs_gpio_pin = 4` or which ever GPIO pin you choose -* `.encoder.config.mode = 257` -* `.axis0.encoder.config.cpr = 2**14` +See the release candidate [encoder documentation](https://github.com/madcowswe/ODrive/blob/rc-v0.5.1/docs/encoders.md) for more information. From 57ce391d3992705416f53f17657d74aa1e646451 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Mon, 24 Aug 2020 18:33:46 -0700 Subject: [PATCH 19/48] update enter_dfu_mode error string --- tools/odrive/dfu.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/odrive/dfu.py b/tools/odrive/dfu.py index 9dc5f6d9..1be62fa6 100755 --- a/tools/odrive/dfu.py +++ b/tools/odrive/dfu.py @@ -216,9 +216,12 @@ def put_into_dfu_mode(device, cancellation_token): Puts the specified device into DFU mode """ if not hasattr(device, "enter_dfu_mode"): - print("The firmware on device {} does not support DFU. You need to \n" - "flash the firmware once using STLink (`make flash`), after that \n" - "DFU with this script should work fine." + print("The firmware on device {} cannot soft enter DFU mode.\n" + "Please remove power, put the DFU switch into DFU mode,\n" + "then apply power again. Then try again.\n" + "If it still doesn't work, you can try to use the DeFuse app or \n" + "dfu-util, see the odrive documentation.\n" + "You can also flash the firmware using STLink (`make flash`)" .format(device.__channel__.usb_device.serial_number)) return From 89bf879ff97eae995aceae9effd263a9096cb927 Mon Sep 17 00:00:00 2001 From: Shaun Meehan Date: Thu, 27 Aug 2020 18:28:33 -0700 Subject: [PATCH 20/48] Added GPIO_MODE_MECH_BRAKE, removed pull-ups for outputs, updated docs, added check for GPIO_MODE_MECH_BRAKE to startup in main --- Firmware/MotorControl/main.cpp | 8 ++++- Firmware/MotorControl/mechanical_brake.cpp | 13 +++++--- Firmware/MotorControl/mechanical_brake.hpp | 5 +-- Firmware/odrive-interface.yaml | 9 ++++- docs/interfaces.md | 38 +++++++++++----------- docs/mechanical-brakes.md | 4 --- tools/odrive/enums.py | 2 ++ 7 files changed, 47 insertions(+), 32 deletions(-) diff --git a/Firmware/MotorControl/main.cpp b/Firmware/MotorControl/main.cpp index c1af09f4..225c01b1 100644 --- a/Firmware/MotorControl/main.cpp +++ b/Firmware/MotorControl/main.cpp @@ -411,7 +411,8 @@ extern "C" int main(void) { GPIO_InitStruct.Pin = get_gpio(i).pin_mask_; // Set Alternate Function setting for this GPIO mode - if (mode == ODriveIntf::GPIO_MODE_DIGITAL || mode == ODriveIntf::GPIO_MODE_ANALOG_IN) { + if (mode == ODriveIntf::GPIO_MODE_DIGITAL || mode == ODriveIntf::GPIO_MODE_ANALOG_IN + || mode == ODriveIntf::GPIO_MODE_MECH_BRAKE) { GPIO_InitStruct.Alternate = 0; } else { auto it = std::find_if( @@ -497,6 +498,11 @@ extern "C" int main(void) { GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; } break; + case ODriveIntf::GPIO_MODE_MECH_BRAKE: { + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + } break; default: { odrv.misconfigured_ = true; continue; diff --git a/Firmware/MotorControl/mechanical_brake.cpp b/Firmware/MotorControl/mechanical_brake.cpp index 591efc62..b70334ff 100644 --- a/Firmware/MotorControl/mechanical_brake.cpp +++ b/Firmware/MotorControl/mechanical_brake.cpp @@ -1,6 +1,7 @@ #include bool MechanicalBrake::apply_config() { + config_.parent = this; set_enabled(config_.enabled); return true; } @@ -14,10 +15,12 @@ void MechanicalBrake::release() { } void MechanicalBrake::set_enabled(bool enable) { - if (config_.gpio_num != 0) { - Stm32Gpio gpio = get_gpio(config_.gpio_num); - if (enable) { - gpio.config(GPIO_MODE_OUTPUT_PP, config_.pulldown ? GPIO_PULLDOWN : GPIO_PULLUP); - } + Stm32Gpio gpio = get_gpio(config_.gpio_num); + + // We need this flag to alert the system to the configuration on boot + odrv.config_.gpio_modes[config_.gpio_num] = ODriveIntf::GPIO_MODE_MECH_BRAKE; + + if (enable) { + gpio.config(GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW); } } \ No newline at end of file diff --git a/Firmware/MotorControl/mechanical_brake.hpp b/Firmware/MotorControl/mechanical_brake.hpp index 240e7ed4..ae8373fd 100644 --- a/Firmware/MotorControl/mechanical_brake.hpp +++ b/Firmware/MotorControl/mechanical_brake.hpp @@ -1,13 +1,14 @@ #ifndef __MECHANICAL_BRAKE_HPP #define __MECHANICAL_BRAKE_HPP -class MechanicalBrake { +#include + +class MechanicalBrake : public ODriveIntf::MechanicalBrakeIntf { public: struct Config_t { uint16_t gpio_num = 0; bool enabled = false; bool is_active_low = true; - bool pulldown = true; // custom setters MechanicalBrake* parent = nullptr; diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index 26491c4d..39108079 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -925,7 +925,13 @@ interfaces: gpio_num: {type: uint16, c_setter: set_gpio_num} enabled: {type: bool, c_setter: set_enabled} is_active_low: bool - pulldown: bool + functions: + engage: + doc: | + This function engages the mechanical brake if one is present and enabled. + release: + doc: | + This function releases the mecahncal brake if one is present and enabled. valuetypes: ODrive.GpioMode: @@ -950,6 +956,7 @@ valuetypes: Enc0: {doc: The pin is used by quadrature encoder 0.} Enc1: {doc: The pin is used by quadrature encoder 1.} Enc2: {doc: This mode is not supported on ODrive v3.x.} + MechBrake: {doc: This is to support external mechanical brakes.} ODrive.Can.Protocol: values: {Simple: } diff --git a/docs/interfaces.md b/docs/interfaces.md index 93297657..090948f4 100644 --- a/docs/interfaces.md +++ b/docs/interfaces.md @@ -18,25 +18,25 @@ The ODrive can be controlled over various ports and protocols. If you're comfort ## Pinout -| # | Label | `GPIO_MODE_DIGITAL` | `GPIO_MODE_ANALOG_IN` | `GPIO_MODE_UART0` | `GPIO_MODE_PWM0` | `GPIO_MODE_CAN0` | `GPIO_MODE_I2C0` | `GPIO_MODE_ENC0` | `GPIO_MODE_ENC1` | -|----|---------------|------------------------|-----------------------|-------------------|------------------|------------------|------------------|------------------|------------------| -| 0 | _not a pin_ | | | | | | | | | -| 1 | GPIO1 (+) | general purpose | analog input | **UART0.TX** | PWM0.0 | | | | | -| 2 | GPIO2 (+) | general purpose | analog input | **UART0.RX** | PWM0.1 | | | | | -| 3 | GPIO3 | general purpose | **analog input** | | PWM0.2 | | | | | -| 4 | GPIO4 | general purpose | **analog input** | | PWM0.3 | | | | | -| 5 | GPIO5 | general purpose | **analog input** (*) | | | | | | | -| 6 | GPIO6 (*) (+) | **general purpose** | | | | | | | | -| 7 | GPIO7 (*) (+) | **general purpose** | | | | | | | | -| 8 | GPIO8 (*) (+) | **general purpose** | | | | | | | | -| 9 | M0.A | general purpose | | | | | | **ENC0.A** | | -| 10 | M0.B | general purpose | | | | | | **ENC0.B** | | -| 11 | M0.Z | **general purpose** | | | | | | | | -| 12 | M1.A | general purpose | | | | | I2C.SCL | | **ENC1.A** | -| 13 | M1.B | general purpose | | | | | I2C.SDA | | **ENC1.B** | -| 14 | M1.Z | **general purpose** | | | | | | | | -| 15 | _not exposed_ | general purpose | | | | **CAN0.RX** | I2C.SCL | | | -| 16 | _not exposed_ | general purpose | | | | **CAN0.TX** | I2C.SDA | | | +| # | Label | `GPIO_MODE_DIGITAL` | `GPIO_MODE_ANALOG_IN` | `GPIO_MODE_UART0` | `GPIO_MODE_PWM0` | `GPIO_MODE_CAN0` | `GPIO_MODE_I2C0` | `GPIO_MODE_ENC0` | `GPIO_MODE_ENC1` | `GPIO_MODE_MECH_BRAKE` | +|----|---------------|------------------------|-----------------------|-------------------|------------------|------------------|------------------|------------------|------------------|------------------------| +| 0 | _not a pin_ | | | | | | | | | | +| 1 | GPIO1 (+) | general purpose | analog input | **UART0.TX** | PWM0.0 | | | | | mechanical brake | +| 2 | GPIO2 (+) | general purpose | analog input | **UART0.RX** | PWM0.1 | | | | | mechanical brake | +| 3 | GPIO3 | general purpose | **analog input** | | PWM0.2 | | | | | mechanical brake | +| 4 | GPIO4 | general purpose | **analog input** | | PWM0.3 | | | | | mechanical brake | +| 5 | GPIO5 | general purpose | **analog input** (*) | | | | | | | mechanical brake | +| 6 | GPIO6 (*) (+) | **general purpose** | | | | | | | | mechanical brake | +| 7 | GPIO7 (*) (+) | **general purpose** | | | | | | | | mechanical brake | +| 8 | GPIO8 (*) (+) | **general purpose** | | | | | | | | mechanical brake | +| 9 | M0.A | general purpose | | | | | | **ENC0.A** | | | +| 10 | M0.B | general purpose | | | | | | **ENC0.B** | | | +| 11 | M0.Z | **general purpose** | | | | | | | | | +| 12 | M1.A | general purpose | | | | | I2C.SCL | | **ENC1.A** | | +| 13 | M1.B | general purpose | | | | | I2C.SDA | | **ENC1.B** | | +| 14 | M1.Z | **general purpose** | | | | | | | | | +| 15 | _not exposed_ | general purpose | | | | **CAN0.RX** | I2C.SCL | | | | +| 16 | _not exposed_ | general purpose | | | | **CAN0.TX** | I2C.SDA | | | | (*) ODrive v3.5 and later
diff --git a/docs/mechanical-brakes.md b/docs/mechanical-brakes.md index dc2cdaf6..ae3ce821 100644 --- a/docs/mechanical-brakes.md +++ b/docs/mechanical-brakes.md @@ -16,7 +16,6 @@ Name | Type | Default gpio_num | int | 0 enabled | boolean | false is_active_low | boolean | true -pulldown | boolean | true ### gpio_num The GPIO pin number, according to the silkscreen labels on ODrive. Set with these commands: @@ -33,9 +32,6 @@ Enables/disables the operation of the mechanical brake. ### is_active_low Most safety braking systems are active low, e.g. when the power is off, the brake is on. If the system uses brake drive electronics which use active high logic, flip this bit then reconsider the safety implications of your design... -### pulldown -If `true`, it enables the GPIO pulldown resistor. If `false`, it enables the GPIO pullup resistor. - ### Example Let's say we're hacking away on an old ABB robotic arm. We've wired a 24V brake drive circuit triggered by GPIO5. When GPIO5 is driven, it will release the brakes on the axis we're moving. diff --git a/tools/odrive/enums.py b/tools/odrive/enums.py index 17409599..8ca03c21 100644 --- a/tools/odrive/enums.py +++ b/tools/odrive/enums.py @@ -16,6 +16,7 @@ GPIO_MODE_PWM0 = 8 GPIO_MODE_ENC0 = 9 GPIO_MODE_ENC1 = 10 GPIO_MODE_ENC2 = 11 +GPIO_MODE_MECH_BRAKE = 12 # ODrive.Can.Protocol PROTOCOL_SIMPLE = 0 @@ -45,6 +46,7 @@ ENCODER_MODE_SINCOS = 2 ENCODER_MODE_SPI_ABS_CUI = 256 ENCODER_MODE_SPI_ABS_AMS = 257 ENCODER_MODE_SPI_ABS_AEAT = 258 +ENCODER_MODE_SPI_ABS_RLS = 259 # ODrive.Controller.ControlMode CONTROL_MODE_VOLTAGE_CONTROL = 0 From 801bda211e36da93255166f5a2b9fc77a7c0ea52 Mon Sep 17 00:00:00 2001 From: Shaun Meehan Date: Thu, 27 Aug 2020 22:02:25 -0700 Subject: [PATCH 21/48] Changed the GPIO configuration for the mechanical brake to only take effect at boot --- Firmware/MotorControl/mechanical_brake.cpp | 10 +++------- docs/mechanical-brakes.md | 2 ++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Firmware/MotorControl/mechanical_brake.cpp b/Firmware/MotorControl/mechanical_brake.cpp index b70334ff..21a98881 100644 --- a/Firmware/MotorControl/mechanical_brake.cpp +++ b/Firmware/MotorControl/mechanical_brake.cpp @@ -14,13 +14,9 @@ void MechanicalBrake::release() { get_gpio(config_.gpio_num).write(config_.is_active_low ? 1 : 0); } -void MechanicalBrake::set_enabled(bool enable) { - Stm32Gpio gpio = get_gpio(config_.gpio_num); - - // We need this flag to alert the system to the configuration on boot - odrv.config_.gpio_modes[config_.gpio_num] = ODriveIntf::GPIO_MODE_MECH_BRAKE; - +void MechanicalBrake::set_enabled(bool enable) { if (enable) { - gpio.config(GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW); + // We need this flag to alert the system to the configuration on boot + odrv.config_.gpio_modes[config_.gpio_num] = ODriveIntf::GPIO_MODE_MECH_BRAKE; } } \ No newline at end of file diff --git a/docs/mechanical-brakes.md b/docs/mechanical-brakes.md index ae3ce821..3dde1e18 100644 --- a/docs/mechanical-brakes.md +++ b/docs/mechanical-brakes.md @@ -22,12 +22,14 @@ The GPIO pin number, according to the silkscreen labels on ODrive. Set with thes ``` ..mechanical_brake.config.gpio_num = <1, 2, 3, 4, 5, 6, 7, 8> ``` +After GPIO pin number is changed, you'll need to run `.save_configuration()` and `.reboot()` for changes to take effect. ### enabled Enables/disables the operation of the mechanical brake. ``` ..mechanical_brake.config.enabled = ``` +After mechanical brake is enabled or disabled, you'll need to run `.save_configuration()` and `.reboot()` for changes to take effect. ### is_active_low Most safety braking systems are active low, e.g. when the power is off, the brake is on. If the system uses brake drive electronics which use active high logic, flip this bit then reconsider the safety implications of your design... From 0882c71beb1ecef858f4e021fe31852503c0dada Mon Sep 17 00:00:00 2001 From: Shaun Meehan Date: Thu, 3 Sep 2020 18:59:14 -0700 Subject: [PATCH 22/48] Removed apply_config and enable functions, removed automatic gpio swap, fixed readme and odrive-interface to match --- Firmware/MotorControl/main.cpp | 1 - Firmware/MotorControl/mechanical_brake.cpp | 21 ++++++--------------- Firmware/MotorControl/mechanical_brake.hpp | 6 +----- Firmware/odrive-interface.yaml | 1 - docs/mechanical-brakes.md | 19 ++++++++----------- 5 files changed, 15 insertions(+), 33 deletions(-) diff --git a/Firmware/MotorControl/main.cpp b/Firmware/MotorControl/main.cpp index 09838764..65609497 100644 --- a/Firmware/MotorControl/main.cpp +++ b/Firmware/MotorControl/main.cpp @@ -103,7 +103,6 @@ static bool config_apply_all() { && axes[i].controller_.apply_config() && axes[i].min_endstop_.apply_config() && axes[i].max_endstop_.apply_config() - && axes[i].mechanical_brake_.apply_config() && motors[i].apply_config() && axes[i].apply_config(); } diff --git a/Firmware/MotorControl/mechanical_brake.cpp b/Firmware/MotorControl/mechanical_brake.cpp index 21a98881..c9d3602f 100644 --- a/Firmware/MotorControl/mechanical_brake.cpp +++ b/Firmware/MotorControl/mechanical_brake.cpp @@ -1,22 +1,13 @@ #include -bool MechanicalBrake::apply_config() { - config_.parent = this; - set_enabled(config_.enabled); - return true; -} - void MechanicalBrake::engage() { - get_gpio(config_.gpio_num).write(config_.is_active_low ? 0 : 1); + if (odrv.config_.gpio_modes[config_.gpio_num] == ODriveIntf::GPIO_MODE_MECH_BRAKE){ + get_gpio(config_.gpio_num).write(config_.is_active_low ? 0 : 1); + } } void MechanicalBrake::release() { - get_gpio(config_.gpio_num).write(config_.is_active_low ? 1 : 0); + if (odrv.config_.gpio_modes[config_.gpio_num] == ODriveIntf::GPIO_MODE_MECH_BRAKE){ + get_gpio(config_.gpio_num).write(config_.is_active_low ? 1 : 0); + } } - -void MechanicalBrake::set_enabled(bool enable) { - if (enable) { - // We need this flag to alert the system to the configuration on boot - odrv.config_.gpio_modes[config_.gpio_num] = ODriveIntf::GPIO_MODE_MECH_BRAKE; - } -} \ No newline at end of file diff --git a/Firmware/MotorControl/mechanical_brake.hpp b/Firmware/MotorControl/mechanical_brake.hpp index ae8373fd..26362ce5 100644 --- a/Firmware/MotorControl/mechanical_brake.hpp +++ b/Firmware/MotorControl/mechanical_brake.hpp @@ -7,13 +7,11 @@ class MechanicalBrake : public ODriveIntf::MechanicalBrakeIntf { public: struct Config_t { uint16_t gpio_num = 0; - bool enabled = false; bool is_active_low = true; // custom setters MechanicalBrake* parent = nullptr; - void set_gpio_num(uint16_t value) { gpio_num = value; parent->apply_config(); } - void set_enabled(uint32_t value) { enabled = value; parent->apply_config(); } + void set_gpio_num(uint16_t value) { gpio_num = value; } }; MechanicalBrake() {} @@ -21,8 +19,6 @@ class MechanicalBrake : public ODriveIntf::MechanicalBrakeIntf { MechanicalBrake::Config_t config_; Axis* axis_ = nullptr; - bool apply_config(); - void set_enabled(bool enabled); void release(); void engage(); }; diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index 8c527d04..3d31d252 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -924,7 +924,6 @@ interfaces: c_is_class: False attributes: gpio_num: {type: uint16, c_setter: set_gpio_num} - enabled: {type: bool, c_setter: set_enabled} is_active_low: bool functions: engage: diff --git a/docs/mechanical-brakes.md b/docs/mechanical-brakes.md index 3dde1e18..ab2164e1 100644 --- a/docs/mechanical-brakes.md +++ b/docs/mechanical-brakes.md @@ -14,7 +14,6 @@ Each axis supports one mechanical brake. The following properties are accessible Name | Type | Default --- | -- | -- gpio_num | int | 0 -enabled | boolean | false is_active_low | boolean | true ### gpio_num @@ -24,26 +23,24 @@ The GPIO pin number, according to the silkscreen labels on ODrive. Set with thes ``` After GPIO pin number is changed, you'll need to run `.save_configuration()` and `.reboot()` for changes to take effect. -### enabled -Enables/disables the operation of the mechanical brake. -``` -..mechanical_brake.config.enabled = -``` -After mechanical brake is enabled or disabled, you'll need to run `.save_configuration()` and `.reboot()` for changes to take effect. - ### is_active_low Most safety braking systems are active low, e.g. when the power is off, the brake is on. If the system uses brake drive electronics which use active high logic, flip this bit then reconsider the safety implications of your design... +### Enabling +The configuration of the mechanical brake will enable the brake functionality. There's no need to specifically 'enable' this feature. + + ### Example Let's say we're hacking away on an old ABB robotic arm. We've wired a 24V brake drive circuit triggered by GPIO5. When GPIO5 is driven, it will release the brakes on the axis we're moving. +We need to notify the axis of the GPIO number we've attached our brake to, and configure the ODrive pin mode to `GPIO_MODE_MECH_BRAKE`: ``` ..mechanical_brake.config.gpio_num = 5 -..mechanical_brake.config.enabled = True +.config.gpio5_mode = GPIO_MODE_MECH_BRAKE ``` -Don't forget to save and reboot: +Pin configurations only take effect after a save/reboot so don't forget to run: ``` .save_configuration() .reboot() @@ -55,7 +52,7 @@ Depending on your system this could be a dangerous experiment. Ensure that you h ``` ..mechanical_brake.release() ``` -Note: If a brake is enabled, it will be engaged/disengaged during the next state machine step. +Note: If a brake is configured, it will be automatically engaged/disengaged during the next state machine step. After you're satisfied with the testing, you can re-enable the brake using the command From d2b469eca0adb53cd9945dffff589df303df58b5 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Wed, 9 Sep 2020 09:14:55 +0200 Subject: [PATCH 23/48] add top level HWIL test script --- tools/odrive/tests/run_all_tests.sh | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100755 tools/odrive/tests/run_all_tests.sh diff --git a/tools/odrive/tests/run_all_tests.sh b/tools/odrive/tests/run_all_tests.sh new file mode 100755 index 00000000..ab04a99c --- /dev/null +++ b/tools/odrive/tests/run_all_tests.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail + +declare -a tests=('analog_input_test.py' + 'calibration_test.py' + 'can_test.py' + 'closed_loop_test.py' + 'encoder_test.py' + 'fibre_test.py' + 'integration_test.py' + 'nvm_test.py' + 'pwm_input_test.py' + 'step_dir_test.py' + 'uart_ascii_test.py' + ) +summary="" + +for test in "${tests[@]}"; do + (ipython3 "$test" -- --test-rig-yaml ../../test-rig-rpi.yaml || true) | tee /tmp/odrivetest.log + if grep "All tests passed!" /tmp/odrivetest.log; then + summary="$summary - $test: passed"$'\n' + else + summary="$summary - $test: failed"$'\n' + fi + + echo "########################" + echo "Current status:" + echo -n "$summary" + echo "########################" +done From 4c5761c120c20e82b399d43ff2e58b548b9f4a01 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 10 Sep 2020 19:31:29 -0400 Subject: [PATCH 24/48] Reset Ibus in reset_current_control --- Firmware/MotorControl/motor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Firmware/MotorControl/motor.cpp b/Firmware/MotorControl/motor.cpp index c7e50128..f22c46c2 100644 --- a/Firmware/MotorControl/motor.cpp +++ b/Firmware/MotorControl/motor.cpp @@ -51,6 +51,7 @@ void Motor::reset_current_control() { current_control_.v_current_control_integral_d = 0.0f; current_control_.v_current_control_integral_q = 0.0f; current_control_.acim_rotor_flux = 0.0f; + current_control_.Ibus = 0.0f; } // @brief Tune the current controller based on phase resistance and inductance From 28b40c9bd47fc3d218987a6566e03243fdd33271 Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Thu, 10 Sep 2020 19:48:36 -0400 Subject: [PATCH 25/48] Fix for high commanded currents during lockin ramp. --- Firmware/MotorControl/axis.cpp | 8 ++++---- Firmware/MotorControl/sensorless_estimator.cpp | 6 ++++-- Firmware/MotorControl/sensorless_estimator.hpp | 3 ++- docs/commands.md | 8 ++++---- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index 310a7a8a..27e30faa 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -234,9 +234,9 @@ bool Axis::run_lockin_spin(const LockinConfig_t &lockin_config) { float x = 0.0f; run_control_loop([&]() { float phase = wrap_pm_pi(lockin_config.ramp_distance * x); - float I_mag = lockin_config.current * x; + float torque = lockin_config.current * motor_.config_.torque_constant * x; x += current_meas_period / lockin_config.ramp_time; - if (!motor_.update(I_mag, phase, 0.0f)) + if (!motor_.update(torque, phase, 0.0f)) return false; return x < 1.0f; }); @@ -265,7 +265,7 @@ bool Axis::run_lockin_spin(const LockinConfig_t &lockin_config) { distance += vel * current_meas_period; phase = wrap_pm_pi(phase + vel * current_meas_period); - if (!motor_.update(lockin_config.current, phase, vel)) + if (!motor_.update(lockin_config.current * motor_.config_.torque_constant, phase, vel)) return false; return !spin_done(true); //vel_override to go to next phase }); @@ -281,7 +281,7 @@ bool Axis::run_lockin_spin(const LockinConfig_t &lockin_config) { distance += vel * current_meas_period; phase = wrap_pm_pi(phase + vel * current_meas_period); - if (!motor_.update(lockin_config.current, phase, vel)) + if (!motor_.update(lockin_config.current * motor_.config_.torque_constant, phase, vel)) return false; return !spin_done(); }); diff --git a/Firmware/MotorControl/sensorless_estimator.cpp b/Firmware/MotorControl/sensorless_estimator.cpp index aebbc09b..4c521b34 100644 --- a/Firmware/MotorControl/sensorless_estimator.cpp +++ b/Firmware/MotorControl/sensorless_estimator.cpp @@ -70,13 +70,15 @@ bool SensorlessEstimator::update() { } // predict PLL phase with velocity - pll_pos_ = wrap_pm_pi(pll_pos_ + current_meas_period * vel_estimate_); + pll_pos_ = wrap_pm_pi(pll_pos_ + current_meas_period * vel_estimate_erad_); // update PLL phase with observer permanent magnet phase phase_ = fast_atan2(eta[1], eta[0]); float delta_phase = wrap_pm_pi(phase_ - pll_pos_); pll_pos_ = wrap_pm_pi(pll_pos_ + current_meas_period * pll_kp * delta_phase); // update PLL velocity - vel_estimate_ += current_meas_period * pll_ki * delta_phase; + vel_estimate_erad_ += current_meas_period * pll_ki * delta_phase; + // convert to mechanical turns/s for controller usage. + vel_estimate_ = vel_estimate_erad_ / (std::max((float)axis_->motor_.config_.pole_pairs, 1.0f) * 2.0f * M_PI); vel_estimate_valid_ = true; return true; diff --git a/Firmware/MotorControl/sensorless_estimator.hpp b/Firmware/MotorControl/sensorless_estimator.hpp index 95992ae0..27f6f1c9 100644 --- a/Firmware/MotorControl/sensorless_estimator.hpp +++ b/Firmware/MotorControl/sensorless_estimator.hpp @@ -20,7 +20,8 @@ public: Error error_ = ERROR_NONE; float phase_ = 0.0f; // [rad] float pll_pos_ = 0.0f; // [rad] - float vel_estimate_ = 0.0f; // [rad/s] + float vel_estimate_ = 0.0f; // [turn/s] + float vel_estimate_erad_ = 0.0f; // [rad/s] bool vel_estimate_valid_ = false; // float pll_kp_ = 0.0f; // [rad/s / rad] // float pll_ki_ = 0.0f; // [(rad/s^2) / rad] diff --git a/docs/commands.md b/docs/commands.md index 1b41b30f..a621d578 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -82,15 +82,15 @@ All variables that are part of a `[...].config` object can be saved to non-volat ## Setting up sensorless The ODrive can run without encoder/hall feedback, but there is a minimum speed, usually around a few hunderd RPM. -To give an example, suppose you have a motor with 7 pole pairs, and you want to spin it at 3000 RPM. Then you would set the `input_vel` to `3000 * 2*pi/60 * 7 = 2199 rad/s electrical`. - -Below are some suggested starting parameters that you can use. Note that you _must_ set the `pm_flux_linkage` correctly for sensorless mode to work. +Below are some suggested starting parameters that you can use. Note that you _must_ set the `pm_flux_linkage` correctly for sensorless mode to work. Motor calibration and setup must also be completed before sensorless mode will work. ``` odrv0.axis0.controller.config.vel_gain = 0.01 odrv0.axis0.controller.config.vel_integrator_gain = 0.05 odrv0.axis0.controller.config.control_mode = 2 -odrv0.axis0.controller.input_vel = 400 +odrv0.axis0.controller.input_vel = 10 +odrv0.axis0.controller.config.vel_limit = +odrv0.axis0.motor.config.current_lim = 2 * odrv0.axis0.config.sensorless_ramp.current odrv0.axis0.motor.config.direction = 1 odrv0.axis0.sensorless_estimator.config.pm_flux_linkage = 5.51328895422 / ( * ) ``` From b952a5e7545f6d39f9a46cfcbadb7f3f99901077 Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Thu, 10 Sep 2020 19:48:36 -0400 Subject: [PATCH 26/48] Fix for high commanded currents during lockin ramp. --- Firmware/MotorControl/axis.cpp | 8 ++++---- Firmware/MotorControl/sensorless_estimator.cpp | 6 ++++-- Firmware/MotorControl/sensorless_estimator.hpp | 3 ++- docs/commands.md | 8 ++++---- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index 6a89e3c3..16b98bbe 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -238,9 +238,9 @@ bool Axis::run_lockin_spin(const LockinConfig_t &lockin_config) { float x = 0.0f; run_control_loop([&]() { float phase = wrap_pm_pi(lockin_config.ramp_distance * x); - float I_mag = lockin_config.current * x; + float torque = lockin_config.current * motor_.config_.torque_constant * x; x += current_meas_period / lockin_config.ramp_time; - if (!motor_.update(I_mag, phase, 0.0f)) + if (!motor_.update(torque, phase, 0.0f)) return false; return x < 1.0f; }); @@ -269,7 +269,7 @@ bool Axis::run_lockin_spin(const LockinConfig_t &lockin_config) { distance += vel * current_meas_period; phase = wrap_pm_pi(phase + vel * current_meas_period); - if (!motor_.update(lockin_config.current, phase, vel)) + if (!motor_.update(lockin_config.current * motor_.config_.torque_constant, phase, vel)) return false; return !spin_done(true); //vel_override to go to next phase }); @@ -285,7 +285,7 @@ bool Axis::run_lockin_spin(const LockinConfig_t &lockin_config) { distance += vel * current_meas_period; phase = wrap_pm_pi(phase + vel * current_meas_period); - if (!motor_.update(lockin_config.current, phase, vel)) + if (!motor_.update(lockin_config.current * motor_.config_.torque_constant, phase, vel)) return false; return !spin_done(); }); diff --git a/Firmware/MotorControl/sensorless_estimator.cpp b/Firmware/MotorControl/sensorless_estimator.cpp index d70c7d2d..878b6ee7 100644 --- a/Firmware/MotorControl/sensorless_estimator.cpp +++ b/Firmware/MotorControl/sensorless_estimator.cpp @@ -66,13 +66,15 @@ bool SensorlessEstimator::update() { } // predict PLL phase with velocity - pll_pos_ = wrap_pm_pi(pll_pos_ + current_meas_period * vel_estimate_); + pll_pos_ = wrap_pm_pi(pll_pos_ + current_meas_period * vel_estimate_erad_); // update PLL phase with observer permanent magnet phase phase_ = fast_atan2(eta[1], eta[0]); float delta_phase = wrap_pm_pi(phase_ - pll_pos_); pll_pos_ = wrap_pm_pi(pll_pos_ + current_meas_period * pll_kp * delta_phase); // update PLL velocity - vel_estimate_ += current_meas_period * pll_ki * delta_phase; + vel_estimate_erad_ += current_meas_period * pll_ki * delta_phase; + // convert to mechanical turns/s for controller usage. + vel_estimate_ = vel_estimate_erad_ / (std::max((float)axis_->motor_.config_.pole_pairs, 1.0f) * 2.0f * M_PI); vel_estimate_valid_ = true; return true; diff --git a/Firmware/MotorControl/sensorless_estimator.hpp b/Firmware/MotorControl/sensorless_estimator.hpp index 9f59b28a..a0a6ec3c 100644 --- a/Firmware/MotorControl/sensorless_estimator.hpp +++ b/Firmware/MotorControl/sensorless_estimator.hpp @@ -18,7 +18,8 @@ public: Error error_ = ERROR_NONE; float phase_ = 0.0f; // [rad] float pll_pos_ = 0.0f; // [rad] - float vel_estimate_ = 0.0f; // [rad/s] + float vel_estimate_ = 0.0f; // [turn/s] + float vel_estimate_erad_ = 0.0f; // [rad/s] bool vel_estimate_valid_ = false; // float pll_kp_ = 0.0f; // [rad/s / rad] // float pll_ki_ = 0.0f; // [(rad/s^2) / rad] diff --git a/docs/commands.md b/docs/commands.md index 1b41b30f..a621d578 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -82,15 +82,15 @@ All variables that are part of a `[...].config` object can be saved to non-volat ## Setting up sensorless The ODrive can run without encoder/hall feedback, but there is a minimum speed, usually around a few hunderd RPM. -To give an example, suppose you have a motor with 7 pole pairs, and you want to spin it at 3000 RPM. Then you would set the `input_vel` to `3000 * 2*pi/60 * 7 = 2199 rad/s electrical`. - -Below are some suggested starting parameters that you can use. Note that you _must_ set the `pm_flux_linkage` correctly for sensorless mode to work. +Below are some suggested starting parameters that you can use. Note that you _must_ set the `pm_flux_linkage` correctly for sensorless mode to work. Motor calibration and setup must also be completed before sensorless mode will work. ``` odrv0.axis0.controller.config.vel_gain = 0.01 odrv0.axis0.controller.config.vel_integrator_gain = 0.05 odrv0.axis0.controller.config.control_mode = 2 -odrv0.axis0.controller.input_vel = 400 +odrv0.axis0.controller.input_vel = 10 +odrv0.axis0.controller.config.vel_limit = +odrv0.axis0.motor.config.current_lim = 2 * odrv0.axis0.config.sensorless_ramp.current odrv0.axis0.motor.config.direction = 1 odrv0.axis0.sensorless_estimator.config.pm_flux_linkage = 5.51328895422 / ( * ) ``` From e7f5f907adcb80ffb27534733b028f793b60f833 Mon Sep 17 00:00:00 2001 From: InNoobWeTrust Date: Tue, 15 Sep 2020 17:41:25 +0700 Subject: [PATCH 27/48] Update docker build for v0.5.1 - Docker image now only contain the build environment, not the code. This save development time by not rebuilding docker image everytime source code change. - Build by mounting repo's directory into container, build output and intermediate artifacts is available for inspecting if build fail midway. --- Dockerfile | 20 +++++++++++++------- dockerbuild.sh | 11 ++++------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9739928c..8810dc23 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,16 +7,22 @@ RUN add-apt-repository ppa:team-gcc-arm-embedded/ppa RUN add-apt-repository ppa:jonathonf/tup RUN apt-get update RUN apt-get -y upgrade -RUN apt-get -y install gcc-arm-embedded openocd tup python3.7 build-essential git +RUN apt-get -y install gcc-arm-embedded openocd tup python3.7 python3-yaml python3-jinja2 python3-jsonschema build-essential git # Build step below does not know about debian's python naming schemme RUN ln -s /usr/bin/python3.7 /usr/bin/python -# Copy the firmware tree into the container -RUN mkdir ODrive -COPY . ODrive +RUN mkdir -p ODrive WORKDIR ODrive/Firmware -# Hack around Tup's dependency on FUSE -RUN tup generate build.sh -RUN ./build.sh +# Must attach the firmware tree into the container +CMD \ + # Regenerate python interface + python interface_generator_stub.py \ + --definitions odrive-interface.yaml \ + --template ../tools/enums_template.j2 \ + --output ../tools/odrive/enums.py && \ + # Hack around Tup's dependency on FUSE + tup init && \ + tup generate build.sh && \ + ./build.sh diff --git a/dockerbuild.sh b/dockerbuild.sh index 779b9bf1..acf77e9d 100755 --- a/dockerbuild.sh +++ b/dockerbuild.sh @@ -1,6 +1,6 @@ function cleanup { echo "Removing previous build artifacts" - rm -rf build + rm -rf build/ Firmware/autogen Firmware/build Firmware/.tup docker rm odrive-build-cont } @@ -13,14 +13,11 @@ function gc { function build { cleanup - echo "Building the firmware" + echo "Building the build-environment image" docker build -t odrive-build-img . - echo "Create container" - docker create --name odrive-build-cont odrive-build-img:latest - - echo "Extract build artifacts" - docker cp odrive-build-cont:ODrive/Firmware/build . + echo "Build in container" + docker run -v $(pwd):/ODrive --name odrive-build-cont odrive-build-img:latest } function usage { From a741177cae7a3eec695ac7cf12dd2b96973e6df3 Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Wed, 16 Sep 2020 22:42:37 -0400 Subject: [PATCH 28/48] Fix for issue where using sensorless mode with input mode VEL_RAMP would cause the motor to try and reach a very high speed at the end of the sensorless ramp --- CHANGELOG.md | 3 +++ Firmware/MotorControl/axis.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6185264..d739a254 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ Please add a note of your changes below this heading if you make a Pull Request. * `axis.motor.thermal_current_lim` has been removed. Instead a new property is available `axis.motor.effective_current_lim` which contains the effective current limit including any thermal limits. * `axis.motor.get_inverter_temp()`, `axis.motor.inverter_temp_limit_lower` and `axis.motor.inverter_temp_limit_upper` have been moved to seperate fet thermistor object under `axis.fet_thermistor`. `get_inverter_temp()` function has been renamed to `temp` and is now a read-only property. * `axis.config.counts_per_step` is now `axis.config.turns_per_step` +* Outputs of `axis.sensorless_estimator` are now in turns/s instead of electrical rad/s +* Fixed bug of high current during lockin-ramp caused by `motor::update()` expecting a torque command instead of current +* Fixed bug where commanded velocity was extremely high just after sensorless ramp when using `input_mode` INPUT_MODE_VEL_RAMP caused by `vel_setpoint` and `axis.config.sensorless_ramp.vel` being in different units # Releases diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index 27e30faa..3385d420 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -555,7 +555,7 @@ void Axis::run_state_machine_loop() { if (status) { // call to controller.reset() that happend when arming means that vel_setpoint // is zeroed. So we make the setpoint the spinup target for smooth transition. - controller_.vel_setpoint_ = config_.sensorless_ramp.vel; + controller_.vel_setpoint_ = config_.sensorless_ramp.vel / (2.0f * M_PI * motor_.config_.pole_pairs); status = run_sensorless_control_loop(); } } break; From b089573feaeaa3ab51e56f02d1cf895b353b85a4 Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Wed, 16 Sep 2020 22:42:37 -0400 Subject: [PATCH 29/48] Fix for issue where using sensorless mode with input mode VEL_RAMP would cause the motor to try and reach a very high speed at the end of the sensorless ramp --- CHANGELOG.md | 3 +++ Firmware/MotorControl/axis.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12b17c06..3a6c0c76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,9 @@ Please add a note of your changes below this heading if you make a Pull Request. * `axis.motor.thermal_current_lim` has been removed. Instead a new property is available `axis.motor.effective_current_lim` which contains the effective current limit including any thermal limits. * `axis.motor.get_inverter_temp()`, `axis.motor.inverter_temp_limit_lower` and `axis.motor.inverter_temp_limit_upper` have been moved to seperate fet thermistor object under `axis.fet_thermistor`. `get_inverter_temp()` function has been renamed to `temp` and is now a read-only property. * `axis.config.counts_per_step` is now `axis.config.turns_per_step` +* Outputs of `axis.sensorless_estimator` are now in turns/s instead of electrical rad/s +* Fixed bug of high current during lockin-ramp caused by `motor::update()` expecting a torque command instead of current +* Fixed bug where commanded velocity was extremely high just after sensorless ramp when using `input_mode` INPUT_MODE_VEL_RAMP caused by `vel_setpoint` and `axis.config.sensorless_ramp.vel` being in different units # Releases diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index 16b98bbe..52150800 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -561,7 +561,7 @@ void Axis::run_state_machine_loop() { if (status) { // call to controller.reset() that happend when arming means that vel_setpoint // is zeroed. So we make the setpoint the spinup target for smooth transition. - controller_.vel_setpoint_ = config_.sensorless_ramp.vel; + controller_.vel_setpoint_ = config_.sensorless_ramp.vel / (2.0f * M_PI * motor_.config_.pole_pairs); status = run_sensorless_control_loop(); } } break; From e9cd716d9fc79eb30f55adda12d2929cd2f04e2a Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Mon, 21 Sep 2020 18:46:10 -0400 Subject: [PATCH 30/48] Updated getting started guide Basic Wiring image, updated references to 48V to 56V --- docs/getting-started.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 497f01b9..98e47401 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -41,7 +41,7 @@ permalink: /
-* A power supply (12V-24V for the 24V board variant, 12V-48V for the 48V board variant). A battery is also fine. Some advice on choosing a power supply can be found [here](https://things-in-motion.blogspot.com/2018/12/how-to-select-right-power-source-for.html). +* A power supply (12V-24V for the 24V board variant, 12V-56V for the 56V board variant). A battery is also fine. Some advice on choosing a power supply can be found [here](https://things-in-motion.blogspot.com/2018/12/how-to-select-right-power-source-for.html).
What voltage variant do I have?
On all ODrives shipped July 2018 or after have a silkscreen label clearly indicating the voltage variant. @@ -61,13 +61,13 @@ All non-power I/O is 3.3V output and 5V tolerant on input, on ODrive v3.3 and ne ### Wiring up the encoders Connect the encoder(s) to J4. The A,B phases are required, and the Z (index pulse) is optional. The A,B and Z lines have 3.3k pull up resistors, for use with open-drain encoder outputs. For single ended push-pull signals with weak drive current (\<4mA), you may want to desolder the pull-ups. -![Image of ODrive all hooked up](https://docs.google.com/drawings/d/e/2PACX-1vTCD0P40Cd-wvD7Fl8UYEaxp3_UL81oI4qUVqrrCJPi6tkJeSs2rsffIXQRpdu6rNZs6-2mRKKYtILG/pub?w=1716&h=1281) +![Image of ODrive all hooked up](https://docs.google.com/drawings/d/e/2PACX-1vTpJziAisrkvV1kTL4vckAJkmJ-BAvTwN1GeZZNCNwpTHv47Cf8bpz-gJqK2Z3un6FCHT4E-rcuUg6c/pub?w=1716&h=1281) ### Safety & Power UP
Always think safety before powering up the ODrive if motors are attached. Consider what might happen if the motor spins as soon as power is applied.
-* Unlike some devices, the ODrive does not recieve power over the USB port so the 24/48 volt power input is required even just to communicate with it using USB. It is ok to power up the ODrive before or after connecting the USB cable. +* Unlike some devices, the ODrive does not recieve power over the USB port so the 24/56 volt power input is required even just to communicate with it using USB. It is ok to power up the ODrive before or after connecting the USB cable. * To power up the ODrive, connect the power source to the DC terminals. Make sure to pay attention to the polarity. A small spark is normal. This is caused by the capacitors charging up. ## Downloading and Installing Tools From 95e1e3d6c955c23bb897ed6c6a33ccea4b04fa21 Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Wed, 23 Sep 2020 17:15:30 -0400 Subject: [PATCH 31/48] Added note about AMT23x absolute encoder problem and workarounds. --- docs/encoders.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/encoders.md b/docs/encoders.md index 06cfb12b..1932018c 100644 --- a/docs/encoders.md +++ b/docs/encoders.md @@ -170,6 +170,8 @@ Apart from (incremental) quadrature encoders, ODrive also supports absolute SPI Some of these chips come with evaluation boards that can simplify mounting the chips to your motor. For our purposes if you are using an evaluation board you should select the settings for 3.3v. +**Note:** The AMT23x family has a hardware bug that causes them to not properly tristate the MISO line. To use them with ODrive, there are two workarounds. One is to sequence power to the encoder a second or two after the ODrive recieves power. This allows 1 encoder to be used without issue. Another solution is to add a tristate buffer, such as the 74AHC1G125SE, on the MISO line between the ODrive and each AMT23x encoder. Tie the enable pin on the buffer to the CS line for the respective encoder. This allows for more than one AMT23x encoder, or one AMT23x and another SPI encoder, to be used at the same time. + 1. Connect the encoder to the ODrive's SPI interface: - The encoder's SCK, MISO (aka "DATA" on CUI encoders), GND and 3.3V should connect to the ODrive pins with the same label. From 486eb9025fabc99783f1f587e329e67f1d5f09c5 Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Wed, 23 Sep 2020 17:15:30 -0400 Subject: [PATCH 32/48] Added note about AMT23x absolute encoder problem and workarounds. --- docs/encoders.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/encoders.md b/docs/encoders.md index 442388b5..c9d1dbf7 100644 --- a/docs/encoders.md +++ b/docs/encoders.md @@ -146,6 +146,8 @@ Apart from (incremental) quadrature encoders, ODrive also supports absolute SPI Some of these chips come with evaluation boards that can simplify mounting the chips to your motor. For our purposes if you are using an evaluation board you should select the settings for 3.3v. +**Note:** The AMT23x family has a hardware bug that causes them to not properly tristate the MISO line. To use them with ODrive, there are two workarounds. One is to sequence power to the encoder a second or two after the ODrive recieves power. This allows 1 encoder to be used without issue. Another solution is to add a tristate buffer, such as the 74AHC1G125SE, on the MISO line between the ODrive and each AMT23x encoder. Tie the enable pin on the buffer to the CS line for the respective encoder. This allows for more than one AMT23x encoder, or one AMT23x and another SPI encoder, to be used at the same time. + 1. Connect the encoder to the ODrive's SPI interface: - The encoder's SCK, MISO (aka "DATA" on CUI encoders), GND and 3.3V should connect to the ODrive pins with the same label. From 383a261fa59029a9c5530bad8b8669f1b489d741 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Thu, 24 Sep 2020 17:56:26 +0200 Subject: [PATCH 33/48] add -g flag for release mode Including debug information doesn't influence the optimizer. --- Firmware/Tupfile.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Firmware/Tupfile.lua b/Firmware/Tupfile.lua index 96733f55..84412357 100644 --- a/Firmware/Tupfile.lua +++ b/Firmware/Tupfile.lua @@ -133,6 +133,7 @@ FLAGS += '-DUSE_HAL_DRIVER' FLAGS += '-mthumb' FLAGS += '-mfloat-abi=hard' FLAGS += { '-Wall', '-Wdouble-promotion', '-Wfloat-conversion', '-fdata-sections', '-ffunction-sections'} +FLAGS += '-g' -- linker flags LDFLAGS += board.ldflags @@ -142,7 +143,7 @@ LDFLAGS += '-Wl,--undefined=uxTopUsedPriority' -- debug build if tup.getconfig("DEBUG") == "true" then - FLAGS += '-g -gdwarf-2' + FLAGS += '-gdwarf-2' OPT += '-Og' else OPT += '-O2' From eb98762a56219d23f279286a9d35dfd31ac01289 Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Sat, 26 Sep 2020 23:17:30 -0400 Subject: [PATCH 34/48] Update top level gitignore for gui artifacts --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 66a8990f..c94fc787 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,8 @@ ODrive\.files ODrive\.includes Firmware/Tests/bin/ + +# GUI +GUI/dist_electron +GUI/node_modules +GUI/build \ No newline at end of file From feb866c45c90181f62e01a492f6b018c6f392eaa Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Sat, 26 Sep 2020 23:17:30 -0400 Subject: [PATCH 35/48] Update top level gitignore for gui artifacts --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 66a8990f..c94fc787 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,8 @@ ODrive\.files ODrive\.includes Firmware/Tests/bin/ + +# GUI +GUI/dist_electron +GUI/node_modules +GUI/build \ No newline at end of file From 7831d795235e5ef8535e4b46621a0721b458ec8f Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sun, 27 Sep 2020 16:19:51 -0700 Subject: [PATCH 36/48] release v0.5.1 --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d739a254..8b3e0c81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Unreleased Features Please add a note of your changes below this heading if you make a Pull Request. -# Release Candidate -## [0.5.1] - Date TBD +# Releases +## [0.5.1] - 2020-09-27 ### Added * Added motor `torque_constant`: units of torque are now [Nm] instead of just motor current. * [Motor thermistors support](docs/thermistors.md) @@ -16,11 +16,11 @@ Please add a note of your changes below this heading if you make a Pull Request. * `axis.motor.get_inverter_temp()`, `axis.motor.inverter_temp_limit_lower` and `axis.motor.inverter_temp_limit_upper` have been moved to seperate fet thermistor object under `axis.fet_thermistor`. `get_inverter_temp()` function has been renamed to `temp` and is now a read-only property. * `axis.config.counts_per_step` is now `axis.config.turns_per_step` * Outputs of `axis.sensorless_estimator` are now in turns/s instead of electrical rad/s + +### Fixed * Fixed bug of high current during lockin-ramp caused by `motor::update()` expecting a torque command instead of current * Fixed bug where commanded velocity was extremely high just after sensorless ramp when using `input_mode` INPUT_MODE_VEL_RAMP caused by `vel_setpoint` and `axis.config.sensorless_ramp.vel` being in different units - -# Releases ## [0.5.0] - 2020-08-03 ### Added * AC Induction Motor support. From 2961714aca96fdbec54dfcf46424d92b2a8dccdf Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sun, 27 Sep 2020 18:21:24 -0700 Subject: [PATCH 37/48] banner saying docs pertains to newest firmware --- docs/_layouts/default.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 4d8029e6..86df64d9 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -16,7 +16,7 @@ -
+
The docs reflect firmware version 0.5.1. There are many breaking changes. Please find docs for v0.4.12 here.
From 5e0d5fde04fdb2a3077308f99ff00a94f740db63 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Mon, 28 Sep 2020 10:25:55 +0200 Subject: [PATCH 38/48] enable custom Github Pages autogen --- .github/workflows/documentation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 18f8786e..5f7d892f 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -2,7 +2,7 @@ name: Build and publish HTML documentation website on: push: - branches: [ feature/doc_autogen ] + branches: [ master ] jobs: jekyll: From 56a6da5b4bf485080ed2113794afc53a0c9e6b80 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Mon, 28 Sep 2020 11:10:17 +0200 Subject: [PATCH 39/48] fix documentation autogen issues --- .github/workflows/documentation.yml | 1 + Firmware/fibre/tools/interface_generator.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 5f7d892f..bc89083f 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -61,6 +61,7 @@ jobs: git config user.name "${GITHUB_ACTOR}" git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" git add -f docs/_site + git add -f .nojekyll git commit -m "jekyll build from Action ${GITHUB_SHA}" git push --force origin HEAD:${REMOTE_BRANCH} env: diff --git a/Firmware/fibre/tools/interface_generator.py b/Firmware/fibre/tools/interface_generator.py index 659d97f6..2dcf9c83 100644 --- a/Firmware/fibre/tools/interface_generator.py +++ b/Firmware/fibre/tools/interface_generator.py @@ -328,7 +328,7 @@ def regularize_valuetype(path, name, elem): elem['flags'][k]['value'] = 0 if current_bit is None else (1 << current_bit) bit = bit if current_bit is None else current_bit + 1 if 'nullflag' in elem: - elem['flags'] = OrderedDict([(elem['nullflag'], {'value': 0, 'bit': None}), *elem['flags'].items()]) + elem['flags'] = OrderedDict([(elem['nullflag'], OrderedDict({'name': elem['nullflag'], 'value': 0, 'bit': None})), *elem['flags'].items()]) elem['values'] = elem['flags'] elem['is_flags'] = True elem['is_enum'] = True @@ -653,6 +653,7 @@ env.filters['skip_first'] = lambda x: list(x)[1:] env.filters['to_c_string'] = lambda x: '\n'.join(('"' + line.replace('"', '\\"') + '"') for line in json.dumps(x, separators=(',', ':')).replace('{"name"', '\n{"name"').split('\n')) env.filters['tokenize'] = tokenize env.filters['diagonalize'] = lambda lst: [lst[:i + 1] for i in range(len(lst))] +env.filters['debug'] = lambda x: print(x) template = env.from_string(template_file.read()) From 0f74eb9faa2fe0b2fa994002fcd251629f8c1290 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Mon, 28 Sep 2020 18:56:26 +0200 Subject: [PATCH 40/48] make hardfault handler more easy to debug --- Firmware/Board/v3/Src/stm32f4xx_it.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Firmware/Board/v3/Src/stm32f4xx_it.c b/Firmware/Board/v3/Src/stm32f4xx_it.c index 1e69bcb9..69feb861 100644 --- a/Firmware/Board/v3/Src/stm32f4xx_it.c +++ b/Firmware/Board/v3/Src/stm32f4xx_it.c @@ -35,6 +35,7 @@ #include "stm32f4xx.h" #include "stm32f4xx_it.h" #include "cmsis_os.h" +#include /* USER CODE BEGIN 0 */ #include @@ -85,6 +86,13 @@ void get_regs(void** stack_ptr) { void* volatile pc __attribute__((unused)) = stack_ptr[6]; // Program counter void* volatile psr __attribute__((unused)) = stack_ptr[7]; // Program status register + void* volatile cfsr __attribute__((unused)) = (void*)SCB->CFSR; // Configurable fault status register + void* volatile cpacr __attribute__((unused)) = (void*)SCB->CPACR; + void* volatile fpccr __attribute__((unused)) = (void*)FPU->FPCCR; + + volatile bool preciserr __attribute__((unused)) = (uint32_t)cfsr & 0x200; + volatile bool ibuserr __attribute__((unused)) = (uint32_t)cfsr & 0x100; + volatile int stay_looping = 1; while(stay_looping); } From d12c17708f786a87e3b935e02f93e443b96b2d20 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Tue, 29 Sep 2020 11:54:25 +0200 Subject: [PATCH 41/48] move .nojekyll file --- .github/workflows/documentation.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index bc89083f..485546ad 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -54,14 +54,14 @@ jobs: bundle install && \ JEKYLL_ENV=production bundle exec jekyll build " - touch .nojekyll + touch docs/.nojekyll - name: Push to documentation branch run: | git config user.name "${GITHUB_ACTOR}" git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" git add -f docs/_site - git add -f .nojekyll + git add -f docs/.nojekyll git commit -m "jekyll build from Action ${GITHUB_SHA}" git push --force origin HEAD:${REMOTE_BRANCH} env: From c070480d98e39f97b7532057c3ee5a47e6f8263f Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Tue, 29 Sep 2020 18:23:18 +0200 Subject: [PATCH 42/48] fix docs page directory structure --- .github/workflows/documentation.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 485546ad..e1335aa5 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -54,14 +54,16 @@ jobs: bundle install && \ JEKYLL_ENV=production bundle exec jekyll build " + mv docs/_site _site + rm -rdf docs + mv _site docs touch docs/.nojekyll - name: Push to documentation branch run: | git config user.name "${GITHUB_ACTOR}" git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" - git add -f docs/_site - git add -f docs/.nojekyll + git add -f docs git commit -m "jekyll build from Action ${GITHUB_SHA}" git push --force origin HEAD:${REMOTE_BRANCH} env: From 47e5c693ba2ccfb0800ebfa3008caea8ceb0f2fe Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Tue, 29 Sep 2020 18:47:46 +0200 Subject: [PATCH 43/48] temporarily disable API documentation --- docs/_layouts/default.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 86df64d9..d3035973 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -42,7 +42,7 @@
  • {{ item.title }}
  • {% endfor %} {% else %} - {% include apiindex.html %} + {% endif %} From 51c9047c351d6a0cd3d3a57f75d97aaea3d92c20 Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Tue, 29 Sep 2020 17:11:13 -0400 Subject: [PATCH 44/48] Added note to CAN documentation about bus crash if two ODrives are connected without node ID configuration --- docs/can-protocol.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/can-protocol.md b/docs/can-protocol.md index 0b3f0c84..5ac54750 100644 --- a/docs/can-protocol.md +++ b/docs/can-protocol.md @@ -73,7 +73,7 @@ Configuration of the CAN parameters should be done via USB before putting the de To set the desired baud rate, use `.can.set_baud_rate()`. The baud rate can be done without rebooting the device. If you'd like to keep the baud rate, simply call `.save_configuration()` before rebooting. -Each axis looks like a separate node on the bus. Thus, they both have the two properties `can_node_id` and `can_node_id_extended`. The node ID can be from 0 to 63 (0x3F) inclusive, or, if extended CAN IDs are used, from 0 to 16777215 (0xFFFFFF). +Each axis looks like a separate node on the bus. Thus, they both have the two properties `can_node_id` and `can_node_id_extended`. The node ID can be from 0 to 63 (0x3F) inclusive, or, if extended CAN IDs are used, from 0 to 16777215 (0xFFFFFF). If you want to connect more than one ODrive on a CAN bus, you must set different node IDs for the second ODrive or they will conflict and crash the bus. ### Example Configuration From 55e59a4532f21254a251225dc27018c1a0262efe Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Tue, 29 Sep 2020 18:28:00 +0200 Subject: [PATCH 45/48] fix docs page --- .github/workflows/documentation.yml | 14 +++++++++----- docs/_layouts/default.html | 6 +++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index e1335aa5..7bc8b8db 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -52,12 +52,16 @@ jobs: cd /srv/jekyll/docs && \ bundle config path vendor/bundle && \ bundle install && \ - JEKYLL_ENV=production bundle exec jekyll build + bundle exec jekyll build --baseurl \"\" + cd .. + mv docs/_site _site + rm -rdf docs + mv _site docs + touch docs/.nojekyll " - mv docs/_site _site - rm -rdf docs - mv _site docs - touch docs/.nojekyll + # Extra checks to reduce likelihood of defect build + test -f docs/CNAME + test -f docs/index.html - name: Push to documentation branch run: | diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index d3035973..0a63814f 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -42,7 +42,7 @@
  • {{ item.title }}
  • {% endfor %} {% else %} - + {% include apiindex.html %} {% endif %} @@ -79,7 +79,7 @@ {% if page.edit_url %} - {% assign edit_url = "https://www.github.com/madcowswe/ODrive/edit/master/" | append: edit_url %} + {% assign edit_url = "https://www.github.com/madcowswe/ODrive/edit/master/" | append: page.edit_url %} {% else %} {% assign edit_url = "https://www.github.com/madcowswe/ODrive/edit/master/docs/" | append: pagename | append: ".md" %} {% endif %} @@ -91,7 +91,7 @@ - {{page.download.text}} + {{page.download.text}}
    {% endif %}
    From 1ad5b7dc6b546b14931783425c7cc7afcf87e21e Mon Sep 17 00:00:00 2001 From: Paul Guenette Date: Wed, 30 Sep 2020 11:03:04 -0400 Subject: [PATCH 46/48] Add --upgrade flag to pip install odrive --- docs/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index e7b8392a..8c1c0604 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -81,7 +81,7 @@ Most instructions in this guide refer to a utility called `odrivetool`, so you s 2. Launch the command prompt. * __Anaconda__: In the start menu, type `Anaconda Prompt` Enter * __Standalone Python__: In the start menu, type `cmd` Enter -3. Install the ODrive tools by typing `pip install odrive` Enter +3. Install the ODrive tools by typing `pip install --upgrade odrive` Enter 4. Plug in a USB cable into the microUSB connector on ODrive, and connect it to your PC. 5. Use the [Zadig](http://zadig.akeo.ie/) utility to set ODrive driver to libusb-win32. * Check 'List All Devices' from the options menu, and select 'ODrive 3.x Native Interface (Interface 2)'. With that selected in the device list choose 'libusb-win32' from the target driver list and then press the large 'install driver' button. From 400b442fa2fcc0e87cf1ab7217d1c7115e3a4c54 Mon Sep 17 00:00:00 2001 From: Paul Guenette Date: Wed, 30 Sep 2020 11:13:44 -0400 Subject: [PATCH 47/48] More --upgrade flags, add upgrading section --- docs/getting-started.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 8c1c0604..eb4d49a0 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -19,6 +19,7 @@ permalink: / - [Other control modes](#other-control-modes) - [Watchdog Timer](#watchdog-timer) - [What's next?](#whats-next) +- [Upgrading from 0.4.12](#upgrading-from-0412) @@ -107,13 +108,13 @@ brew install libusb ``` 5. Now that you have Python 3 and all the package managers, run: ```bash -pip3 install odrive +pip3 install --upgrade odrive ``` __Troubleshooting__ 1. Permission Errors: Just run the previous command in sudo ```bash -sudo pip3 install odrive +sudo pip3 install --upgrade odrive ``` 2. Dependency Errors: If the installer doesn't complete and you get a dependency @@ -126,7 +127,7 @@ Try step 5 again ### Linux 1. [Install Python 3](https://www.python.org/downloads/). (for example, on Ubuntu, `sudo apt install python3 python3-pip`) -2. Install the ODrive tools by opening a terminal and typing `sudo pip3 install odrive` Enter +2. Install the ODrive tools by opening a terminal and typing `sudo pip3 install --upgrade odrive` Enter * This should automatically add the udev rules. If this fails for some reason you can add them manually: ```bash echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="0d[0-9][0-9]", MODE="0666"' | sudo tee /etc/udev/rules.d/91-odrive.rules @@ -373,3 +374,7 @@ You can now: * See how you can improve the behavior during the startup procedure, like [bypassing encoder calibration](encoders.md#encoder-with-index-signal). If you have any issues or any questions please get in touch. The [ODrive Community](https://discourse.odriverobotics.com/) warmly welcomes you. + + +## Upgrading from 0.4.12 +A new version (0.5.1) of ODrive firmware has released, complete with a new odrivetool. Follow the installation instructions, making sure to add the `--upgrade` flag to pip commands, and check out the [Changelog](../CHANGELOG.md) for changes! From 3a5eda9a4f09ce0e0cf74d87a442f62cb8a6fe63 Mon Sep 17 00:00:00 2001 From: Paul Guenette Date: Wed, 30 Sep 2020 11:24:23 -0400 Subject: [PATCH 48/48] Fix changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 931406f7..0652edf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,8 +17,8 @@ Please add a note of your changes below this heading if you make a Pull Request. * `.motor.gate_driver` was moved to `.gate_driver`. * `.min_endstop.pullup` and `.max_endstop.pullup` were removed. Use `.config.gpioX_mode = GPIO_MODE_DIGITAL / GPIO_MODE_DIGITAL_PULL_UP / GPIO_MODE_DIGITAL_PULL_DOWN` instead. -# Release Candidate -## [0.5.1] - Date TBD +# Releases +## [0.5.1] - 2020-09-27 ### Added * Added motor `torque_constant`: units of torque are now [Nm] instead of just motor current. * [Motor thermistors support](docs/thermistors.md)