From 50436709dbbbcb3fb00acf9f76671c851ef72c00 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Sun, 25 Feb 2018 19:59:29 -0800 Subject: [PATCH] Reorganize config parameters All configurable parameters are now exposed on the protocol in objects called "[...].config". Those are the same parameters that are saved to NVM. --- Firmware/MotorControl/commands.cpp | 93 +++++++++++++++++++++++------- Firmware/MotorControl/config.cpp | 10 ++-- Firmware/MotorControl/low_level.c | 4 +- Firmware/MotorControl/low_level.h | 15 ++--- Firmware/README.md | 58 ++++++++++++------- tools/explore_odrive.py | 11 ++++ 6 files changed, 136 insertions(+), 55 deletions(-) diff --git a/Firmware/MotorControl/commands.cpp b/Firmware/MotorControl/commands.cpp index 98dea15d..deec308d 100644 --- a/Firmware/MotorControl/commands.cpp +++ b/Firmware/MotorControl/commands.cpp @@ -8,6 +8,7 @@ #include "commands.h" #include "low_level.h" +#include "axis.h" #include "protocol.hpp" #include "freertos_vars.h" #include "utils.h" @@ -88,41 +89,60 @@ void motors_1_set_current_setpoint_func(void) { set_current_setpoint(&motors[1], motors[1].set_current_setpoint_args.current_setpoint); } - +bool test_bool = true; // This table specifies which fields and functions are exposed on the USB and UART ports. // TODO: Autogenerate this table. It will come up again very soon in the Arduino library. // clang-format off const Endpoint endpoints[] = { Endpoint::make_property("vbus_voltage", const_cast(&vbus_voltage)), + Endpoint::make_property("test_bool", &test_bool), Endpoint::make_property("UUID_0", (const uint32_t*)(ID_UNIQUE_ADDRESS + 0*4)), Endpoint::make_property("UUID_1", (const uint32_t*)(ID_UNIQUE_ADDRESS + 1*4)), Endpoint::make_property("UUID_2", (const uint32_t*)(ID_UNIQUE_ADDRESS + 2*4)), + Endpoint::make_object("config"), + Endpoint::make_property("brake_resistance", &brake_resistance), + Endpoint::close_tree(), + Endpoint::make_object("axis0"), + Endpoint::make_object("config"), + Endpoint::make_property("enable_control", &axis_configs[0].enable_control_at_start), + Endpoint::make_property("do_calibration", &axis_configs[0].do_calibration_at_start), + Endpoint::close_tree(), + Endpoint::close_tree(), Endpoint::make_object("motor0"), - Endpoint::make_property("control_mode", reinterpret_cast(&motors[0].control_mode)), + Endpoint::make_object("config"), + Endpoint::make_property("control_mode", reinterpret_cast(&motors[0].control_mode)), + Endpoint::make_property("counts_per_step", &motors[0].counts_per_step), + Endpoint::make_property("pole_pairs", &motors[0].pole_pairs), + Endpoint::make_property("pos_gain", &motors[0].pos_gain), + Endpoint::make_property("vel_gain", &motors[0].vel_gain), + Endpoint::make_property("vel_integrator_gain", &motors[0].vel_integrator_gain), + Endpoint::make_property("vel_limit", &motors[0].vel_limit), + Endpoint::make_property("calibration_current", &motors[0].calibration_current), + Endpoint::make_property("resistance_calib_max_voltage", &motors[0].resistance_calib_max_voltage), + Endpoint::make_property("phase_inductance", &motors[0].phase_inductance), + Endpoint::make_property("phase_resistance", &motors[0].phase_resistance), + Endpoint::make_property("motor_type", reinterpret_cast(&motors[0].motor_type)), + Endpoint::make_property("rotor_mode", reinterpret_cast(&motors[0].rotor_mode)), + Endpoint::close_tree(), Endpoint::make_property("error", reinterpret_cast(&motors[0].error)), Endpoint::make_property("pos_setpoint", &motors[0].pos_setpoint), - Endpoint::make_property("pos_gain", &motors[0].pos_gain), Endpoint::make_property("vel_setpoint", &motors[0].vel_setpoint), - Endpoint::make_property("vel_gain", &motors[0].vel_gain), - Endpoint::make_property("vel_integrator_gain", &motors[0].vel_integrator_gain), Endpoint::make_property("vel_integrator_current", &motors[0].vel_integrator_current), - Endpoint::make_property("vel_limit", &motors[0].vel_limit), Endpoint::make_property("current_setpoint", &motors[0].current_setpoint), - Endpoint::make_property("calibration_current", &motors[0].calibration_current), - Endpoint::make_property("phase_inductance", const_cast(&motors[0].phase_inductance)), - Endpoint::make_property("phase_resistance", const_cast(&motors[0].phase_resistance)), Endpoint::make_property("current_meas_phB", const_cast(&motors[0].current_meas.phB)), Endpoint::make_property("current_meas_phC", const_cast(&motors[0].current_meas.phC)), Endpoint::make_property("DC_calib.phB", &motors[0].DC_calib.phB), Endpoint::make_property("DC_calib.phC", &motors[0].DC_calib.phC), Endpoint::make_property("shunt_conductance", &motors[0].shunt_conductance), Endpoint::make_property("phase_current_rev_gain", &motors[0].phase_current_rev_gain), - Endpoint::make_property("thread_ready", reinterpret_cast(&motors[0].thread_ready)), + Endpoint::make_property("thread_ready", &motors[0].thread_ready), Endpoint::make_property("control_deadline", &motors[0].control_deadline), Endpoint::make_property("last_cpu_time", &motors[0].last_cpu_time), Endpoint::make_property("loop_counter", &motors[0].loop_counter), Endpoint::make_object("current_control"), - Endpoint::make_property("current_lim", &motors[0].current_control.current_lim), + Endpoint::make_object("config"), + Endpoint::make_property("current_lim", &motors[0].current_control.current_lim), + Endpoint::close_tree(), Endpoint::make_property("p_gain", &motors[0].current_control.p_gain), Endpoint::make_property("i_gain", &motors[0].current_control.i_gain), Endpoint::make_property("v_current_control_integral_d", &motors[0].current_control.v_current_control_integral_d), @@ -132,6 +152,14 @@ const Endpoint endpoints[] = { Endpoint::make_property("Ibus", const_cast(&motors[0].current_control.Ibus)), Endpoint::close_tree(), Endpoint::make_object("encoder"), + Endpoint::make_object("config"), + Endpoint::make_property("use_index", &motors[0].encoder.use_index), + Endpoint::make_property("calibrated", &motors[0].encoder.calibrated), + Endpoint::make_property("idx_search_speed", &motors[0].encoder.idx_search_speed), + Endpoint::make_property("cpr", &motors[0].encoder.encoder_cpr), + Endpoint::make_property("offset", &motors[0].encoder.encoder_offset), + Endpoint::make_property("motor_dir", &motors[0].encoder.motor_dir), + Endpoint::close_tree(), Endpoint::make_property("phase", const_cast(&motors[0].encoder.phase)), Endpoint::make_property("pll_pos", &motors[0].encoder.pll_pos), Endpoint::make_property("pll_vel", &motors[0].encoder.pll_vel), @@ -154,32 +182,47 @@ const Endpoint endpoints[] = { Endpoint::make_property("current_setpoint", &motors[0].set_current_setpoint_args.current_setpoint), Endpoint::close_tree(), Endpoint::close_tree(), // motor0 + Endpoint::make_object("axis1"), + Endpoint::make_object("config"), + Endpoint::make_property("enable_control", &axis_configs[1].enable_control_at_start), + Endpoint::make_property("do_calibration", &axis_configs[1].do_calibration_at_start), + Endpoint::close_tree(), + Endpoint::close_tree(), Endpoint::make_object("motor1"), - Endpoint::make_property("control_mode", reinterpret_cast(&motors[1].control_mode)), + Endpoint::make_object("config"), + Endpoint::make_property("control_mode", reinterpret_cast(&motors[1].control_mode)), + Endpoint::make_property("counts_per_step", &motors[1].counts_per_step), + Endpoint::make_property("pole_pairs", &motors[1].pole_pairs), + Endpoint::make_property("pos_gain", &motors[1].pos_gain), + Endpoint::make_property("vel_gain", &motors[1].vel_gain), + Endpoint::make_property("vel_integrator_gain", &motors[1].vel_integrator_gain), + Endpoint::make_property("vel_limit", &motors[1].vel_limit), + Endpoint::make_property("calibration_current", &motors[1].calibration_current), + Endpoint::make_property("resistance_calib_max_voltage", &motors[1].resistance_calib_max_voltage), + Endpoint::make_property("phase_inductance", &motors[1].phase_inductance), + Endpoint::make_property("phase_resistance", &motors[1].phase_resistance), + Endpoint::make_property("motor_type", reinterpret_cast(&motors[1].motor_type)), + Endpoint::make_property("rotor_mode", reinterpret_cast(&motors[1].rotor_mode)), + Endpoint::close_tree(), Endpoint::make_property("error", reinterpret_cast(&motors[1].error)), Endpoint::make_property("pos_setpoint", &motors[1].pos_setpoint), - Endpoint::make_property("pos_gain", &motors[1].pos_gain), Endpoint::make_property("vel_setpoint", &motors[1].vel_setpoint), - Endpoint::make_property("vel_gain", &motors[1].vel_gain), - Endpoint::make_property("vel_integrator_gain", &motors[1].vel_integrator_gain), Endpoint::make_property("vel_integrator_current", &motors[1].vel_integrator_current), - Endpoint::make_property("vel_limit", &motors[1].vel_limit), Endpoint::make_property("current_setpoint", &motors[1].current_setpoint), - Endpoint::make_property("calibration_current", &motors[1].calibration_current), - Endpoint::make_property("phase_inductance", const_cast(&motors[1].phase_inductance)), - Endpoint::make_property("phase_resistance", const_cast(&motors[1].phase_resistance)), Endpoint::make_property("current_meas_phB", const_cast(&motors[1].current_meas.phB)), Endpoint::make_property("current_meas_phC", const_cast(&motors[1].current_meas.phC)), Endpoint::make_property("DC_calib.phB", &motors[1].DC_calib.phB), Endpoint::make_property("DC_calib.phC", &motors[1].DC_calib.phC), Endpoint::make_property("shunt_conductance", &motors[1].shunt_conductance), Endpoint::make_property("phase_current_rev_gain", &motors[1].phase_current_rev_gain), - Endpoint::make_property("thread_ready", reinterpret_cast(&motors[1].thread_ready)), + Endpoint::make_property("thread_ready", &motors[1].thread_ready), Endpoint::make_property("control_deadline", &motors[1].control_deadline), Endpoint::make_property("last_cpu_time", &motors[1].last_cpu_time), Endpoint::make_property("loop_counter", &motors[1].loop_counter), Endpoint::make_object("current_control"), - Endpoint::make_property("current_lim", &motors[1].current_control.current_lim), + Endpoint::make_object("config"), + Endpoint::make_property("current_lim", &motors[1].current_control.current_lim), + Endpoint::close_tree(), Endpoint::make_property("p_gain", &motors[1].current_control.p_gain), Endpoint::make_property("i_gain", &motors[1].current_control.i_gain), Endpoint::make_property("v_current_control_integral_d", &motors[1].current_control.v_current_control_integral_d), @@ -189,6 +232,14 @@ const Endpoint endpoints[] = { Endpoint::make_property("Ibus", const_cast(&motors[1].current_control.Ibus)), Endpoint::close_tree(), Endpoint::make_object("encoder"), + Endpoint::make_object("config"), + Endpoint::make_property("use_index", &motors[1].encoder.use_index), + Endpoint::make_property("calibrated", &motors[1].encoder.calibrated), + Endpoint::make_property("idx_search_speed", &motors[1].encoder.idx_search_speed), + Endpoint::make_property("cpr", &motors[1].encoder.encoder_cpr), + Endpoint::make_property("offset", &motors[1].encoder.encoder_offset), + Endpoint::make_property("motor_dir", &motors[1].encoder.motor_dir), + Endpoint::close_tree(), Endpoint::make_property("phase", const_cast(&motors[1].encoder.phase)), Endpoint::make_property("pll_pos", &motors[1].encoder.pll_pos), Endpoint::make_property("pll_vel", &motors[1].encoder.pll_vel), diff --git a/Firmware/MotorControl/config.cpp b/Firmware/MotorControl/config.cpp index 41e97ea6..847a8938 100644 --- a/Firmware/MotorControl/config.cpp +++ b/Firmware/MotorControl/config.cpp @@ -42,7 +42,7 @@ typedef struct { float encoder_idx_search_speed; int32_t encoder_cpr; int32_t encoder_offset; - int32_t motor_dir; + int32_t encoder_motor_dir; } MotorConfig_t; /* Global constant data ------------------------------------------------------*/ @@ -182,7 +182,7 @@ void set_motor_config(const MotorConfig_t* config, Motor_t* motor) { motor->encoder.idx_search_speed = config->encoder_idx_search_speed; motor->encoder.encoder_cpr = config->encoder_cpr; motor->encoder.encoder_offset = config->encoder_offset; - motor->encoder.motor_dir = config->motor_dir; + motor->encoder.motor_dir = config->encoder_motor_dir; } // This function is obviously stupid and should go away (make MotorConfig_t a member of Motor_t) @@ -209,14 +209,14 @@ void get_motor_config(const Motor_t* motor, MotorConfig_t* config) { config->encoder_idx_search_speed = motor->encoder.idx_search_speed; config->encoder_cpr = motor->encoder.encoder_cpr; config->encoder_offset = motor->encoder.encoder_offset; - config->motor_dir = motor->encoder.motor_dir; + config->encoder_motor_dir = motor->encoder.motor_dir; } void init_configuration(void) { MotorConfig_t motor_config[2]; //TODO: we really shouldn't be hardcoding like this - if (NVM_init() || Config::load_config(&motor_config[0], &motor_config[1], &axis_configs[0], &axis_configs[1])) { + if (NVM_init() || Config::load_config(&motor_config[0], &motor_config[1], &axis_configs[0], &axis_configs[1], &brake_resistance)) { //printf("no config found\r\n"); osDelay(5); // load default config // motor_config[0] = MotorConfig_t(); @@ -237,7 +237,7 @@ void save_configuration(void) { get_motor_config(&motors[0], &motor_config[0]); get_motor_config(&motors[1], &motor_config[1]); //TODO: we really shouldn't be hardcoding like this - if (Config::store_config(&motor_config[0], &motor_config[1], &axis_configs[0], &axis_configs[1])) { + if (Config::store_config(&motor_config[0], &motor_config[1], &axis_configs[0], &axis_configs[1], &brake_resistance)) { //printf("saving configuration failed\r\n"); osDelay(5); } } diff --git a/Firmware/MotorControl/low_level.c b/Firmware/MotorControl/low_level.c index 802c91c1..7aadb847 100644 --- a/Firmware/MotorControl/low_level.c +++ b/Firmware/MotorControl/low_level.c @@ -264,6 +264,8 @@ Motor_t motors[] = { }; const size_t num_motors = sizeof(motors) / sizeof(motors[0]); +float brake_resistance = 0.47f; // [ohm] + /* Private constant data -----------------------------------------------------*/ static const float one_by_sqrt3 = 0.57735026919f; static const float sqrt3_by_2 = 0.86602540378f; @@ -271,8 +273,6 @@ static const float current_meas_period = CURRENT_MEAS_PERIOD; static const int current_meas_hz = CURRENT_MEAS_HZ; /* Private variables ---------------------------------------------------------*/ -static float brake_resistance = 0.47f; // [ohm] - /* Function implementations --------------------------------------------------*/ //-------------------------------- diff --git a/Firmware/MotorControl/low_level.h b/Firmware/MotorControl/low_level.h index b5625a25..cd02276d 100644 --- a/Firmware/MotorControl/low_level.h +++ b/Firmware/MotorControl/low_level.h @@ -55,16 +55,16 @@ typedef enum { // Note: these should be sorted from lowest level of control to // highest level of control, to allow "<" style comparisons. typedef enum { - CTRL_MODE_VOLTAGE_CONTROL, - CTRL_MODE_CURRENT_CONTROL, - CTRL_MODE_VELOCITY_CONTROL, - CTRL_MODE_POSITION_CONTROL + CTRL_MODE_VOLTAGE_CONTROL = 0, + CTRL_MODE_CURRENT_CONTROL = 1, + CTRL_MODE_VELOCITY_CONTROL = 2, + CTRL_MODE_POSITION_CONTROL = 3 } Motor_control_mode_t; typedef enum { - MOTOR_TYPE_HIGH_CURRENT, - // MOTOR_TYPE_LOW_CURRENT, //Not yet implemented - MOTOR_TYPE_GIMBAL + MOTOR_TYPE_HIGH_CURRENT = 0, + // MOTOR_TYPE_LOW_CURRENT = 1, //Not yet implemented + MOTOR_TYPE_GIMBAL = 2 } Motor_type_t; typedef struct { @@ -199,6 +199,7 @@ extern const size_t num_motors; extern const float elec_rad_per_enc; /* Exported variables --------------------------------------------------------*/ extern float vbus_voltage; +extern float brake_resistance; extern Motor_t motors[]; /* Exported macro ------------------------------------------------------------*/ /* Exported functions --------------------------------------------------------*/ diff --git a/Firmware/README.md b/Firmware/README.md index bd9602bd..2663138e 100644 --- a/Firmware/README.md +++ b/Firmware/README.md @@ -22,8 +22,8 @@ The project is under active development, so make sure to check the [Changelog](C -## Configuring parameters -To correctly operate the ODrive, you need to supply some parameters. Some are mandatory, and if supplied incorrectly will cause the drive to malfunction. To get good performance you must also tune the drive. +## Configuring the build +To correctly operate the ODrive, you need to supply some parameters. Some are mandatory, and if supplied incorrectly will cause the drive to malfunction. The first thing to set is your board hardware version, located at the top of [Inc/main.h](Inc/main.h). If, for example, you are using the hardware: ODrive v3.2, then you should set it like this: ```C @@ -61,21 +61,38 @@ Note that UART is only supported on ODrive v3.3 and higher. - `UART_PROTOCOL_NONE`: Ignore UART communication - `USE_GPIO_MODE_STEP_DIR`: Step/direction control mode (use in conjunction with `UART_PROTOCOL_NONE`) -### Motor control parameters -The rest of all the parameters are at the top of the [MotorControl/low_level.c](MotorControl/low_level.c) file. Please note that many parameters occur twice, once for each motor. -In it's current state, the motor structs contain both tuning parameters, meant to be set by the developer, and static variables, meant to be modified by the software. Unfortunatly these are mixed together right now, but cleaning this up is a high priority task. +## Controller Configuration +To get good performance you need to tune the ODrive after flashing. -It may be helpful to know that the entry point of each of the motor threads is `void axis_thread_entry` at the top of [MotorControl/axis.cpp](MotorControl/axis.cpp). This is like `main` for each motor, and is probably where you should start reading the code. +The general configuration procedure goes like this: + + 1. Launch `./tools/explore_odrive.py`. This will give you a command prompt where you can modify using simple assignments. + 2. Configure parameters inside the `my_odrive.[...].config` objects. For example to adjust the position gain: `my_odrive.motor0.config.pos_gain = 30` Enter + + The complete list of configurable parameters is: + - `my_odrive.motorN.config.*` + - `my_odrive.axisN.config.*` + + where N is a valid motor number (0 or 1). + + 3. Save the configuration into non-volatile memory: `my_odrive.save_configuration()` Enter + + This will save the properties of all the `[...].config` objects and no other parameters. + 4. Reboot the drive: `my_odrive.reboot()` Enter + +Note that a firmware upgrade at this point will preserve the configuration if and only if the parameters of both firmware versions are identical. Should you need to reset the configuration, you can run `my_odrive.erase_configuration()`. + +__Developers__: Be aware that you can also modify the compile-time defaults for all of these parameters. Most of them you will find at the top of [MotorControl/low_level.c](MotorControl/low_level.c#L50). Note that the configuration parameters there are somewhat intertwined with runtime variables and hardware specific configuration that should not be changed. Also note that all parameters occur twice. ### Mandatory parameters -You must set: -* `ENCODER_CPR`: Encoder Count Per Revolution (CPR). This is 4x the Pulse Per Revolution (PPR) value. -* `POLE_PAIRS`: This is the number of magnet poles in the rotor, **divided by two**. You can simply count the number of permanent magnets in the rotor, if you can see them. Note: this is not the same as the number of coils in the stator. -* `brake_resistance`: This is the resistance of the brake resistor. If you are not using it, you may set it to 0.0f. -* `motor_type`: This is the type of motor being used. Currently two types of motors are supported -- High-current motors (`MOTOR_TYPE_HIGH_CURRENT`) and Gimbal motors (`MOTOR_TYPE_GIMBAL`). +You must set for every motor: +* `my_odrive.motorN.encoder.config.cpr`: Encoder Count Per Revolution (CPR). This is 4x the Pulse Per Revolution (PPR) value. +* `my_odrive.motorN.config.pole_pairs`: This is the number of magnet poles in the rotor, **divided by two**. You can simply count the number of permanent magnets in the rotor, if you can see them. Note: this is not the same as the number of coils in the stator. +* `my_odrive.config.brake_resistance` [Ohm]: This is the resistance of the brake resistor. If you are not using it, you may set it to 0.0f. +* `my_odrive.motorN.config.motor_type`: This is the type of motor being used. Currently two types of motors are supported -- High-current motors (`MOTOR_TYPE_HIGH_CURRENT`) and Gimbal motors (`MOTOR_TYPE_GIMBAL`). ### Motor Modes -The firwmare currently supports two different types of motors, high-current motors, and Gimbal motors. If you're using a regular hobby brushless motor like [this](https://hobbyking.com/en_us/turnigy-aerodrive-sk3-5065-236kv-brushless-outrunner-motor.html) one, you should set `motor_mode` to `MOTOR_TYPE_HIGH_CURRENT`. For high-torque gimbal motors like [this](https://hobbyking.com/en_us/turnigy-hd-5208-brushless-gimbal-motor-bldc.html) one, you should choose `MOTOR_TYPE_GIMBAL`. +The firwmare currently supports two different types of motors, high-current motors, and Gimbal motors. If you're using a regular hobby brushless motor like [this](https://hobbyking.com/en_us/turnigy-aerodrive-sk3-5065-236kv-brushless-outrunner-motor.html) one, you should set `my_odrive.motorN.config.motor_type` to `MOTOR_TYPE_HIGH_CURRENT`. For high-torque gimbal motors like [this](https://hobbyking.com/en_us/turnigy-hd-5208-brushless-gimbal-motor-bldc.html) one, you should choose `MOTOR_TYPE_GIMBAL`. **Further detail:** @@ -86,15 +103,15 @@ If 100's of mA current noise is "large" for you, and you intend to spin the moto ### Tuning parameters The most important parameters are the limits: -* The current limit: `.current_lim = 75.0f, //[A] // Note: consistent with 40v/v gain`. The default current limit, for safety reasons, is set to 10A. This is quite weak, and good for making sure the drive is stable. Once you have tuned the drive, you can increase this to 75A to get some performance. Note that above 75A, you must change the current amplifier gains. +* The current limit: `my_odrive.motorN.current_control.config.current_lim` [A]. The default current limit, for safety reasons, is set to 10A. This is quite weak, and good for making sure the drive is stable. Once you have tuned the drive, you can increase this to 75A to get some performance. Note that above 75A, you must change the current amplifier gains. * Note: The motor current and the current drawn from the power supply is not the same in general. You should not look at the power supply current to see what is going on with the motor current. -* The velocity limit: `.vel_limit = 20000.0f, // [counts/s]`. The motor will be limited to this speed; again the default value is quite slow. -* You can change `.calibration_current` to the largest value you feel comfortable leaving running through the motor continously when the motor is stationary. +* The velocity limit: `my_odrive.motorN.config.vel_limit` [counts/s]. The motor will be limited to this speed; again the default value is quite slow. +* You can change `my_odrive.motorN.config.calibration_current` [A] to the largest value you feel comfortable leaving running through the motor continously when the motor is stationary. The motion control gains are currently manually tuned: -* `.pos_gain = 20.0f, // [(counts/s) / counts]` -* `.vel_gain = 15.0f / 10000.0f, // [A/(counts/s)]` -* `.vel_integrator_gain = 10.0f / 10000.0f, // [A/(counts/s * s)]` +* `my_odrive.motorN.config.pos_gain = 20.0f` [(counts/s) / counts] +* `my_odrive.motorN.config.vel_gain = 15.0f / 10000.0f` [A/(counts/s)] +* `my_odrive.motorN.config.vel_integrator_gain = 10.0f / 10000.0f` [A/(counts/s * s)] An upcoming feature will enable automatic tuning. Until then, here is a rough tuning procedure: * Set the integrator gain to 0 @@ -107,7 +124,8 @@ An upcoming feature will enable automatic tuning. Until then, here is a rough tu ### Optional parameters By default both motors are enabled, and the default control mode is position control. -If you want a different mode, you can change `.control_mode`. To disable a motor, set `.enable_control` and `.do_calibration` to false. +If you want a different mode, you can change `my_odrive.motorN.config.control_mode`. Possible values are `CTRL_MODE_VOLTAGE_CONTROL`, `CTRL_MODE_CURRENT_CONTROL`, `CTRL_MODE_VELOCITY_CONTROL` and `CTRL_MODE_POSITION_CONTROL`. +To disable a motor, set `my_odrive.axisN.config.enable_control` and `my_odrive.axisN.config.do_calibration` to `False`.

