mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-09-20 06:28:03 +08:00
Merge pull request #270 from madcowswe/configurable-stepdir
Configurable stepdir
This commit is contained in:
@@ -3,6 +3,7 @@ Please add a note of your changes below this heading if you make a Pull Request.
|
||||
|
||||
### Added
|
||||
* Overspeed fault
|
||||
* Make step dir gpio pins configurable.
|
||||
|
||||
### Changed
|
||||
* Increased switching frequency from around 8kHz to 24kHz. Control loops still run at 8kHz.
|
||||
|
||||
@@ -26,6 +26,8 @@ Axis::Axis(const AxisHardwareConfig_t& hw_config,
|
||||
controller_.axis_ = this;
|
||||
motor_.axis_ = this;
|
||||
trap_.axis_ = this;
|
||||
|
||||
decode_step_dir_pins();
|
||||
}
|
||||
|
||||
static void step_cb_wrapper(void* ctx) {
|
||||
@@ -67,24 +69,37 @@ bool Axis::wait_for_current_meas() {
|
||||
// step/direction interface
|
||||
void Axis::step_cb() {
|
||||
if (step_dir_active_) {
|
||||
GPIO_PinState dir_pin = HAL_GPIO_ReadPin(hw_config_.dir_port, hw_config_.dir_pin);
|
||||
GPIO_PinState dir_pin = HAL_GPIO_ReadPin(dir_port_, dir_pin_);
|
||||
float dir = (dir_pin == GPIO_PIN_SET) ? 1.0f : -1.0f;
|
||||
controller_.pos_setpoint_ += dir * config_.counts_per_step;
|
||||
}
|
||||
};
|
||||
|
||||
// @brief Enables or disables step/dir input
|
||||
void Axis::set_step_dir_enabled(bool enable) {
|
||||
if (enable) {
|
||||
void Axis::load_default_step_dir_pin_config(
|
||||
const AxisHardwareConfig_t& hw_config, Config_t* config) {
|
||||
config->step_gpio_pin = hw_config.step_gpio_pin;
|
||||
config->dir_gpio_pin = hw_config.dir_gpio_pin;
|
||||
}
|
||||
|
||||
void Axis::decode_step_dir_pins() {
|
||||
step_port_ = get_gpio_port_by_pin(config_.step_gpio_pin);
|
||||
step_pin_ = get_gpio_pin_by_pin(config_.step_gpio_pin);
|
||||
dir_port_ = get_gpio_port_by_pin(config_.dir_gpio_pin);
|
||||
dir_pin_ = get_gpio_pin_by_pin(config_.dir_gpio_pin);
|
||||
}
|
||||
|
||||
// @brief (de)activates step/dir input
|
||||
void Axis::set_step_dir_active(bool active) {
|
||||
if (active) {
|
||||
// Set up the direction GPIO as input
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
GPIO_InitStruct.Pin = hw_config_.dir_pin;
|
||||
GPIO_InitStruct.Pin = dir_pin_;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(hw_config_.dir_port, &GPIO_InitStruct);
|
||||
HAL_GPIO_Init(dir_port_, &GPIO_InitStruct);
|
||||
|
||||
// Subscribe to rising edges of the step GPIO
|
||||
GPIO_subscribe(hw_config_.step_port, hw_config_.step_pin, GPIO_PULLDOWN,
|
||||
GPIO_subscribe(step_port_, step_pin_, GPIO_PULLDOWN,
|
||||
step_cb_wrapper, this);
|
||||
|
||||
step_dir_active_ = true;
|
||||
@@ -92,7 +107,7 @@ void Axis::set_step_dir_enabled(bool enable) {
|
||||
step_dir_active_ = false;
|
||||
|
||||
// Unsubscribe from step GPIO
|
||||
GPIO_unsubscribe(hw_config_.step_port, hw_config_.step_pin);
|
||||
GPIO_unsubscribe(step_port_, step_pin_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +182,6 @@ bool Axis::run_sensorless_spin_up() {
|
||||
|
||||
// Note run_sensorless_control_loop and run_closed_loop_control_loop are very similar and differ only in where we get the estimate from.
|
||||
bool Axis::run_sensorless_control_loop() {
|
||||
set_step_dir_enabled(config_.enable_step_dir);
|
||||
run_control_loop([this](){
|
||||
if (controller_.config_.control_mode >= Controller::CTRL_MODE_POSITION_CONTROL)
|
||||
return error_ |= ERROR_POS_CTRL_DURING_SENSORLESS, false;
|
||||
@@ -180,12 +194,11 @@ bool Axis::run_sensorless_control_loop() {
|
||||
return false; // set_error should update axis.error_
|
||||
return true;
|
||||
});
|
||||
set_step_dir_enabled(false);
|
||||
return check_for_errors();
|
||||
}
|
||||
|
||||
bool Axis::run_closed_loop_control_loop() {
|
||||
set_step_dir_enabled(config_.enable_step_dir);
|
||||
set_step_dir_active(config_.enable_step_dir);
|
||||
run_control_loop([this](){
|
||||
// Note that all estimators are updated in the loop prefix in run_control_loop
|
||||
float current_setpoint;
|
||||
@@ -195,7 +208,7 @@ bool Axis::run_closed_loop_control_loop() {
|
||||
return false; // set_error should update axis.error_
|
||||
return true;
|
||||
});
|
||||
set_step_dir_enabled(false);
|
||||
set_step_dir_active(false);
|
||||
return check_for_errors();
|
||||
}
|
||||
|
||||
|
||||
@@ -45,9 +45,12 @@ public:
|
||||
bool startup_sensorless_control = false; //<! enable sensorless control after calibration/startup
|
||||
bool enable_step_dir = false; //<! enable step/dir input after calibration
|
||||
// For M0 this has no effect if enable_uart is true
|
||||
|
||||
float counts_per_step = 2.0f;
|
||||
|
||||
// Defaults loaded from hw_config in load_configuration in main.cpp
|
||||
uint16_t step_gpio_pin = 0;
|
||||
uint16_t dir_gpio_pin = 0;
|
||||
|
||||
// Spinup settings
|
||||
float ramp_up_time = 0.4f; // [s]
|
||||
float ramp_up_distance = 4 * M_PI; // [rad]
|
||||
@@ -74,7 +77,10 @@ public:
|
||||
bool wait_for_current_meas();
|
||||
|
||||
void step_cb();
|
||||
void set_step_dir_enabled(bool enable);
|
||||
void set_step_dir_active(bool enable);
|
||||
void decode_step_dir_pins();
|
||||
static void load_default_step_dir_pin_config(
|
||||
const AxisHardwareConfig_t& hw_config, Config_t* config);
|
||||
|
||||
bool check_DRV_fault();
|
||||
bool check_PSU_brownout();
|
||||
@@ -168,6 +174,13 @@ public:
|
||||
// variables exposed on protocol
|
||||
Error_t error_ = ERROR_NONE;
|
||||
bool step_dir_active_ = false; // auto enabled after calibration, based on config.enable_step_dir
|
||||
|
||||
// updated from config in constructor, and on protocol hook
|
||||
GPIO_TypeDef* step_port_;
|
||||
uint16_t step_pin_;
|
||||
GPIO_TypeDef* dir_port_;
|
||||
uint16_t dir_pin_;
|
||||
|
||||
State_t requested_state_ = AXIS_STATE_STARTUP_SEQUENCE;
|
||||
State_t task_chain_[10] = { AXIS_STATE_UNDEFINED };
|
||||
State_t& current_state_ = task_chain_[0];
|
||||
@@ -189,6 +202,10 @@ public:
|
||||
make_protocol_property("startup_sensorless_control", &config_.startup_sensorless_control),
|
||||
make_protocol_property("enable_step_dir", &config_.enable_step_dir),
|
||||
make_protocol_property("counts_per_step", &config_.counts_per_step),
|
||||
make_protocol_property("step_gpio_pin", &config_.step_gpio_pin,
|
||||
[](void* ctx) { static_cast<Axis*>(ctx)->decode_step_dir_pins(); }, this),
|
||||
make_protocol_property("dir_gpio_pin", &config_.dir_gpio_pin,
|
||||
[](void* ctx) { static_cast<Axis*>(ctx)->decode_step_dir_pins(); }, this),
|
||||
make_protocol_property("ramp_up_time", &config_.ramp_up_time),
|
||||
make_protocol_property("ramp_up_distance", &config_.ramp_up_distance),
|
||||
make_protocol_property("spin_up_current", &config_.spin_up_current),
|
||||
|
||||
@@ -21,10 +21,8 @@
|
||||
|
||||
|
||||
typedef struct {
|
||||
GPIO_TypeDef* step_port;
|
||||
uint16_t step_pin;
|
||||
GPIO_TypeDef* dir_port;
|
||||
uint16_t dir_pin;
|
||||
uint16_t step_gpio_pin;
|
||||
uint16_t dir_gpio_pin;
|
||||
size_t thermistor_adc_ch;
|
||||
osPriority thread_priority;
|
||||
} AxisHardwareConfig_t;
|
||||
@@ -74,10 +72,8 @@ const size_t thermistor_num_coeffs = sizeof(thermistor_poly_coeffs)/sizeof(therm
|
||||
const BoardHardwareConfig_t hw_configs[2] = { {
|
||||
//M0
|
||||
.axis_config = {
|
||||
.step_port = GPIO_1_GPIO_Port,
|
||||
.step_pin = GPIO_1_Pin,
|
||||
.dir_port = GPIO_2_GPIO_Port,
|
||||
.dir_pin = GPIO_2_Pin,
|
||||
.step_gpio_pin = 1,
|
||||
.dir_gpio_pin = 2,
|
||||
.thermistor_adc_ch = 15,
|
||||
.thread_priority = (osPriority)(osPriorityHigh + (osPriority)1),
|
||||
},
|
||||
@@ -111,15 +107,11 @@ const BoardHardwareConfig_t hw_configs[2] = { {
|
||||
//M1
|
||||
.axis_config = {
|
||||
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 5
|
||||
.step_port = GPIO_7_GPIO_Port,
|
||||
.step_pin = GPIO_7_Pin,
|
||||
.dir_port = GPIO_8_GPIO_Port,
|
||||
.dir_pin = GPIO_8_Pin,
|
||||
.step_gpio_pin = 7,
|
||||
.dir_gpio_pin = 8,
|
||||
#else
|
||||
.step_port = GPIO_3_GPIO_Port,
|
||||
.step_pin = GPIO_3_Pin,
|
||||
.dir_port = GPIO_4_GPIO_Port,
|
||||
.dir_pin = GPIO_4_Pin,
|
||||
.step_gpio_pin = 3,
|
||||
.dir_gpio_pin = 4,
|
||||
#endif
|
||||
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 3
|
||||
.thermistor_adc_ch = 4,
|
||||
|
||||
@@ -65,6 +65,8 @@ void load_configuration(void) {
|
||||
motor_configs[i] = Motor::Config_t();
|
||||
trap_configs[i] = TrapezoidalTrajectory::Config_t();
|
||||
axis_configs[i] = Axis::Config_t();
|
||||
// Default step/dir pins are different, so we need to explicitly load them
|
||||
Axis::load_default_step_dir_pin_config(hw_configs[i].axis_config, &axis_configs[i]);
|
||||
}
|
||||
} else {
|
||||
user_config_loaded_ = true;
|
||||
@@ -178,8 +180,6 @@ int odrive_main(void) {
|
||||
// TODO: make dynamically reconfigurable
|
||||
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 3
|
||||
if (board_config.enable_uart) {
|
||||
axes[0]->config_.enable_step_dir = false;
|
||||
axes[0]->set_step_dir_enabled(false);
|
||||
SetGPIO12toUART();
|
||||
}
|
||||
#endif
|
||||
|
||||
+5
-2
@@ -32,7 +32,10 @@ The ODrive can be controlled over various ports and protocols. If you're comfort
|
||||
(+) on ODrive v3.4 and earlier <br>
|
||||
(*) ODrive v3.5 and later
|
||||
|
||||
ODrive v3.3 and onward have 5V tolerant GPIO pins.
|
||||
Notes:
|
||||
* ODrive v3.3 and onward have 5V tolerant GPIO pins.
|
||||
* ODrive v3.5 and later have some noise supression filters on the default step/dir pins
|
||||
* You can change the step/dir pins using `axis.config.<step/dir>_gpio_pin`.
|
||||
|
||||
### Pin function priorities
|
||||
1. PWM in, if enabled. Disabled by default.
|
||||
@@ -89,7 +92,7 @@ There is an Arduino library that gives some expamples on how to use the ASCII pr
|
||||
This is the simplest possible way of controlling the ODrive. It is also the most primitive and fragile one. So don't use it unless you must interoperate with other hardware that you don't control.
|
||||
|
||||
Pinout:
|
||||
* Step/dir signals: see [Pinout](#pinout) above.
|
||||
* Step/dir signals: see [Pinout](#pinout) above. Note in that section how to reassign the pins.
|
||||
* GND: you must connect the grounds of the devices together. Use any GND pin on J3 of the ODrive.
|
||||
|
||||
To enable step/dir mode for the GPIO, set `<axis>.config.enable_step_dir` to true for each axis that you wish to use this on.
|
||||
|
||||
Reference in New Issue
Block a user