Merge branch 'RazorsFrozenTesting' into RazorsEdge

This commit is contained in:
Paul Guenette
2020-04-23 16:36:01 -04:00
31 changed files with 1533 additions and 4371 deletions
+1 -1
View File
@@ -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
View File
@@ -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
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://github.com/madcowswe/ODrive/blob/master/docs/controller_with_ff.png?raw=true)
![Cascaded pos vel I loops](controller_with_ff.png)
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
View File
@@ -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`
+5 -5
View File
@@ -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
View File
@@ -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
```
+113
View File
@@ -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.
![POS Filter Response](secondOrderResponse.png)
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.
![Trapezoidal Planner Response](TrapTrajPosVel.png)
### 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://img.youtube.com/vi/D4_vBtyVVzM/0.jpg)](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
View File
@@ -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
View File
@@ -1 +0,0 @@
test