## Compiling and downloading firmware @@ -209,7 +227,7 @@ See the [protocol specification](protocol.md) or the [legacy protocol specificat By default the encoder-to-motor calibration will run on every startup. During encoder calibration the rotor must be allowed to rotate without any biased load during startup. That means mass and weak friction loads are fine, but gravity or spring loads are not okay. ### Encoder with Index signal -If you have an encoder with an index (Z) signal, you may avoid having to do the calibration on every startup, and instead use the index signal to re-sync the encoder to a stored calibration. Bleow 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. +If you have an encoder with an index (Z) signal, you may avoid having to do the 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. * All the parameters we will be modifying are in the motor structs at the top of [MotorControl/low_level.c](MotorControl/low_level.c). diff --git a/tools/explore_odrive.py b/tools/explore_odrive.py index 7afb8009..59492a30 100755 --- a/tools/explore_odrive.py +++ b/tools/explore_odrive.py @@ -7,6 +7,17 @@ import odrive.core import argparse import sys +# some enums described in the README +# TODO: transmit as part of the JSON +MOTOR_TYPE_HIGH_CURRENT = 0 +#MOTOR_TYPE_LOW_CURRENT = 1 +MOTOR_TYPE_GIMBAL = 2 + +CTRL_MODE_VOLTAGE_CONTROL = 0, +CTRL_MODE_CURRENT_CONTROL = 1, +CTRL_MODE_VELOCITY_CONTROL = 2, +CTRL_MODE_POSITION_CONTROL = 3 + # Parse arguments parser = argparse.ArgumentParser(description='Load an odrive object to play with in the IPython interactive shell.')