Merge branch 'devel' into feature/CAN

This commit is contained in:
Unknown
2019-01-02 12:16:32 -05:00
23 changed files with 234 additions and 63 deletions
+7 -2
View File
@@ -1,8 +1,14 @@
# Unreleased Features
Please add a note of your changes below this heading if you make a Pull Request.
### Added
* `dump_errors()` utility function in odrivetool to dump, decode and optionally clear errors.
# Releases
## [0.4.7] - 2018-11-28
### Added
* Overspeed fault
* Current sense saturation fault.
* Supress startup transients by sampling encoder estimate into position setpoint when entering closed loop control.
* Make step dir gpio pins configurable.
* Configuration variable `encoder.config.zero_count_on_find_idx`, true by default. Set to false to leave the initial encoder count to be where the axis was at boot.
@@ -14,11 +20,10 @@ Please add a note of your changes below this heading if you make a Pull Request.
* Renamed `axis.enable_step_dir` to `axis.step_dir_active`
* New process for working with STM32CubeMX.
## Fixed
### Fixed
* Would get ERROR_CONTROL_DEADLINE_MISSED along with every ERROR_PHASE_RESISTANCE_OUT_OF_RANGE.
* ODrive tool can now run interactive nested scripts with "%run -i script.py"
# Releases
## [0.4.6] - 2018-10-07
### Fixed
* Broken printing of floats on ascii protocol
+1 -1
View File
@@ -66,7 +66,7 @@ void MX_UART4_Init(void)
{
huart4.Instance = UART4;
huart4.Init.BaudRate = 115200;
huart4.Init.BaudRate = 115200; // Provisionally this can be changed to 921600 for faster transfers, the low power Arduinos will not keep up.
huart4.Init.WordLength = UART_WORDLENGTH_8B;
huart4.Init.StopBits = UART_STOPBITS_1;
huart4.Init.Parity = UART_PARITY_NONE;
+4 -2
View File
@@ -271,8 +271,10 @@ bool Encoder::update() {
if (delta_enc > 3)
delta_enc -= 6;
} else {
set_error(ERROR_ILLEGAL_HALL_STATE);
return false;
if (!config_.ignore_illegal_hall_state) {
set_error(ERROR_ILLEGAL_HALL_STATE);
return false;
}
}
} break;
+3 -1
View File
@@ -37,6 +37,7 @@ public:
float offset_float = 0.0f; // Sub-count phase alignment offset
float calib_range = 0.02f;
float bandwidth = 1000.0f;
bool ignore_illegal_hall_state = false;
};
Encoder(const EncoderHardwareConfig_t& hw_config,
@@ -106,7 +107,8 @@ public:
make_protocol_property("offset_float", &config_.offset_float),
make_protocol_property("bandwidth", &config_.bandwidth,
[](void* ctx) { static_cast<Encoder*>(ctx)->update_pll_gains(); }, this),
make_protocol_property("calib_range", &config_.calib_range)
make_protocol_property("calib_range", &config_.calib_range),
make_protocol_property("ignore_illegal_hall_state", &config_.ignore_illegal_hall_state)
)
);
}
+30 -1
View File
@@ -713,4 +713,33 @@ void pwm_in_cb(int channel, uint32_t timestamp) {
last_timestamp[gpio_num - 1] = timestamp;
last_pin_state[gpio_num - 1] = current_pin_state;
last_sample_valid[gpio_num - 1] = true;
}
}
/* Analog speed control input */
static void update_analog_endpoint(const struct PWMMapping_t *map, int gpio)
{
float fraction = get_adc_voltage(get_gpio_port_by_pin(gpio), get_gpio_pin_by_pin(gpio)) / 3.3f;
float value = map->min + (fraction * (map->max - map->min));
get_endpoint(map->endpoint)->set_from_float(value);
}
static void analog_polling_thread(void *)
{
while (true) {
for (int i = 0; i < GPIO_COUNT; i++) {
struct PWMMapping_t *map = &board_config.analog_mappings[i];
if (is_endpoint_ref_valid(map->endpoint))
update_analog_endpoint(map, i + 1);
}
osDelay(10);
}
}
void start_analog_thread()
{
osThreadDef(thread_def, analog_polling_thread, osPriorityLow, 0, 4*512);
osThreadCreate(osThread(thread_def), NULL);
}
+1
View File
@@ -51,6 +51,7 @@ void sync_timers(TIM_HandleTypeDef* htim_a, TIM_HandleTypeDef* htim_b,
void start_general_purpose_adc();
float get_adc_voltage(GPIO_TypeDef* GPIO_port, uint16_t GPIO_pin);
void pwm_in_init();
void start_analog_thread();
void update_brake_current();
+2
View File
@@ -223,6 +223,8 @@ int odrive_main(void) {
axes[i]->start_thread();
}
start_analog_thread();
system_stats_.fully_booted = true;
return 0;
}
+10 -1
View File
@@ -73,7 +73,8 @@ void Motor::DRV8301_setup() {
// Solve for exact gain, then snap down to have equal or larger range as requested
// or largest possible range otherwise
static const float kMargin = 0.90f;
static const float max_output_swing = 1.6f; // [V] out of amplifier
static const float kTripMargin = 1.0f; // Trip level is at edge of linear range of amplifer
static const float max_output_swing = 1.35f; // [V] out of amplifier
float max_unity_gain_current = kMargin * max_output_swing * hw_config_.shunt_conductance; // [A]
float requested_gain = max_unity_gain_current / config_.requested_current_range; // [V/V]
@@ -99,6 +100,8 @@ void Motor::DRV8301_setup() {
phase_current_rev_gain_ = 1.0f / gain_snap_down->first;
// Clip all current control to actual usable range
current_control_.max_allowed_current = max_unity_gain_current * phase_current_rev_gain_;
// Set trip level
current_control_.overcurrent_trip_level = (kTripMargin / kMargin) * current_control_.max_allowed_current;
// We now have the gain settings we want to use, lets set up DRV chip
DRV_SPI_8301_Vars_t* local_regs = &gate_driver_regs_;
@@ -296,6 +299,12 @@ bool Motor::FOC_current(float Id_des, float Iq_des, float phase) {
// For Reporting
ictrl.Iq_setpoint = Iq_des;
// Check for current sense saturation
if (fabsf(current_meas_.phB) > ictrl.overcurrent_trip_level
|| fabsf(current_meas_.phC) > ictrl.overcurrent_trip_level) {
set_error(ERROR_CURRENT_SENSE_SATURATION);
}
// Clarke transform
float Ialpha = -current_meas_.phB - current_meas_.phC;
float Ibeta = one_by_sqrt3 * (current_meas_.phB - current_meas_.phC);
+10 -6
View File
@@ -20,7 +20,8 @@ public:
ERROR_BRAKE_CURRENT_OUT_OF_RANGE = 0x0040,
ERROR_MODULATION_MAGNITUDE = 0x0080,
ERROR_BRAKE_DEADTIME_VIOLATION = 0x0100,
ERROR_UNEXPECTED_TIMER_CALLBACK = 0x0200
ERROR_UNEXPECTED_TIMER_CALLBACK = 0x0200,
ERROR_CURRENT_SENSE_SATURATION = 0x0400
};
enum MotorType_t {
@@ -43,9 +44,10 @@ public:
// Voltage applied at end of cycle:
float final_v_alpha; // [V]
float final_v_beta; // [V]
float Iq_setpoint;
float Iq_measured;
float max_allowed_current;
float Iq_setpoint; // [A]
float Iq_measured; // [A]
float max_allowed_current; // [A]
float overcurrent_trip_level; // [A]
};
// NOTE: for gimbal motors, all units of A are instead V.
@@ -64,7 +66,7 @@ public:
// float current_lim = 70.0f; //[A]
float current_lim = 10.0f; //[A]
// Value used to compute shunt amplifier gains
float requested_current_range = 70.0f; // [A]
float requested_current_range = 60.0f; // [A]
float current_control_bandwidth = 1000.0f; // [rad/s]
};
@@ -153,6 +155,7 @@ public:
.Iq_setpoint = 0.0f,
.Iq_measured = 0.0f,
.max_allowed_current = 0.0f,
.overcurrent_trip_level = 0.0f,
};
DRV8301_FaultType_e drv_fault_ = DRV8301_FaultType_NoFault;
DRV_SPI_8301_Vars_t gate_driver_regs_; //Local view of DRV registers (initialized by DRV8301_setup)
@@ -178,7 +181,8 @@ public:
make_protocol_property("final_v_beta", &current_control_.final_v_beta),
make_protocol_property("Iq_setpoint", &current_control_.Iq_setpoint),
make_protocol_property("Iq_measured", &current_control_.Iq_measured),
make_protocol_property("max_allowed_current", &current_control_.max_allowed_current)
make_protocol_ro_property("max_allowed_current", &current_control_.max_allowed_current),
make_protocol_ro_property("overcurrent_trip_level", &current_control_.overcurrent_trip_level)
),
make_protocol_object("gate_driver",
make_protocol_ro_property("drv_fault", &drv_fault_)
+1
View File
@@ -83,6 +83,7 @@ struct BoardConfig_t {
//<! the brake power if the brake resistor is disabled.
//<! The default is 26V for the 24V board version and 52V for the 48V board version.
PWMMapping_t pwm_mappings[GPIO_COUNT];
PWMMapping_t analog_mappings[GPIO_COUNT];
};
extern BoardConfig_t board_config;
extern bool user_config_loaded_;
+5 -2
View File
@@ -160,8 +160,11 @@ static inline auto make_obj_tree() {
make_protocol_object("gpio2_pwm_mapping", make_protocol_definitions(board_config.pwm_mappings[1])),
make_protocol_object("gpio3_pwm_mapping", make_protocol_definitions(board_config.pwm_mappings[2])),
#endif
make_protocol_object("gpio4_pwm_mapping", make_protocol_definitions(board_config.pwm_mappings[3]))
),
make_protocol_object("gpio4_pwm_mapping", make_protocol_definitions(board_config.pwm_mappings[3])),
make_protocol_object("gpio3_analog_mapping", make_protocol_definitions(board_config.analog_mappings[2])),
make_protocol_object("gpio4_analog_mapping", make_protocol_definitions(board_config.analog_mappings[3]))
),
make_protocol_object("axis0", axes[0]->make_protocol_definitions()),
make_protocol_object("axis1", axes[1]->make_protocol_definitions()),
make_protocol_object("can", odCAN->make_protocol_definitions()),
+1 -1
View File
@@ -221,7 +221,7 @@ GEM
ruby-enum (0.7.2)
i18n
ruby_dep (1.5.0)
rubyzip (1.2.1)
rubyzip (1.2.2)
safe_yaml (1.0.4)
sass (3.5.6)
sass-listen (~> 4.0.0)
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

