mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-09-23 00:59:54 +08:00
Merge branch 'RazorsFrozenTesting' into RazorsEdge
This commit is contained in:
@@ -131,7 +131,7 @@ Not all parameters can be accessed via the ASCII protocol but at least all param
|
||||
```
|
||||
* `property` name of the property, as seen in ODrive Tool
|
||||
* `value` text representation of the value to be written
|
||||
* Example: `w axis0.controller.pos_setpoint -123.456`
|
||||
* Example: `w axis0.controller.input_pos -123.456`
|
||||
|
||||
#### System commands:
|
||||
* `ss` - Save config
|
||||
|
||||
+17
-2
@@ -60,6 +60,21 @@ Possible values are:
|
||||
* `CTRL_MODE_CURRENT_CONTROL`
|
||||
* `CTRL_MODE_VOLTAGE_CONTROL` - this one is not normally used.
|
||||
|
||||
### Input Mode
|
||||
The default input mode is `INPUT_MODE_PASSTHROUGH`.
|
||||
Modes can be selected by changing `<axis>.controller.config.input_mode`.
|
||||
Possible values are:
|
||||
* `INPUT_MODE_INACTIVE`
|
||||
* `INPUT_MODE_PASSTHROUGH`
|
||||
* `INPUT_MODE_VEL_RAMP`
|
||||
* `INPUT_MODE_POS_FILTER`
|
||||
* `INPUT_MODE_MIX_CHANNELS`
|
||||
* `INPUT_MODE_TRAP_TRAJ`
|
||||
* `INPUT_MODE_CURRENT_RAMP`
|
||||
* `INPUT_MODE_MIRROR`
|
||||
|
||||
For more information, see [input_modes](input_modes.md).
|
||||
|
||||
# Control Commands
|
||||
* `<axis>.controller.input_pos = <encoder_counts>`
|
||||
* `<axis>.controller.input_vel = <encoder_counts/s>`
|
||||
@@ -96,7 +111,7 @@ All variables that are part of a `[...].config` object can be saved to non-volat
|
||||
The ODrive can run without encoder/hall feedback, but there is a minimum speed, usually around a few hunderd RPM.
|
||||
However the units of this mode is different from when using an encoder. Velocities are not measured in counts/s, instead it is electrical rad/s. This also applies to the gains. For example, `vel_gain` is in units of `A / (rad/s)` instead of `A / (count/s)`.
|
||||
|
||||
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 `vel_setpoint` to `3000 * 2*pi/60 * 7 = 2199 rad/s electrical`.
|
||||
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.
|
||||
|
||||
@@ -104,7 +119,7 @@ Below are some suggested starting parameters that you can use. Note that you _mu
|
||||
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.vel_setpoint = 400
|
||||
odrv0.axis0.controller.input_vel = 400
|
||||
odrv0.axis0.motor.config.direction = 1
|
||||
odrv0.axis0.sensorless_estimator.config.pm_flux_linkage = 5.51328895422 / (<pole pairs> * <motor kv>)
|
||||
```
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||

|
||||

