Merge branch 'master' into fw-v0.5.3

This commit is contained in:
Samuel Sadok
2021-06-18 09:45:59 +02:00
10 changed files with 158 additions and 121 deletions
+9 -5
View File
@@ -36,13 +36,13 @@ jobs:
run: |
DEBIAN_VERSION="$(lsb_release --release --short)"
echo Debian version: $DEBIAN_VERSION
if [ "$DEBIAN_VERSION" -gt 9 ]; then
sudo apt-get install gcc-arm-none-eabi
else
if [ "$DEBIAN_VERSION" == "16.04" ]; then
# Ubuntu 16.04 (Debian 9) is on ARM GCC 4.9 which is too old for us
sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa
sudo apt-get update
sudo apt-get install gcc-arm-embedded
else
sudo apt-get install gcc-arm-none-eabi
fi
if ! (apt-cache search tup | grep "^tup - "); then
@@ -58,7 +58,9 @@ jobs:
if: startsWith(matrix.os, 'macOS-')
run: |
brew install armmbed/formulae/arm-none-eabi-gcc
brew install --cask osxfuse && brew install tup
# See https://github.com/osxfuse/osxfuse/issues/801#issuecomment-833419942
brew install --cask macfuse
brew install gromgit/fuse/tup-mac
pip3 install PyYAML Jinja2 jsonschema
@@ -91,7 +93,9 @@ jobs:
cd ${{ github.workspace }}/Firmware
echo "CONFIG_BOARD_VERSION=${{ matrix.board_version }}" >> tup.config
echo "CONFIG_STRICT=true" >> tup.config
echo "CONFIG_DEBUG=${{ matrix.release }}" >> tup.config
echo "CONFIG_DEBUG=${{ matrix.debug }}" >> tup.config
mkdir -p autogen
python ../tools/odrive/version.py --output autogen/version.c
tup init
tup generate ./tup_build.sh
+1 -1
View File
@@ -700,7 +700,7 @@ interfaces:
UNKNOWN_TORQUE: {doc: The motor controller did not get a valid torque input.}
UNKNOWN_CURRENT_COMMAND: {doc: The current controller did not get a valid current setpoint. Maybe you didn't configure the controller correctly.}
UNKNOWN_CURRENT_MEASUREMENT: {doc: The current controller did not get a valid current measurement.}
UNKNOWN_VBUS_VOLTAGE: {doc: The current controller did not get a valid `ODrive:vbus_voltage` measurement.}
UNKNOWN_VBUS_VOLTAGE: {doc: 'The current controller did not get a valid `ODrive:vbus_voltage` measurement.'}
UNKNOWN_VOLTAGE_COMMAND: {doc: The current controller did not get a valid feedforward voltage setpoint.}
UNKNOWN_GAINS: {doc: The current controller gains were not configured. Run motor calibration or set `config.phase_resistance` and `config.phase_inductance` manually.}
CONTROLLER_INITIALIZING: {doc: Internal value used while the controller is not yet ready to generate PWM timings.}
+3 -1
View File
@@ -9,11 +9,13 @@ sections:
url: /
- title: ODrive Tool
url: /odrivetool
- title: Control Modes
url: /control-modes
- title: Parameters & Commands
url: /commands
- title: Encoders
url: /encoders
- title: Control & Tuning
- title: Control Structure & Tuning
url: /control
- title: Troubleshooting
url: /troubleshooting
+32 -18
View File
@@ -9,6 +9,24 @@ ODrive currently supports the following CAN baud rates:
* 500 kbps
* 1000 kbps
---
## Configuring ODrive for CAN
Configuration of the CAN parameters should be done via USB before putting the device on the bus.
To set the desired baud rate, use `<odrv>.can.config.baud_rate = <value>`.
Each axis looks like a separate node on the bus. Thus, they both have the two properties `can_node_id` and `can_node_id_extended`. The node ID can be from 0 to 63 (0x3F) inclusive, or, if extended CAN IDs are used, from 0 to 16777215 (0xFFFFFF). If you want to connect more than one ODrive on a CAN bus, you must set different node IDs for the second ODrive or they will conflict and crash the bus.
### Example Configuration
```
odrv0.axis0.config.can_node_id = 3
odrv0.axis1.config.can_node_id = 1
odrv0.can.config.baud_rate = 500000
odrv0.save_configuration()
odrv0.reboot()
```
---
## Transport Protocol
We've implemented a very basic CAN protocol that we call "CAN Simple" to get users going with ODrive. This protocol is sufficiently abstracted that it is straightforward to add other protocols such as CANOpen, J1939, or Fibre over ISO-TP in the future. Unfortunately, implementing those protocols is a lot of work, and we wanted to give users a way to control ODrive's basic functions via CAN sooner rather than later.
@@ -21,15 +39,13 @@ At its most basic, the CAN Simple frame looks like this:
To understand how the Node ID and Command ID interact, let's look at an example
`odrv0.axis0.can_node_id = 0x010` - Reserves messages 0x200 through 0x21F
`odrv0.axis1.can_node_id = 0x018` - Reserves messages 0x300 through 0x31F
The 11-bit Arbitration ID is setup as follows:
It may not be obvious, but this allows for some compatibility with CANOpen. Although the address space 0x200 and 0x300 correspond to receive PDO base addresses, we can guarantee they will not conflict if all CANopen node IDs are >= 32. E.g.:
`can_id = axis_id << 5 | cmd_id`
CANopen nodeID = 35 = 0x23
Receive PDO 0x200 + nodeID = 0x223, which does not conflict with the range [0x200 : 0x21F]
For example, an Axis ID of `0x01` with a command of `0x0C` would be result in `0x2C`:
Be careful that you don't assign too many nodeIDs per PDO group. Four CAN Simple nodes (32*4) is all of the available address space of a single PDO. If the bus is strictly ODrive CAN Simple nodes, a simple sequential Node ID assignment will work fine.
`0x01 << 5 | 0x0C = 0x2C`
### Messages
@@ -69,19 +85,17 @@ CMD ID | Name | Sender | Signals | Start byte | Signal Type | Bits | Factor | Of
\*\*\* Note: These messages can be sent to either address on a given ODrive board.
---
## Configuring ODrive for CAN
Configuration of the CAN parameters should be done via USB before putting the device on the bus.
To set the desired baud rate, use `<odrv>.can.config.baud_rate = <value>`.
### Interoperability with CANopen
You can deconflict with CANopen like this:
Each axis looks like a separate node on the bus. Thus, they both have the two properties `can_node_id` and `can_node_id_extended`. The node ID can be from 0 to 63 (0x3F) inclusive, or, if extended CAN IDs are used, from 0 to 16777215 (0xFFFFFF). If you want to connect more than one ODrive on a CAN bus, you must set different node IDs for the second ODrive or they will conflict and crash the bus.
`odrv0.axis0.can_node_id = 0x010` - Reserves messages 0x200 through 0x21F
`odrv0.axis1.can_node_id = 0x018` - Reserves messages 0x300 through 0x31F
### Example Configuration
It may not be obvious, but this allows for some compatibility with CANOpen. Although the address space 0x200 and 0x300 correspond to receive PDO base addresses, we can guarantee they will not conflict if all CANopen node IDs are >= 32. E.g.:
CANopen nodeID = 35 = 0x23
Receive PDO 0x200 + nodeID = 0x223, which does not conflict with the range [0x200 : 0x21F]
Be careful that you don't assign too many nodeIDs per PDO group. Four CAN Simple nodes (32*4) is all of the available address space of a single PDO. If the bus is strictly ODrive CAN Simple nodes, a simple sequential Node ID assignment will work fine.
```
odrv0.axis0.config.can_node_id = 3
odrv0.axis1.config.can_node_id = 1
odrv0.can.config.baud_rate = 500000
odrv0.save_configuration()
odrv0.reboot()
```
+100
View File
@@ -0,0 +1,100 @@
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 continuous 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.
- [Filtered position control](#filtered-position-control)
- [Trajectory control](#trajectory-control)
- [Circular position control](#circular-position-control)
- [Velocity control](#velocity-control)
- [Ramped velocity control](#ramped-velocity-control)
- [Torque control](#torque-control)
### Filtered position control
Asking the ODrive controller to go as hard as it can to raw setpoints may result in jerky movement. Even if you are using a planned trajectory generated from an external source, if that is sent at a modest frequency, the ODrive may chase each stair in the incoming staircase in a jerky way. In this case, a good starting point for tuning the filter bandwidth is to set it to one half of your setpoint command rate.
You can use the second order position filter in these cases.
Set the filter bandwidth: `axis.controller.config.input_filter_bandwidth = 2.0` [1/s]<br>
Activate the setpoint filter: `axis.controller.config.input_mode = INPUT_MODE_POS_FILTER`.<br>
You can now control the velocity with `axis.controller.input_pos = 1` [turns].
![secondOrderResponse](secondOrderResponse.PNG)<br>
Step response of a 1000 to 0 position input with a filter bandwidth of 1.0 [/sec].
### Trajectory control
See the **Usage** section for usage details.<br>
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>.controller.config.inertia = <Float>
```
`vel_limit` is the maximum planned trajectory speed. This sets your coasting speed.<br>
`accel_limit` is the maximum acceleration in turns / sec^2<br>
`decel_limit` is the maximum deceleration in turns / sec^2<br>
`controller.config.inertia` is a value which correlates acceleration (in turns / sec^2) and motor torque. 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. It is recommended 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
Make sure you are in position control mode. To activate the trajectory module, set the input mode to trajectory:
```
axis.controller.config.input_mode = INPUT_MODE_TRAP_TRAJ
```
Simply send a position command to execute the move:
```
<odrv>.<axis>.controller.input_pos = <Float>
```
Use the `move_incremental` function to move to a relative position.
To set the goal relative to the current actual position, use `from_goal_point = False`
To set the goal relative to the previous destination, use `from_goal_point = True`
```
<odrv>.<axis>.controller.move_incremental(pos_increment, from_goal_point)
```
You can also execute a move with the [appropriate ascii command](ascii-protocol.md#motor-trajectory-command).
### Circular position control
To enable Circular position control, set `axis.controller.config.circular_setpoints = True`
This mode is useful for continuous 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 `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, `input_pos` is expected in the range `[0, 1)`. 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_circular` is used for feedback instead of `encoder.pos_estimate`.
If you try to increment the axis with a large step in one go that exceeds `1` turn, 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 larger circular range. Set `controller.config.circular_setpoints_range = N`. Choose N to give you an appropriate circular space for your application.
### Velocity control
Set `axis.controller.config.control_mode = CONTROL_MODE_VELOCITY_CONTROL`.<br>
You can now control the velocity with `axis.controller.input_vel = 1` [turn/s].
### Ramped velocity control
Set `axis.controller.config.control_mode = CONTROL_MODE_VELOCITY_CONTROL`.<br>
Set the velocity ramp rate (acceleration): `axis.controller.config.vel_ramp_rate = 0.5` [turn/s^2]<br>
Activate the ramped velocity mode: `axis.controller.config.input_mode = INPUT_MODE_VEL_RAMP`.<br>
You can now control the velocity with `axis.controller.input_vel = 1` [turn/s].
### Torque control
Set `axis.controller.config.control_mode = CONTROL_MODE_TORQUE_CONTROL`.<br>
You can now control the torque with `axis.controller.input_torque = 0.1` [Nm].
Note: If you exceed `vel_limit` in torque control mode, the current is reduced. To disable this, set `axis.controller.enable_current_mode_vel_limit = False`.
+2
View File
@@ -6,6 +6,8 @@ The motor controller is a cascaded style position, velocity and current control
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.
* Note: The controller has been updated to use `torque` in Newton-meters instead of current at the "system" level. There is a `torque_constant` parameter which converts between torque and current, after which the rest of this explanation still holds.
### Position loop:
The position controller is a P loop with a single proportional gain.
```text
+1 -1
View File
@@ -113,7 +113,7 @@ To customize the compile time parameters, copy or rename the file `Firmware/tup.
__CONFIG_BOARD_VERSION__: The board version you're using. Can be `v3.1`, `v3.2`, `v3.3`, `v3.4-24V`, `v3.4-48V`, `v3.5-24V`, `v3.5-48V`, etc. Check for a label on the upper side of the ODrive to find out which version you have. Some ODrive versions don't specify the voltage: in that case you can read the value of the main capacitors: 120uF are 48V ODrives, 470uF are 24V ODrives.
__CONFIG_DEBUG__: Defines wether debugging will be enabled when compiling the firmware; specifically the `-g -gdwarf-2` flags. Note that printf debugging will only function if your tup.config specifies the `USB_PROTOCOL` or `UART_PROTOCOL` as stdout and `DEBUG_PRINT` is defined. See the IDE specific documentation for more information.
__CONFIG_DEBUG__: Defines whether debugging will be enabled when compiling the firmware; specifically the `-g -gdwarf-2` flags. Note that printf debugging will only function if your tup.config specifies the `USB_PROTOCOL` or `UART_PROTOCOL` as stdout and `DEBUG_PRINT` is defined. See the IDE specific documentation for more information.
You can also modify the compile-time defaults for all `.config` parameters. You will find them if you search for `AxisConfig`, `MotorConfig`, etc.
+1 -1
View File
@@ -20,7 +20,7 @@ In the `odrivetool`, type `<axis>.requested_state = AXIS_STATE_ENCODER_OFFSET_CA
To verify everything went well, check the following variables:
* `<axis>.error` should be 0.
* `<axis>.encoder.config.offset` - This should print a number, like -326 or 1364.
* `<axis>.encoder.config.phase_offset` - This should print a number, like -326 or 1364.
* `<axis>.encoder.config.direction` - This should print 1 or -1.
### Encoder with index signal
+8 -93
View File
@@ -14,11 +14,13 @@ permalink: /
- [Downloading and Installing Tools](#downloading-and-installing-tools)
- [Firmware](#firmware)
- [Start `odrivetool`](#start-odrivetool)
- [Debugging](#debugging)
- [Configure M0](#configure-m0)
- [Position control of M0](#position-control-of-m0)
- [Other control modes](#other-control-modes)
- [Watchdog Timer](#watchdog-timer)
- [What's next?](#whats-next)
- [Upgrading from 0.4.12](#upgrading-from-0412)
<!-- /TOC -->
@@ -282,101 +284,14 @@ The default control mode is unfiltered position control in the absolute encoder
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.
- [Filtered position control](#filtered-position-control)
- [Trajectory control](#trajectory-control)
- [Circular position control](#circular-position-control)
- [Velocity control](#velocity-control)
- [Ramped velocity control](#ramped-velocity-control)
- [Torque control](#torque-control)
- [Filtered position control](control-modes.md#filtered-position-control)
- [Trajectory control](control-modes.md#trajectory-control)
- [Circular position control](control-modes.md#circular-position-control)
- [Velocity control](control-modes.md#velocity-control)
- [Ramped velocity control](control-modes.md#ramped-velocity-control)
- [Torque control](control-modes.md#torque-control)
### Filtered position control
Asking the ODrive controller to go as hard as it can to raw setpoints may result in jerky movement. Even if you are using a planned trajectory generated from an external source, if that is sent at a modest frequency, the ODrive may chase each stair in the incoming staircase in a jerky way. In this case, a good starting point for tuning the filter bandwidth is to set it to one half of your setpoint command rate.
You can use the second order position filter in these cases.
Set the filter bandwidth: `axis.controller.config.input_filter_bandwidth = 2.0` [1/s]<br>
Activate the setpoint filter: `axis.controller.config.input_mode = INPUT_MODE_POS_FILTER`.<br>
You can now control the velocity with `axis.controller.input_pos = 1` [turns].
![secondOrderResponse](secondOrderResponse.PNG)<br>
Step response of a 1000 to 0 position input with a filter bandwidth of 1.0 [/sec].
### Trajectory control
See the **Usage** section for usage details.<br>
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>.controller.config.inertia = <Float>
```
`vel_limit` is the maximum planned trajectory speed. This sets your coasting speed.<br>
`accel_limit` is the maximum acceleration in turns / sec^2<br>
`decel_limit` is the maximum deceleration in turns / sec^2<br>
`controller.config.inertia` is a value which correlates acceleration (in turns / sec^2) and motor torque. 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. It is recommended 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
Make sure you are in position control mode. To activate the trajectory module, set the input mode to trajectory:
```
axis.controller.config.input_mode = INPUT_MODE_TRAP_TRAJ
```
Simply send a position command to execute the move:
```
<odrv>.<axis>.controller.input_pos = <Float>
```
Use the `move_incremental` function to move to a relative position.
To set the goal relative to the current actual position, use `from_goal_point = False`
To set the goal relative to the previous destination, use `from_goal_point = True`
```
<odrv>.<axis>.controller.move_incremental(pos_increment, from_goal_point)
```
You can also execute a move with the [appropriate ascii command](ascii-protocol.md#motor-trajectory-command).
### Circular position control
To enable Circular position control, set `axis.controller.config.circular_setpoints = True`
This mode is useful for continuous 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 `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, `input_pos` is expected in the range `[0, 1)`. 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_circular` is used for feedback instead of `encoder.pos_estimate`.
If you try to increment the axis with a large step in one go that exceeds `1` turn, 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 larger circular range. Set `controller.config.circular_setpoints_range = N`. Choose N to give you an appropriate circular space for your application.
### Velocity control
Set `axis.controller.config.control_mode = CONTROL_MODE_VELOCITY_CONTROL`.<br>
You can now control the velocity with `axis.controller.input_vel = 1` [turn/s].
### Ramped velocity control
Set `axis.controller.config.control_mode = CONTROL_MODE_VELOCITY_CONTROL`.<br>
Set the velocity ramp rate (acceleration): `axis.controller.config.vel_ramp_rate = 0.5` [turn/s^2]<br>
Activate the ramped velocity mode: `axis.controller.config.input_mode = INPUT_MODE_VEL_RAMP`.<br>
You can now control the velocity with `axis.controller.input_vel = 1` [turn/s].
### Torque control
Set `axis.controller.config.control_mode = CONTROL_MODE_TORQUE_CONTROL`.<br>
You can now control the torque with `axis.controller.input_torque = 0.1` [Nm].
Note: If you exceed `vel_limit` in torque control mode, the current is reduced. To disable this, set `axis.controller.enable_current_mode_vel_limit = False`.
## Watchdog Timer
Each axis has a configurable watchdog timer that can stop the motors if the
control connection to the ODrive is interrupted.
+1 -1
View File
@@ -19,7 +19,7 @@ You may wire the motor phases in any order into a motor connector on the ODrive,
| Green | Z |
| Black | GND |
Note: In order to be compatible with encoder inputs, the ODrive doesn't have any filtering capacitors on the pins where the hall sensors connect. Therefore to get a reliable hall signal, it is recommended that you add some filter capacitors to these pins. You can see instructions [here](https://discourse.odriverobotics.com/t/encoder-error-error-illegal-hall-state/1047/7?u=madcowswe).
Note: In order to be compatible with encoder inputs, the ODrive doesn't have any filtering capacitors on the pins where the hall sensors connect. Therefore to get a reliable hall signal, it is recommended that you add some filter capacitors to these pins. We recommend about 22nF between each signal pin and GND. You can see instructions [here](https://discourse.odriverobotics.com/t/encoder-error-error-illegal-hall-state/1047/7?u=madcowswe).
### Hoverboard motor configuration