+1 -1
View File
@@ -22,7 +22,7 @@ The current state of an axis is indicated by `<axis>.current_state`. The user ca
1. `AXIS_STATE_IDLE` Disable motor PWM and do nothing.
2. `AXIS_STATE_STARTUP_SEQUENCE` Run the [startup procedure](#startup-procedure).
3. `AXIS_STATE_FULL_CALIBRATION_SEQUENCE` Run motor calibration and then encoder offset calibration (or encoder index search if `<axis>.encoder.use_index` is `True`).
3. `AXIS_STATE_FULL_CALIBRATION_SEQUENCE` Run motor calibration and then encoder offset calibration (or encoder index search if `<axis>.encoder.config.use_index` is `True`).
4. `AXIS_STATE_MOTOR_CALIBRATION` Measure phase resistance and phase inductance of the motor.
* To store the results set `<axis>.motor.config.pre_calibrated` to `True` and [save the configuration](#saving-the-configuration). After that you don't have to run the motor calibration on the next start up.
* This modifies the variables `<axis>.motor.config.phase_resistance` and `<axis>.motor.config.phase_inductance`.
+1 -1
View File
@@ -2,7 +2,7 @@
The motor controller is a cascaded style position, velocity and current control loop, as per the diagram below. When the control mode is set to position control, the whole loop runs. When running in velocity control mode, the position control part is removed and the velocity command is fed directly in to the second stage input. In current control mode, only the current controller is used.
![Cascaded pos vel I loops](https://static1.squarespace.com/static/58aff26de4fcb53b5efd2f02/t/5b66284a0e2e72aae8818d64/1533421649405/CascadedController.png?format=2500w)
![Cascaded pos vel I loops](https://github.com/madcowswe/ODrive/blob/master/docs/controller_with_ff.png?raw=true)
### Position loop:
The position controller is a P loop with a single proportional gain.
Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

+69 -11
View File
@@ -16,6 +16,7 @@ permalink: /
- [Start `odrivetool`](#start-odrivetool)
- [Configure M0](#configure-m0)
- [Position control of M0](#position-control-of-m0)
- [Other control modes](#other-control-modes)
- [What's next?](#whats-next)
<!-- /TOC -->
@@ -129,10 +130,10 @@ Try step 5 again
## Firmware
**ODrive v3.5 and later**<br>
Your board should come preflashed with firmware. If you run into problems, follow the instructions [here](odrivetool.md#device-firmware-update) on the DFU procedure before you continue.</div>
Your board should come preflashed with firmware. If you run into problems, follow the instructions [here](odrivetool.md#device-firmware-update) on the DFU procedure before you continue.
**ODrive v3.4 and earlier**<br>
Your board does **not** come preflashed with any firmware. Follow the instructions [here](odrivetool.md#device-firmware-update) on the STP Link procedure before you continue.</div>
Your board does **not** come preflashed with any firmware. Follow the instructions [here](odrivetool.md#device-firmware-update) on the STP Link procedure before you continue.
## Start `odrivetool`
To launch the main interactive ODrive tool, type `odrivetool` <kbd>Enter</kbd>. Connect your ODrive and wait for the tool to find it. Now you can, for instance type `odrv0.vbus_voltage` <kbd>Enter</kbd> to inpect the boards main supply voltage.
@@ -165,7 +166,7 @@ For instance, to set the current limit of M0 to 10A you would type: `odrv0.axis0
**Current limit**<br>
`odrv0.axis0.motor.config.current_lim` [A].
The default current limit, for safety reasons, is set to 10A. This is quite weak, but good for making sure the drive is stable. Once you have tuned the oDrive, you can increase this to 75A to increase performance. Note that above 75A, you must change the current amplifier gains. You do this by requesting a different current range. i.e. for 90A on M0: `odrv0.axis0.motor.config.requested_current_range = 90` [A], then save the configuration and reboot as the gains are written out to the DRV (MOSFET driver) only during startup.
The default current limit, for safety reasons, is set to 10A. This is quite weak, but good for making sure the drive is stable. Once you have tuned the oDrive, you can increase this to 60A to increase performance. Note that above 60A, you must change the current amplifier gains. You do this by requesting a different current range. i.e. for 90A on M0: `odrv0.axis0.motor.config.requested_current_range = 90` [A], then save the configuration and reboot as the gains are written out to the DRV (MOSFET driver) only during startup.
*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.*
<details><summary markdown="span">Ok, so tell me how it actually works then...</summary><div markdown="block">
@@ -241,16 +242,73 @@ Let's get motor 0 up and running. The procedure for motor 1 is exactly the same,
2. Type `odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL` <kbd>Enter</kbd>. From now on the ODrive will try to hold the motor's position. If you try to turn it by hand, it will fight you gently. That is unless you bump up `odrv0.axis0.motor.config.current_lim`, in which case it will fight you more fiercely.
3. Send the motor a new position setpoint. `odrv0.axis0.controller.pos_setpoint = 10000` <kbd>Enter</kbd>. The units are in encoder counts.
### Other control modes
The ODrive also supports velocity control and current (torque) control.
## Other control modes
The default control mode is unfiltered position control in the absolute encoder reference frame. You may wish to use a controlled trajectory instead. Or you may wish to control position in a circular frame to allow continous rotation forever without growing the numeric value of the setpoint too large.
You may also wish to control velocity (directly or with a ramping filter).
You can also directly control the current of the motor, which is proportional to torque.
**Velocity control**<br>
Set `odrv0.axis0.controller.config.control_mode = CTRL_MODE_VELOCITY_CONTROL`.
You can now control the velocity with `odrv0.axis0.controller.vel_setpoint = 5000` [count/s].
- [Trajectory control](#trajectory-control)
- [Circular position control](#circular-position-control)
- [Velocity control](#velocity-control)
- [Ramped velocity control](#ramped-velocity-control)
- [Current control](#current-control)
**Current control**<br>
Set `odrv0.axis0.controller.config.control_mode = CTRL_MODE_CURRENT_CONTROL`.
You can now control the current with `odrv0.axis0.controller.current_setpoint = 3` [A].
### Trajectory control
This mode lets you smoothly accelerate, coast, and decelerate the axis from one position to another. With raw position control, the controller simply tries to go to the setpoint as quickly as possible. Using a trajectory lets you tune the feedback gains more aggressively to reject disturbance, while keeping smooth motion.
![Taptraj](TrapTrajPosVel.PNG)<br>
In the above image blue is position and orange is velocity.
#### Parameters
```
<odrv>.<axis>.trap_traj.config.vel_limit = <Float>
<odrv>.<axis>.trap_traj.config.accel_limit = <Float>
<odrv>.<axis>.trap_traj.config.decel_limit = <Float>
<odrv>.<axis>.trap_traj.config.A_per_css = <Float>
```
`vel_limit` is the maximum planned trajectory speed. This sets your coasting speed.<br>
`accel_limit` is the maximum acceleration in counts / sec^2<br>
`decel_limit` is the maximum deceleration in counts / sec^2<br>
`A_per_css` is a value which correlates acceleration (in counts / sec^2) and motor current. It is 0 by default. It is optional, but can improve response of your system if correctly tuned. Keep in mind this will need to change with the load / mass of your system.
All values should be strictly positive (>= 0).
Keep in mind that you must still set your safety limits as before. I recommend you set these a little higher ( > 10%) than the planner values, to give the controller enough control authority.
```
<odrv>.<axis>.motor.config.current_lim = <Float>
<odrv>.<axis>.controller.config.vel_limit = <Float>
```
#### Usage
Use the `move_to_pos` function to move to an absolute position:
```
<odrv>.<axis>.controller.move_to_pos(<Float>)
```
### Circular position control
This mode is useful for continuos incremental position movement. For example a robot rolling indefinitely, or an extruder motor or conveyor belt moving with controlled increments indefinitely.
In the regular position mode, the `pos_setpoint` would grow to a very large value and would lose precision due to floating point rounding.
In this mode, the controller will try to track the position within only one turn of the motor. Specifically, `pos_setpoint` is expected in the range `[0, cpr-1]`, where `cpr` is the number of encoder counts in one revolution. If the `pos_setpoint` is incremented to outside this range (say via step/dir input), it is automatically wrapped around into the correct value.
Note that in this mode `encoder.pos_cpr` is used for feedback in stead of `encoder.pos_estimate`.
If you try to increment the axis with a large step in one go that exceeds `cpr/2` steps, the motor will go to the same angle around the wrong way. This is also the case if there is a large disturbance. If you have an application where you would like to handle larger steps, you can use a virtual CPR that is an integer times larger than your encoder's actual CPR. Set `encoder.config.cpr = N * your_enc_cpr`, where N is some integer. Choose N to give you an appropriate circular space for your application.
### Velocity control
Set `axis.controller.config.control_mode = CTRL_MODE_VELOCITY_CONTROL`.<br>
You can now control the velocity with `axis.controller.vel_setpoint = 5000` [count/s].
### Ramped velocity control
Set `axis.controller.config.control_mode = CTRL_MODE_VELOCITY_CONTROL`.<br>
Set the velocity ramp rate (acceleration): `axis.controller.config.vel_ramp_rate = 2000` [counts/s^2]<br>
Activate the ramped velocity mode: `axis.controller.vel_ramp_enable = True`.<br>
You can now control the velocity with `axis.controller.vel_ramp_target = 5000` [count/s].
### Current control
Set `axis.controller.config.control_mode = CTRL_MODE_CURRENT_CONTROL`.<br>
You can now control the current with `axis.controller.current_setpoint = 3` [A].
*Note: There is no velocity limiting in current control mode. Make sure that you don't overrev the motor, or exceed the max speed for your encoder.*
+2 -2
View File
@@ -8,9 +8,9 @@ Each step is acompanied by some explanation so hopefully you can carry over some
### Hoverboard motor wiring
Hoverboard motors come with three motor phases (usually colored yellow, blue, green) which are thicker, and a set of 5 thinner wires for the hall sensor feedback (usually colored red, yellow, blue, green, black).
You may wire the motor phases in any order into a motor connector on the ODrive, as we will calibrate the phase alignment later anyway. Wire the hall feedback into the ODrive J2 conenctor (make sure that the motor channel number matches) as follows:
You may wire the motor phases in any order into a motor connector on the ODrive, as we will calibrate the phase alignment later anyway. Wire the hall feedback into the ODrive J4 conenctor (make sure that the motor channel number matches) as follows:
| Hall wire | J2 signal |
| Hall wire | J4 signal |
|-----------|-----------|
| Red | 5V |
| Yellow | A |
+2 -14
View File
@@ -14,21 +14,9 @@ Table of Contents:
<!-- /TOC -->
## Error codes
If your ODrive is not working as expected, run `odrivetool` and type `hex(<axis>.error)` <kbd>Enter</kbd> where `<axis>` is the axis that isn't working. This will display a [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) representation of the error code. Each bit represents one error flag.
<details><summary markdown="span">Example</summary><div markdown="block">
Say you got this error output:
```python
In [1]: hex(odrv0.axis0.error)
Out[1]: '0x6'
```
Written in binary, the number `0x6` corresponds to `110`, that means bits 1 and 2 are set (counting starts at 0).
Looking at the reference below, this means that both `ERROR_DC_BUS_UNDER_VOLTAGE` and `ERROR_DC_BUS_OVER_VOLTAGE` occurred.
</div></details>
The axis error may say that some other component has failed. Say it reports `ERROR_ENCODER_FAILED`, then you need to go check the encoder error: `hex(<axis>.encoder.error)`.
If your ODrive is not working as expected, run `odrivetool` and type `dump_errors(odrv0)` <kbd>Enter</kbd>. This will dump a list of all the errors that are present. To also clear all the errors, you can run `dump_errors(odrv0, True)`.
The following sections will give some guidance on the most common errors. You may also check the code for the full list of errors:
* Axis error flags defined [here](../Firmware/MotorControl/axis.hpp).
* Motor error flags defined [here](../Firmware/MotorControl/motor.hpp).
* Encoder error flags defined [here](../Firmware/MotorControl/encoder.hpp).
+41 -11
View File
@@ -11,17 +11,47 @@ AXIS_STATE_ENCODER_INDEX_SEARCH = 6
AXIS_STATE_ENCODER_OFFSET_CALIBRATION = 7
AXIS_STATE_CLOSED_LOOP_CONTROL = 8
AXIS_ERROR_NONE = 0
AXIS_ERROR_INVALID_STATE = 1
#AXIS_ERROR_DC_BUS_UNDER_VOLTAGE = 2
#AXIS_ERROR_DC_BUS_OVER_VOLTAGE = 3
#AXIS_ERROR_CURRENT_MEASUREMENT_TIMEOUT = 4
#AXIS_ERROR_CONTROL_LOOP_TIMEOUT = 5
#AXIS_ERROR_MOTOR_FAILED = 6
#AXIS_ERROR_SENSORLESS_ESTIMATOR_FAILED = 7
#AXIS_ERROR_ENCODER_FAILED = 8
#AXIS_ERROR_CONTROLLER_FAILED = 9
#AXIS_ERROR_POS_CTRL_DURING_SENSORLESS = 10
class errors:
class axis:
ERROR_NONE = 0x00
ERROR_INVALID_STATE = 0x01 #<! an invalid state was requested
ERROR_DC_BUS_UNDER_VOLTAGE = 0x02
ERROR_DC_BUS_OVER_VOLTAGE = 0x04
ERROR_CURRENT_MEASUREMENT_TIMEOUT = 0x08
ERROR_BRAKE_RESISTOR_DISARMED = 0x10 #<! the brake resistor was unexpectedly disarmed
ERROR_MOTOR_DISARMED = 0x20 #<! the motor was unexpectedly disarmed
ERROR_MOTOR_FAILED = 0x40 # Go to motor.hpp for information, check odrvX.axisX.motor.error for error value
ERROR_SENSORLESS_ESTIMATOR_FAILED = 0x80
ERROR_ENCODER_FAILED = 0x100 # Go to encoder.hpp for information, check odrvX.axisX.encoder.error for error value
ERROR_CONTROLLER_FAILED = 0x200
ERROR_POS_CTRL_DURING_SENSORLESS = 0x400
class motor:
ERROR_NONE = 0
ERROR_PHASE_RESISTANCE_OUT_OF_RANGE = 0x0001
ERROR_PHASE_INDUCTANCE_OUT_OF_RANGE = 0x0002
ERROR_ADC_FAILED = 0x0004
ERROR_DRV_FAULT = 0x0008
ERROR_CONTROL_DEADLINE_MISSED = 0x0010
ERROR_NOT_IMPLEMENTED_MOTOR_TYPE = 0x0020
ERROR_BRAKE_CURRENT_OUT_OF_RANGE = 0x0040
ERROR_MODULATION_MAGNITUDE = 0x0080
ERROR_BRAKE_DEADTIME_VIOLATION = 0x0100
ERROR_UNEXPECTED_TIMER_CALLBACK = 0x0200
ERROR_CURRENT_SENSE_SATURATION = 0x0400
class encoder:
ERROR_NONE = 0
ERROR_UNSTABLE_GAIN = 0x01
ERROR_CPR_OUT_OF_RANGE = 0x02
ERROR_NO_RESPONSE = 0x04
ERROR_UNSUPPORTED_ENCODER_MODE = 0x08
ERROR_ILLEGAL_HALL_STATE = 0x10
ERROR_INDEX_NOT_FOUND_YET = 0x20
class controller:
ERROR_NONE = 0
ERROR_OVERSPEED = 0x01
MOTOR_TYPE_HIGH_CURRENT = 0
#MOTOR_TYPE_LOW_CURRENT = 1
+3 -2
View File
@@ -5,7 +5,7 @@ import threading
import fibre
import odrive
import odrive.enums
from odrive.utils import start_liveplotter
from odrive.utils import start_liveplotter, dump_errors
#from odrive.enums import * # pylint: disable=W0614
def print_banner():
@@ -76,7 +76,8 @@ def launch_shell(args, logger, app_shutdown_token):
"""
interactive_variables = {
'start_liveplotter': start_liveplotter
'start_liveplotter': start_liveplotter,
'dump_errors': dump_errors
}
# Expose all enums from odrive.enums
+39 -3
View File
@@ -7,6 +7,7 @@ import platform
import subprocess
import os
from fibre.utils import Event
from odrive.enums import errors
try:
if platform.system() == 'Windows':
@@ -19,13 +20,48 @@ except ImportError:
sys.stdout.flush()
pass
data_rate = 100
plot_rate = 10
num_samples = 1000
_VT100Colors = {
'green': '\x1b[92;1m',
'cyan': '\x1b[96;1m',
'yellow': '\x1b[93;1m',
'red': '\x1b[91;1m',
'default': '\x1b[0m'
}
class OperationAbortedException(Exception):
pass
def dump_errors(odrv, clear=False):
axes = [axis for name, axis in odrv._remote_attributes.items() if 'axis' in name]
for num, axis in enumerate(axes):
print('Axis{}:'.format(num))
# Flatten axis and submodules
# (name, remote_obj, errorcode)
module_decode_map = [
('axis', axis, errors.axis),
('motor', axis.motor, errors.motor),
('encoder', axis.encoder, errors.encoder),
('controller', axis.controller, errors.controller),
]
# Module error decode
for name, remote_obj, errorcodes in module_decode_map:
prefix = ' '*2 + name + ": "
if (remote_obj.error != errorcodes.ERROR_NONE):
print(prefix + _VT100Colors['red'] + "Error(s):" + _VT100Colors['default'])
errorcodes_tup = [(name, val) for name, val in errorcodes.__dict__.items() if 'ERROR_' in name]
for codename, codeval in errorcodes_tup:
if remote_obj.error & codeval != 0:
print(" " + codename)
if clear:
remote_obj.error = errorcodes.ERROR_NONE
else:
print(prefix + _VT100Colors['green'] + "no error" + _VT100Colors['default'])
data_rate = 100
plot_rate = 10
num_samples = 1000
def start_liveplotter(get_var_callback):
"""
Starts a liveplotter.
+1 -1
View File
@@ -1,2 +1,2 @@
@echo off
ipython %~dp0\odrivetool -- %*
ipython "%~dp0\odrivetool" -- %*