Mechanical Brake feature

This commit is contained in:
Shaun Meehan
2020-08-18 23:37:44 -07:00
parent 6fbd1f7d83
commit 43cb91b3b1
10 changed files with 176 additions and 4 deletions
+7 -1
View File
@@ -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<CurrentLimiter*>(&fet_thermistor),
static_cast<CurrentLimiter*>(&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:
+3 -1
View File
@@ -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.
+8 -1
View File
@@ -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<Axis*, AXIS_COUNT> 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;
@@ -0,0 +1,41 @@
#include <odrive_main.h>
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);
}
}
}
@@ -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
+1
View File
@@ -210,6 +210,7 @@ enum TimingLog_t {
#include <thermistor.hpp>
#include <trapTraj.hpp>
#include <endstop.hpp>
#include <mechanical_brake.hpp>
#include <axis.hpp>
#include <communication/communication.h>
+1
View File
@@ -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',
+11 -1
View File
@@ -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:
+2
View File
@@ -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
+66
View File
@@ -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:
```
<odrv>.<axis>.mechanical_brake.config.gpio_num = <1, 2, 3, 4, 5, 6, 7, 8>
```
### enabled
Enables/disables the operation of the mechanical brake.
```
<odrv>.<axis>.mechanical_brake.config.enabled = <True, False>
```
### 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.
```
<odrv>.<axis>.mechanical_brake.config.gpio_num = 5
<odrv>.<axis>.mechanical_brake.config.enabled = True
```
Don't forget to save and reboot:
```
<odrv>.save_configuration()
<odrv>.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.
```
<odrv>.<axis>.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
```
<odrv>.<axis>.mechanical_brake.engage()
```