|
||||
|
||||
Each stage of the control loop is a variation on a [PID controller](https://en.wikipedia.org/wiki/PID_controller). A PID controller is a mathematical model that can be adapted to control a wide variety of systems. This flexibility is essential as it allows the ODrive to be used to control all kinds of mechanical systems.
|
||||
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ If calibration works, congratulations.
|
||||
|
||||
Now try:
|
||||
* `<axis>.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL`
|
||||
* `<axis>.controller.set_vel_setpoint(3000,0) `
|
||||
* `<axis>.controller.input_vel = 3000`
|
||||
let it loop a few times and then set:
|
||||
* `<axis>.requested_state = AXIS_STATE_IDLE`
|
||||
|
||||
|
||||
@@ -247,7 +247,7 @@ Let's get motor 0 up and running. The procedure for motor 1 is exactly the same,
|
||||
</div></details>
|
||||
|
||||
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. If the motor begins to vibrate either immediately or after being disturbed you will need to [lower the controller gains](control.md).
|
||||
3. Send the motor a new position setpoint. `odrv0.axis0.controller.pos_setpoint = 10000` <kbd>Enter</kbd>. The units are in encoder counts.
|
||||
3. Send the motor a new position setpoint. `odrv0.axis0.controller.input_pos = 10000` <kbd>Enter</kbd>. The units are in encoder counts.
|
||||
4. At this point you will probably want to [Properly tune](control.md) the motor controller in order to maximize system performance.
|
||||
|
||||
## Other control modes
|
||||
@@ -328,16 +328,16 @@ You can also execute a move with the [appropriate ascii command](ascii-protocol.
|
||||
To enable Circular position control, set `axis.controller.config.setpoints_in_cpr = True`
|
||||
|
||||
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 the regular position mode, the `input_pos` 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.
|
||||
In this mode, the controller will try to track the position within only one turn of the motor. Specifically, `input_pos` is expected in the range `[0, cpr-1]`, where `cpr` is the number of encoder counts in one revolution. If the `input_pos` 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].
|
||||
You can now control the velocity with `axis.controller.input_vel = 5000` [count/s].
|
||||
|
||||
### Ramped velocity control
|
||||
Set `axis.controller.config.control_mode = CTRL_MODE_VELOCITY_CONTROL`.<br>
|
||||
@@ -347,7 +347,7 @@ You can now control the velocity with `axis.controller.input_vel = 5000` [count/
|
||||
|
||||
### 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].
|
||||
You can now control the current with `axis.controller.input_current = 3` [A].
|
||||
|
||||
Note: If you exceed `vel_limit` in current control mode, the current is reduced. To disable this, set `axis.controller.enable_current_vel_limit = False`.
|
||||
|
||||
|
||||
+10
-10
@@ -112,9 +112,9 @@ The ODrive starts in idle (we will look at changing this later) so we can enable
|
||||
odrv0.save_configuration()
|
||||
odrv0.reboot()
|
||||
odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
|
||||
odrv0.axis0.controller.vel_setpoint = 120
|
||||
odrv0.axis0.controller.input_vel = 120
|
||||
# Your motor should spin here
|
||||
odrv0.axis0.controller.vel_setpoint = 0
|
||||
odrv0.axis0.controller.input_vel = 0
|
||||
odrv0.axis0.requested_state = AXIS_STATE_IDLE
|
||||
```
|
||||
|
||||
@@ -128,31 +128,31 @@ We also have to reboot to activate the PWM input.
|
||||
```txt
|
||||
odrv0.config.gpio3_pwm_mapping.min = -200
|
||||
odrv0.config.gpio3_pwm_mapping.max = 200
|
||||
odrv0.config.gpio3_pwm_mapping.endpoint = odrv0.axis0.controller._remote_attributes['vel_setpoint']
|
||||
odrv0.config.gpio3_pwm_mapping.endpoint = odrv0.axis0.controller._remote_attributes['input_vel']
|
||||
|
||||
odrv0.config.gpio4_pwm_mapping.min = -200
|
||||
odrv0.config.gpio4_pwm_mapping.max = 200
|
||||
odrv0.config.gpio4_pwm_mapping.endpoint = odrv0.axis1.controller._remote_attributes['vel_setpoint']
|
||||
odrv0.config.gpio4_pwm_mapping.endpoint = odrv0.axis1.controller._remote_attributes['input_vel']
|
||||
|
||||
odrv0.save_configuration()
|
||||
odrv0.reboot()
|
||||
```
|
||||
|
||||
Now we can check that the sticks are writing to the velocity setpoint. Move the stick, print `vel_setpoint`, move to a different position, check again.
|
||||
Now we can check that the sticks are writing to the velocity setpoint. Move the stick, print `input_vel`, move to a different position, check again.
|
||||
```txt
|
||||
In [1]: odrv0.axis1.controller.vel_setpoint
|
||||
In [1]: odrv0.axis1.controller.input_vel
|
||||
Out[1]: 0.1904754638671875
|
||||
|
||||
In [2]: odrv0.axis1.controller.vel_setpoint
|
||||
In [2]: odrv0.axis1.controller.input_vel
|
||||
Out[2]: 0.1904754638671875
|
||||
|
||||
In [3]: odrv0.axis1.controller.vel_setpoint
|
||||
In [3]: odrv0.axis1.controller.input_vel
|
||||
Out[3]: 28.152389526367188
|
||||
|
||||
In [4]: odrv0.axis1.controller.vel_setpoint
|
||||
In [4]: odrv0.axis1.controller.input_vel
|
||||
Out[4]: 61.21905517578125
|
||||
|
||||
In [5]: odrv0.axis1.controller.vel_setpoint
|
||||
In [5]: odrv0.axis1.controller.input_vel
|
||||
Out[5]: -52.990474700927734
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
# Input Modes
|
||||
As of version ###, ODrive now intercepts the incoming commands and can apply filters to them. The old protocol values `pos_setpoint`, `vel_setpoint`, and `current_setpoint` are still used internally by the closed-loop cascade control, but the user cannot write to them directly. This allows us to condense the number of ways the ODrive accepts motion commands. The new commands are:
|
||||
|
||||
* `<axis>.controller.config.input_mode`
|
||||
* `<axis>.controller.input_pos`
|
||||
* `<axis>.controller.input_vel`
|
||||
* `<axis>.controller.input_current`
|
||||
|
||||
The Input Modes currently valid are:
|
||||
* `INPUT_MODE_INACTIVE`
|
||||
* `INPUT_MODE_PASSTHROUGH`
|
||||
* `INPUT_MODE_VEL_RAMP`
|
||||
* `INPUT_MODE_POS_FILTER`
|
||||
* `INPUT_MODE_MIX_CHANNELS`
|
||||
* `INPUT_MODE_TRAP_TRAJ`
|
||||
* `INPUT_MODE_CURRENT_RAMP`
|
||||
* `INPUT_MODE_MIRROR`
|
||||
|
||||
---
|
||||
|
||||
## INPUT_MODE_INACTIVE
|
||||
Disable inputs. Setpoints retain their last value.
|
||||
|
||||
## INPUT_MODE_PASSTHROUGH
|
||||
Pass `input_xxx` through to `xxx_setpoint` directly.
|
||||
|
||||
### Valid Inputs:
|
||||
* `input_pos`
|
||||
* `input_vel`
|
||||
* `input_current`
|
||||
|
||||
### Valid Control modes:
|
||||
* `CTRL_MODE_VOLTAGE_CONTROL`
|
||||
* `CTRL_MODE_CURRENT_CONTROL`
|
||||
* `CTRL_MODE_VELOCITY_CONTROL`
|
||||
* `CTRL_MODE_POSITION_CONTROL`
|
||||
|
||||
## INPUT_MODE_VEL_RAMP
|
||||
Ramps a velocity command from the current value to the target value.
|
||||
|
||||
### Configuration Values:
|
||||
* `<axis>.controller.config.vel_ramp_rate` [cpr/sec]
|
||||
* `<axis>.controller.config.inertia` [A/(count/s^2))]
|
||||
|
||||
### Valid inputs:
|
||||
* `input_vel`
|
||||
|
||||
### Valid Control Modes:
|
||||
* `CTRL_MODE_VELOCITY_CONTROL`
|
||||
|
||||
## INPUT_MODE_POS_FILTER
|
||||
Implements a 2nd order position tracking filter. Inteded for use with step/dir interface, but can also be used with position-only commands.
|
||||
|
||||

|
||||
Result of a step command from 1000 to 0
|
||||
|
||||
### Configuration Values:
|
||||
* `<axis>.controller.config.input_filter_bandwidth`
|
||||
* `<axis>.controller.config.inertia`
|
||||
|
||||
### Valid inputs:
|
||||
* `input_pos`
|
||||
|
||||
### Valid Control modes:
|
||||
* `CTRL_MODE_POSITION_CONTROL`
|
||||
|
||||
## INPUT_MODE_MIX_CHANNELS
|
||||
Not Implemented.
|
||||
|
||||
|
||||
## INPUT_MODE_TRAP_TRAJ
|
||||
Implementes an online trapezoidal trajectory planner.
|
||||
|
||||

|
||||
|
||||
### Configuration Values:
|
||||
* `<axis>.trap_traj.config.vel_limit`
|
||||
* `<axis>.trap_traj.config.accel_limit`
|
||||
* `<axis>.trap_traj.config.decel_limit`
|
||||
* `<axis>.controller.config.inertia`
|
||||
|
||||
### Valid Inputs:
|
||||
* `input_pos`
|
||||
|
||||
### Valid Control Modes:
|
||||
* `CTRL_MODE_POSITION_CONTROL`
|
||||
|
||||
## INPUT_MODE_CURRENT_RAMP
|
||||
Ramp a current command from the current value to the target value.
|
||||
|
||||
### Configuration Values:
|
||||
* `<axis>.controller.config.current_ramp_rate`
|
||||
|
||||
### Valid Inputs:
|
||||
* `input_current`
|
||||
|
||||
### Valid Control Modes:
|
||||
* `CTRL_MODE_CURRENT_CONTROL`
|
||||
|
||||
## INPUT_MODE_MIRROR
|
||||
Implements "electronic mirroring". This is like electronic camming, but you can only mirror exactly the movements of the other motor, according to a fixed ratio
|
||||
|
||||
[](http://www.youtube.com/watch?v=D4_vBtyVVzM "Example Mirroring Video")
|
||||
|
||||
### Configuration Values
|
||||
* `<axis>.controller.config.axis_to_mirror`
|
||||
* `<axis>.controller.config.mirror_ratio`
|
||||
|
||||
### Valid Inputs
|
||||
* None. Inputs are taken directly from the other axis encoder estimates
|
||||
|
||||
### Valid Control modes
|
||||
* `CTRL_MODE_POSITION_CONTROL`
|
||||
+2
-2
@@ -115,13 +115,13 @@ Some GPIO pins can be used for PWM input, if they are not allocated to other fun
|
||||
Any of the numerical parameters that are writable from the ODrive Tool can be hooked up to a PWM input.
|
||||
As an example, we'll configure GPIO4 to control the angle of axis 0. We want the axis to move within a range of -1500 to 1500 encoder counts.
|
||||
|
||||
1. Make sure you're able control the axis 0 angle by writing to `odrv0.axis0.controller.pos_setpoint`. If you need help with this follow the [getting started guide](getting-started.md).
|
||||
1. Make sure you're able control the axis 0 angle by writing to `odrv0.axis0.controller.input_pos`. If you need help with this follow the [getting started guide](getting-started.md).
|
||||
2. If you want to control your ODrive with the PWM input without using anything else to activate the ODrive, you can configure the ODrive such that axis 0 automatically goes operational at startup. See [here](commands.md#startup-procedure) for more information.
|
||||
3. In ODrive Tool, configure the PWM input mapping
|
||||
```
|
||||
In [1]: odrv0.config.gpio4_pwm_mapping.min = -1500
|
||||
In [2]: odrv0.config.gpio4_pwm_mapping.max = 1500
|
||||
In [3]: odrv0.config.gpio4_pwm_mapping.endpoint = odrv0.axis0.controller._remote_attributes['pos_setpoint']
|
||||
In [3]: odrv0.config.gpio4_pwm_mapping.endpoint = odrv0.axis0.controller._remote_attributes['input_pos']
|
||||
```
|
||||
Note: you can disable the input by setting `odrv0.config.gpio4_pwm_mapping.endpoint = None`
|
||||
4. Save the configuration and reboot
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
test
|
||||
Reference in New Issue
Block a user