mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-09-25 02:47:27 +08:00
Merge pull request #424 from madcowswe/feature/doc_autogen
HTML API reference autogeneration
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
name: Build and publish HTML documentation website
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ feature/doc_autogen ]
|
||||
|
||||
jobs:
|
||||
jekyll:
|
||||
runs-on: ubuntu-16.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
# Use GitHub Actions' cache for ruby and python packages to shorten build times and decrease load on servers
|
||||
- name: Cache gems
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: docs/vendor/bundle
|
||||
key: ${{ runner.os }}-gems-${{ hashFiles('docs/Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gems-
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-PyYAML-Jinja2-jsonschema
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: pip install PyYAML Jinja2 jsonschema
|
||||
|
||||
# Autogenerate the API reference .md files in the python in the python/python3 container
|
||||
- name: Autogenerate the API reference .md files in the python container
|
||||
run: |
|
||||
mkdir -p docs/_api docs/_includes
|
||||
python Firmware/interface_generator_stub.py --definitions Firmware/odrive-interface.yaml --template docs/_layouts/api_documentation_template.j2 --outputs docs/_api/#.md
|
||||
python Firmware/interface_generator_stub.py --definitions Firmware/odrive-interface.yaml --template docs/_layouts/api_index_template.j2 --output docs/_includes/apiindex.html
|
||||
|
||||
- name: Build the site in the jekyll/builder container
|
||||
run: |
|
||||
docker run \
|
||||
-v ${{ github.workspace }}:/srv/jekyll -e PAGES_REPO_NWO=${GITHUB_REPOSITORY} \
|
||||
ruby:2.7-buster /bin/sh -c "
|
||||
chmod 777 /srv/jekyll/docs && \
|
||||
cd /srv/jekyll/docs && \
|
||||
bundle config path vendor/bundle && \
|
||||
bundle install && \
|
||||
JEKYLL_ENV=production bundle exec jekyll build
|
||||
"
|
||||
touch .nojekyll
|
||||
|
||||
- name: Push to documentation branch
|
||||
run: |
|
||||
git config user.name "${GITHUB_ACTOR}"
|
||||
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
|
||||
git add -f docs/_site
|
||||
git commit -m "jekyll build from Action ${GITHUB_SHA}"
|
||||
git push --force origin HEAD:${REMOTE_BRANCH}
|
||||
env:
|
||||
REMOTE_BRANCH: gh-pages
|
||||
+12
-7
@@ -24,9 +24,6 @@ coverage.xml
|
||||
# Django stuff:
|
||||
*.log
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
@@ -37,10 +34,18 @@ target/
|
||||
.tup
|
||||
tup.config
|
||||
|
||||
docs/ruby-bundle
|
||||
docs/_site
|
||||
docs/.bundle
|
||||
docs/Gemfile.lock
|
||||
# Sphinx documentation
|
||||
/docs/_build/
|
||||
|
||||
# Autogenerated API reference
|
||||
/docs/_api
|
||||
/docs/_includes/apiindex.html
|
||||
|
||||
# Jekyll HTML documention and artifacts
|
||||
/docs/ruby-bundle
|
||||
/docs/_site
|
||||
/docs/.bundle/config
|
||||
/docs/.jekyll-metadata
|
||||
|
||||
|
||||
*.exe
|
||||
|
||||
@@ -623,13 +623,17 @@ def tokenize(text, interface, interface_transform, value_type_transform, attribu
|
||||
token_list = split_name(token)
|
||||
|
||||
# Check if this is an attribute reference
|
||||
attr_intf = interface
|
||||
for name in token_list:
|
||||
if not name in attr_intf['attributes']:
|
||||
attr = None
|
||||
break
|
||||
attr = attr_intf['attributes'][name]
|
||||
attr_intf = attr['type']
|
||||
scope = interface
|
||||
attr = None
|
||||
while attr is None and not scope is None:
|
||||
attr_intf = scope
|
||||
for name in token_list:
|
||||
if not name in attr_intf['attributes']:
|
||||
attr = None
|
||||
break
|
||||
attr = attr_intf['attributes'][name]
|
||||
attr_intf = attr['type']
|
||||
scope = scope.get('parent', None)
|
||||
|
||||
if not attr is None:
|
||||
return attribute_transform(token, attr)
|
||||
@@ -648,6 +652,7 @@ env.filters['first'] = lambda x: next(iter(x))
|
||||
env.filters['skip_first'] = lambda x: list(x)[1:]
|
||||
env.filters['to_c_string'] = lambda x: '\n'.join(('"' + line.replace('"', '\\"') + '"') for line in json.dumps(x, separators=(',', ':')).replace('{"name"', '\n{"name"').split('\n'))
|
||||
env.filters['tokenize'] = tokenize
|
||||
env.filters['diagonalize'] = lambda lst: [lst[:i + 1] for i in range(len(lst))]
|
||||
|
||||
template = env.from_string(template_file.read())
|
||||
|
||||
|
||||
+311
-39
@@ -8,9 +8,26 @@ dictionary: [ODrive] # Prevent the word 'ODrive' from being detected as two word
|
||||
interfaces:
|
||||
ODrive:
|
||||
c_is_class: True
|
||||
brief: Toplevel interface of your ODrive.
|
||||
doc: |
|
||||
The odrv0, odrv1, ... objects that appear in odrivetool implement this
|
||||
toplevel interface.
|
||||
attributes:
|
||||
vbus_voltage: readonly float32
|
||||
ibus: readonly float32
|
||||
vbus_voltage:
|
||||
type: readonly float32
|
||||
unit: V
|
||||
brief: Voltage on the DC bus as measured by the ODrive.
|
||||
ibus:
|
||||
type: readonly float32
|
||||
unit: A
|
||||
brief: Current on the DC bus as calculated by the ODrive.
|
||||
doc: |
|
||||
A positive value means that the ODrive is consuming power from the power supply,
|
||||
a negative value means that the ODrive is sourcing power to the power supply.
|
||||
|
||||
This value is equal to the sum of the motor currents and the brake resistor currents.
|
||||
The motor currents are measured, the brake resistor current is calculated based on
|
||||
`config.brake_resistance`.
|
||||
serial_number: readonly uint64
|
||||
hw_version_major: readonly uint8
|
||||
hw_version_minor: readonly uint8
|
||||
@@ -65,7 +82,8 @@ interfaces:
|
||||
doc: 'TODO: changing this currently requires a reboot - fix this'
|
||||
uart_baudrate:
|
||||
type: uint32
|
||||
doc: "Defines the baudrate used on the UART interface.
|
||||
doc: |
|
||||
Defines the baudrate used on the UART interface.
|
||||
Some baudrates will have a small timing error due to hardware limitations.
|
||||
|
||||
Here's an (incomplete) list of baudrates for ODrive v3.x:
|
||||
@@ -85,62 +103,71 @@ interfaces:
|
||||
1.792 MBps | 1.826 MBps | 1.9
|
||||
1.8432 MBps | 1.826 MBps | 0.93
|
||||
|
||||
For more information refer to Section 30.3.4 and Table 142 (the column with f_PCLK = 42 MHz) in the STM datasheet:
|
||||
https://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf"
|
||||
For more information refer to Section 30.3.4 and Table 142 (the column with f_PCLK = 42 MHz) in the
|
||||
[STM datasheet](https://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf).
|
||||
enable_i2c_instead_of_can:
|
||||
type: bool
|
||||
doc: 'Changing this requires a reboot'
|
||||
doc: Changing this requires a reboot.
|
||||
enable_ascii_protocol_on_usb: bool
|
||||
max_regen_current: float32
|
||||
brake_resistance:
|
||||
type: float32
|
||||
unit: Ohm
|
||||
doc: Value of the brake resistor connected to the ODrive. Set to 0 to disable.
|
||||
brief: Value of the brake resistor connected to the ODrive.
|
||||
doc: Set to 0 to disable.
|
||||
|
||||
dc_bus_undervoltage_trip_level:
|
||||
type: float32
|
||||
unit: V
|
||||
doc: Minimum voltage below which the motor stops operating.
|
||||
brief: Minimum voltage below which the motor stops operating.
|
||||
dc_bus_overvoltage_trip_level:
|
||||
type: float32
|
||||
unit: V
|
||||
doc: Maximum voltage above which the motor stops operating.
|
||||
brief: Maximum voltage above which the motor stops operating.
|
||||
doc: |
|
||||
This protects against cases in which the power supply fails to dissipate
|
||||
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.
|
||||
|
||||
enable_dc_bus_overvoltage_ramp:
|
||||
type: bool
|
||||
doc: 'If enabled, if the measured DC voltage exceeds `dc_bus_overvoltage_ramp_start`,
|
||||
status: experimental
|
||||
brief: Enables the DC bus overvoltage ramp feature.
|
||||
doc: |
|
||||
If enabled, if the measured DC voltage exceeds `dc_bus_overvoltage_ramp_start`,
|
||||
the ODrive will sink more power than usual into the the brake resistor
|
||||
in an attempt to bring the voltage down again.
|
||||
|
||||
The brake duty cycle is increased by the following amount:
|
||||
vbus_voltage == dc_bus_overvoltage_ramp_start => brake_duty_cycle += 0%
|
||||
vbus_voltage == dc_bus_overvoltage_ramp_end => brake_duty_cycle += 100%
|
||||
|
||||
* `vbus_voltage` == `dc_bus_overvoltage_ramp_start` => brake_duty_cycle += 0%
|
||||
* `vbus_voltage` == `dc_bus_overvoltage_ramp_end` => brake_duty_cycle += 100%
|
||||
|
||||
Remarks:
|
||||
- This feature is active even when all motors are disarmed.
|
||||
- This feature is disabled if `brake_resistance` is non-positive.'
|
||||
- This feature is disabled if `brake_resistance` is non-positive.
|
||||
dc_bus_overvoltage_ramp_start:
|
||||
type: float32
|
||||
doc: See `enable_dc_bus_overvoltage_ramp`.
|
||||
Do not set this lower than your usual vbus_voltage,
|
||||
status: experimental
|
||||
brief: See `enable_dc_bus_overvoltage_ramp`.
|
||||
doc: Do not set this lower than your usual `vbus_voltage`,
|
||||
unless you like fried brake resistors.
|
||||
dc_bus_overvoltage_ramp_end:
|
||||
type: float32
|
||||
doc: See `enable_dc_bus_overvoltage_ramp`.
|
||||
Must be larger than `dc_bus_overvoltage_ramp_start`,
|
||||
status: experimental
|
||||
brief: See `enable_dc_bus_overvoltage_ramp`.
|
||||
doc: Must be larger than `dc_bus_overvoltage_ramp_start`,
|
||||
otherwise the ramp feature is disabled.
|
||||
|
||||
dc_max_positive_current:
|
||||
type: float32
|
||||
unit: A
|
||||
doc: Max current the power supply can source.
|
||||
brief: Max current the power supply can source.
|
||||
dc_max_negative_current:
|
||||
type: float32
|
||||
unit: A
|
||||
doc: Max current the power supply can sink. You most likely want a non-positive value here. Set to -INFINITY to disable.
|
||||
brief: Max current the power supply can sink.
|
||||
doc: You most likely want a non-positive value here. Set to -INFINITY to disable.
|
||||
|
||||
gpio1_pwm_mapping: {type: Endpoint, c_name: 'pwm_mappings[0]'} # TODO: disable for ODrive v3.2 and older
|
||||
gpio2_pwm_mapping: {type: Endpoint, c_name: 'pwm_mappings[1]'} # TODO: disable for ODrive v3.2 and older
|
||||
@@ -192,9 +219,48 @@ interfaces:
|
||||
nullflag: 'None'
|
||||
flags:
|
||||
InvalidState:
|
||||
doc: An invalid state was requested.
|
||||
brief: An invalid state was requested.
|
||||
doc: |
|
||||
You tried to run a state before you are allowed to. Typically you
|
||||
tried to run encoder calibration or closed loop control before the
|
||||
motor was calibrated, or you tried to run closed loop control
|
||||
before the encoder was calibrated.
|
||||
DcBusUnderVoltage:
|
||||
brief: The DC voltage fell below the limit configured in `config.dc_bus_undervoltage_trip_level`.
|
||||
doc: |
|
||||
Confirm that your power leads are connected securely. For initial
|
||||
testing a 12V PSU which can supply a couple of amps should be
|
||||
sufficient while the use of low current ‘wall wart’ plug packs may
|
||||
lead to inconsistent behaviour and is not recommended.
|
||||
|
||||
You can monitor your PSU voltage using liveplotter in odrivetool
|
||||
by entering `start_liveplotter(lambda: [odrv0.vbus_voltage])`. If
|
||||
you see your votlage drop below `config.dc_bus_undervoltage_trip_level`
|
||||
(default: ~ 8V) then you will trip this error. Even a relatively
|
||||
small motor can draw multiple kW momentary and so unless you have
|
||||
a very large PSU or are running of a battery you may encounter
|
||||
this error when executing high speed movements with a high current
|
||||
limit. To limit your PSU power draw you can limit your motor
|
||||
current and/or velocity limit `controller.config.vel_limit` and
|
||||
`motor.config.current_lim`.
|
||||
DcBusOverVoltage:
|
||||
brief: The DC voltage exceeded the limit configured in `config.dc_bus_overvoltage_trip_level`.
|
||||
doc: |
|
||||
Confirm that you have a brake resistor of the correct value
|
||||
connected securely and that `config.brake_resistance` is set to
|
||||
the value of your brake resistor.
|
||||
|
||||
You can monitor your PSU voltage using liveplotter in odrivetool
|
||||
by entering `start_liveplotter(lambda: [odrv0.vbus_voltage])`. If
|
||||
during a move you see the voltage rise above your PSU’s nominal
|
||||
set voltage then you have your brake resistance set too low. This
|
||||
may happen if you are using long wires or small gauge wires to
|
||||
connect your brake resistor to your odrive which will added extra
|
||||
resistance. This extra resistance needs to be accounted for to
|
||||
prevent this voltage spike. If you have checked all your
|
||||
connections you can also try increasing your brake resistance by
|
||||
~ 0.01 Ohm at a time to a maximum of 0.05 greater than your brake
|
||||
resistor value.
|
||||
CurrentMeasurementTimeout:
|
||||
BrakeResistorDisarmed:
|
||||
doc: The brake resistor was unexpectedly disarmed.
|
||||
@@ -207,7 +273,7 @@ interfaces:
|
||||
doc: Check `encoder.error` for more information.
|
||||
ControllerFailed:
|
||||
PosCtrlDuringSensorless:
|
||||
doc: DEPRECATED
|
||||
status: deprecated
|
||||
WatchdogTimerExpired:
|
||||
MinEndstopPressed:
|
||||
MaxEndstopPressed:
|
||||
@@ -251,7 +317,7 @@ interfaces:
|
||||
enable_step_dir:
|
||||
type: bool
|
||||
doc: Enable step/dir input after calibration.
|
||||
For M0 this has no effect if `enable_uart` is true.
|
||||
For M0 this has no effect if `config.enable_uart` is true.
|
||||
step_dir_always_on:
|
||||
type: bool
|
||||
doc: Keep step/dir enabled while the motor is disabled.
|
||||
@@ -327,13 +393,71 @@ interfaces:
|
||||
nullflag: None
|
||||
flags:
|
||||
PhaseResistanceOutOfRange:
|
||||
brief: The measured motor phase resistance is outside of the plausible range.
|
||||
doc: |
|
||||
During calibration the motor resistance and
|
||||
[inductance](https://en.wikipedia.org/wiki/Inductance) is measured.
|
||||
If the measured motor resistance or inductance falls outside a set
|
||||
range this error will be returned. Check that all motor leads are
|
||||
connected securely.
|
||||
|
||||
The measured values can be viewed using odrivetool as is shown below:
|
||||
```
|
||||
In [2]: odrv0.axis0.motor.config.phase_inductance
|
||||
Out[2]: 1.408751450071577e-05
|
||||
|
||||
In [3]: odrv0.axis0.motor.config.phase_resistance
|
||||
Out[3]: 0.029788672924041748
|
||||
```
|
||||
Some motors will have a considerably different phase resistance
|
||||
and inductance than this. For example, gimbal motors, some small
|
||||
motors (e.g. < 10A peak current). If you think this applies to you
|
||||
try increasing `config.resistance_calib_max_voltage` from
|
||||
its default value of 1 using odrivetool and repeat the motor
|
||||
calibration process. If your motor has a small peak current draw
|
||||
(e.g. < 20A) you can also try decreasing
|
||||
`config.calibration_current` from its default value of 10A.
|
||||
|
||||
In general, you need
|
||||
```text
|
||||
resistance_calib_max_voltage > calibration_current * phase_resistance
|
||||
resistance_calib_max_voltage < 0.5 * vbus_voltage
|
||||
```
|
||||
PhaseInductanceOutOfRange:
|
||||
brief: The measured motor phase inductance is outside of the plausible range.
|
||||
doc: |
|
||||
See `PhaseResistanceOutOfRange` for details.
|
||||
AdcFailed:
|
||||
DrvFault:
|
||||
brief: The gate driver chip reported an error.
|
||||
doc: |
|
||||
The ODrive v3.4 is known to have a hardware issue whereby the
|
||||
motors would stop operating when applying high currents to M0. The
|
||||
reported error of both motors in this case is `ERROR_DRV_FAULT`.
|
||||
|
||||
The conjecture is that the high switching current creates large
|
||||
ripples in the power supply of the DRV8301 gate driver chips, thus
|
||||
tripping its under-voltage fault detection.
|
||||
|
||||
To resolve this issue you can limit the M0 current to 40A. The
|
||||
lowest current at which the DRV fault was observed is 45A on one
|
||||
test motor and 50A on another test motor. Refer to
|
||||
[this post](https://discourse.odriverobotics.com/t/drv-fault-on-odrive-v3-4/558)
|
||||
for instructions for a hardware fix.
|
||||
ControlDeadlineMissed:
|
||||
NotImplementedMotorType:
|
||||
BrakeCurrentOutOfRange:
|
||||
ModulationMagnitude:
|
||||
doc: |
|
||||
The bus voltage was insufficent to push the requested current
|
||||
through the motor.
|
||||
If you are getting this during motor calibration, make sure that
|
||||
`config.resistance_calib_max_voltage` is no more than half
|
||||
your bus voltage.
|
||||
|
||||
For gimbal motors, it is recommended to set the
|
||||
`config.calibration_current` and `config.current_lim`
|
||||
to half your bus voltage, or less.
|
||||
BrakeDeadtimeViolation:
|
||||
UnexpectedTimerCallback:
|
||||
CurrentSenseSaturation:
|
||||
@@ -450,6 +574,18 @@ interfaces:
|
||||
nullflag: None
|
||||
flags:
|
||||
Overspeed:
|
||||
doc: |
|
||||
Try increasing `config.vel_limit`. The default of 20,000 encoder
|
||||
counts per second gives a motor speed of only ~146 RPM with the
|
||||
common CUI-AMT102 8192 count per rotation encoder. Note: Even if
|
||||
you do not commanded your motor to exceed `config.vel_limit`
|
||||
sudden changes in the load placed on a motor may cause this speed
|
||||
to be temporarily exceeded, resulting in this error.
|
||||
|
||||
You can also try increasing `config.vel_limit_tolerance`. The
|
||||
default value of 1.2 means it will only allow a 20% violation of
|
||||
the speed limit. You can set the `config.vel_limit_tolerance` to 0
|
||||
to disable the check altogether.
|
||||
InvalidInputMode:
|
||||
UnstableGain:
|
||||
InvalidMirrorAxis:
|
||||
@@ -523,7 +659,15 @@ interfaces:
|
||||
cogging_ratio: readonly float32
|
||||
anticogging_enabled: bool
|
||||
functions:
|
||||
move_incremental: {in: {displacement: float32, from_input_pos: bool}}
|
||||
move_incremental:
|
||||
doc: Moves the axes' goal point by a specified increment.
|
||||
in:
|
||||
displacement: {type: float32, doc: The desired position change.}
|
||||
from_input_pos: {type: bool, doc:
|
||||
'If true, the increment is applied relative to `input_pos`.
|
||||
If false, the increment is applied relative to `pos_setpoint`, which
|
||||
usually corresponds roughly to the current position of the axis.'
|
||||
}
|
||||
start_anticogging_calibration:
|
||||
|
||||
|
||||
@@ -535,10 +679,27 @@ interfaces:
|
||||
flags:
|
||||
UnstableGain:
|
||||
CprPolepairsMismatch:
|
||||
doc: |
|
||||
Confirm you have entered the correct count per rotation (CPR) for
|
||||
[your encoder](https://docs.odriverobotics.com/encoders). The
|
||||
ODrive uses your supplied value for the motor pole pairs to
|
||||
measure the CPR. So you should also double check this value.
|
||||
|
||||
Note that the AMT encoders are configurable using the micro-
|
||||
switches on the encoder PCB and so you may need to check that
|
||||
these are in the right positions. If your encoder lists its pulse
|
||||
per rotation (PPR) multiply that number by four to get CPR.
|
||||
NoResponse:
|
||||
doc: |
|
||||
Confirm that your encoder is plugged into the right pins on the
|
||||
ODrive board.
|
||||
UnsupportedEncoderMode:
|
||||
IllegalHallState:
|
||||
IndexNotFoundYet:
|
||||
doc: |
|
||||
Check that your encoder is a model that has an index pulse. If
|
||||
your encoder does not have a wire connected to pin Z on your
|
||||
ODrive then it does not output an index pulse.
|
||||
AbsSpiTimeout:
|
||||
AbsSpiComFail:
|
||||
AbsSpiNotReady:
|
||||
@@ -635,26 +796,54 @@ valuetypes:
|
||||
Undefined:
|
||||
doc: will fall through to idle
|
||||
Idle:
|
||||
doc: disable PWM and do nothing
|
||||
brief: Disable motor PWM and do nothing.
|
||||
StartupSequence:
|
||||
doc: the actual sequence is defined by the config.startup... flags
|
||||
brief: Run the startup procedure.
|
||||
doc: the actual sequence is defined by the `config`.startup... flags
|
||||
FullCalibrationSequence:
|
||||
doc: run all calibration procedures, then idle
|
||||
doc: Run motor calibration and then encoder offset calibration (or encoder
|
||||
index search if `<axis>.encoder.config.use_index` is `True`).
|
||||
MotorCalibration:
|
||||
doc: run motor calibration
|
||||
brief: Measure phase resistance and phase inductance of the motor.
|
||||
doc: |
|
||||
* To store the results set `motor.config.pre_calibrated` to `True`
|
||||
and save the configuration (`save_configuration()`). After that you
|
||||
don't have to run the motor calibration on the next start up.
|
||||
* This modifies the variables `motor.config.phase_resistance` and
|
||||
`motor.config.phase_inductance`.
|
||||
SensorlessControl:
|
||||
doc: run sensorless control
|
||||
brief: Run sensorless control.
|
||||
doc: |
|
||||
* The motor must be calibrated (`motor.is_calibrated`)
|
||||
* `controller.config.control_mode` must be `True`.
|
||||
EncoderIndexSearch:
|
||||
doc: run encoder index search
|
||||
brief: Turn the motor in one direction until the encoder index is traversed.
|
||||
doc: This state can only be entered if `encoder.config.use_index` is `True`.
|
||||
EncoderOffsetCalibration:
|
||||
doc: run encoder offset calibration
|
||||
brief: Turn the motor in one direction for a few seconds and then back to measure the offset between the encoder position and the electrical phase.
|
||||
doc: |
|
||||
* Can only be entered if the motor is calibrated (`motor.is_calibrated`).
|
||||
* A successful encoder calibration will make the `encoder.is_ready`
|
||||
go to true.
|
||||
ClosedLoopControl:
|
||||
doc: run closed loop control
|
||||
brief: Run closed loop control.
|
||||
doc: |
|
||||
* The action depends on the `controller.config.control_mode`.
|
||||
* Can only be entered if the motor is calibrated
|
||||
(`motor.is_calibrated`) and the encoder is ready (`encoder.is_ready`).
|
||||
LockinSpin:
|
||||
doc: run lockin spin
|
||||
brief: Run lockin spin.
|
||||
doc: |
|
||||
Can only be entered if the motor is calibrated (`motor.is_calibrated`)
|
||||
or the motor direction is unspecified (`motor.config.direction` == 1)
|
||||
EncoderDirFind:
|
||||
brief: Run encoder direction search.
|
||||
doc: |
|
||||
Can only be entered if the motor is calibrated (`motor.is_calibrated`).
|
||||
Homing:
|
||||
doc: run axis homing function
|
||||
brief: Run axis homing function.
|
||||
doc:
|
||||
Endstops must be enabled to use this feature.
|
||||
|
||||
ODrive.Encoder.Mode:
|
||||
values:
|
||||
@@ -676,6 +865,7 @@ valuetypes:
|
||||
# Note: these should be sorted from lowest level of control to
|
||||
# highest level of control, to allow "<" style comparisons.
|
||||
VoltageControl:
|
||||
doc: this one is not normally used
|
||||
CurrentControl:
|
||||
VelocityControl:
|
||||
PositionControl:
|
||||
@@ -683,14 +873,96 @@ valuetypes:
|
||||
ODrive.Controller.InputMode:
|
||||
values:
|
||||
Inactive:
|
||||
brief: Disable inputs. Setpoints retain their last value.
|
||||
Passthrough:
|
||||
VelRamp:
|
||||
PosFilter:
|
||||
MixChannels:
|
||||
TrapTraj:
|
||||
CurrentRamp:
|
||||
Mirror:
|
||||
brief: Pass `input_xxx` through to `xxx_setpoint` directly.
|
||||
doc: |
|
||||
### Valid Inputs:
|
||||
* `input_pos`
|
||||
* `input_vel`
|
||||
* `input_current`
|
||||
|
||||
### Valid Control modes:
|
||||
* `CONTROL_MODE_VOLTAGE_CONTROL`
|
||||
* `CONTROL_MODE_CURRENT_CONTROL`
|
||||
* `CONTROL_MODE_VELOCITY_CONTROL`
|
||||
* `CONTROL_MODE_POSITION_CONTROL`
|
||||
VelRamp:
|
||||
brief: Ramps a velocity command from the current value to the target value.
|
||||
doc: |
|
||||
### Configuration Values:
|
||||
* `config.vel_ramp_rate` [cpr/sec]
|
||||
* `config.inertia` [A/(count/s^2))]
|
||||
|
||||
### Valid inputs:
|
||||
* `input_vel`
|
||||
|
||||
### Valid Control Modes:
|
||||
* `CONTROL_MODE_VELOCITY_CONTROL`
|
||||
PosFilter:
|
||||
brief: Implements a 2nd order position tracking filter.
|
||||
doc: |
|
||||
Intended 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:
|
||||
* `config.input_filter_bandwidth`
|
||||
* `config.inertia`
|
||||
|
||||
### Valid inputs:
|
||||
* `input_pos`
|
||||
|
||||
### Valid Control modes:
|
||||
* `CONTROL_MODE_POSITION_CONTROL`
|
||||
MixChannels:
|
||||
brief: Not Implemented.
|
||||
TrapTraj:
|
||||
brief: Implementes an online trapezoidal trajectory planner.
|
||||
doc: |
|
||||

|
||||
|
||||
### Configuration Values:
|
||||
* `trap_traj.config.vel_limit`
|
||||
* `trap_traj.config.accel_limit`
|
||||
* `trap_traj.config.decel_limit`
|
||||
* `config.inertia`
|
||||
|
||||
### Valid Inputs:
|
||||
* `input_pos`
|
||||
|
||||
### Valid Control Modes:
|
||||
* `CONTROL_MODE_POSITION_CONTROL`
|
||||
CurrentRamp:
|
||||
brief: Ramp a current command from the current value to the target value.
|
||||
doc: |
|
||||
### Configuration Values:
|
||||
* `config.current_ramp_rate`
|
||||
|
||||
### Valid Inputs:
|
||||
* `input_current`
|
||||
|
||||
### Valid Control Modes:
|
||||
* `CONTROL_MODE_CURRENT_CONTROL`
|
||||
Mirror:
|
||||
brief: Implements "electronic mirroring".
|
||||
doc: |
|
||||
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
|
||||
* `config.axis_to_mirror`
|
||||
* `config.mirror_ratio`
|
||||
|
||||
### Valid Inputs
|
||||
* None. Inputs are taken directly from the other axis encoder estimates
|
||||
|
||||
### Valid Control modes
|
||||
* `CONTROL_MODE_POSITION_CONTROL`
|
||||
|
||||
ODrive.Motor.MotorType:
|
||||
values:
|
||||
|
||||
+114
-116
@@ -1,55 +1,57 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activesupport (4.2.9)
|
||||
i18n (~> 0.7)
|
||||
activesupport (6.0.3.1)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
addressable (2.5.2)
|
||||
public_suffix (>= 2.0.2, < 4.0)
|
||||
zeitwerk (~> 2.2, >= 2.2.2)
|
||||
addressable (2.7.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
coffee-script (2.4.1)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.11.1)
|
||||
colorator (1.1.0)
|
||||
commonmarker (0.17.9)
|
||||
commonmarker (0.17.13)
|
||||
ruby-enum (~> 0.5)
|
||||
concurrent-ruby (1.0.5)
|
||||
concurrent-ruby (1.1.6)
|
||||
dnsruby (1.61.3)
|
||||
addressable (~> 2.5)
|
||||
em-websocket (0.5.1)
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0.6.0)
|
||||
ethon (0.11.0)
|
||||
ethon (0.12.0)
|
||||
ffi (>= 1.3.0)
|
||||
eventmachine (1.2.5)
|
||||
eventmachine (1.2.7)
|
||||
execjs (2.7.0)
|
||||
faraday (0.14.0)
|
||||
faraday (1.0.1)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ffi (1.9.24)
|
||||
ffi (1.12.2)
|
||||
forwardable-extended (2.6.0)
|
||||
gemoji (3.0.0)
|
||||
github-pages (181)
|
||||
activesupport (= 4.2.9)
|
||||
github-pages-health-check (= 1.4.0)
|
||||
jekyll (= 3.7.4)
|
||||
jekyll-avatar (= 0.5.0)
|
||||
gemoji (3.0.1)
|
||||
github-pages (206)
|
||||
github-pages-health-check (= 1.16.1)
|
||||
jekyll (= 3.8.7)
|
||||
jekyll-avatar (= 0.7.0)
|
||||
jekyll-coffeescript (= 1.1.1)
|
||||
jekyll-commonmark-ghpages (= 0.1.5)
|
||||
jekyll-commonmark-ghpages (= 0.1.6)
|
||||
jekyll-default-layout (= 0.1.4)
|
||||
jekyll-feed (= 0.9.3)
|
||||
jekyll-feed (= 0.13.0)
|
||||
jekyll-gist (= 1.5.0)
|
||||
jekyll-github-metadata (= 2.9.4)
|
||||
jekyll-mentions (= 1.3.0)
|
||||
jekyll-optional-front-matter (= 0.3.0)
|
||||
jekyll-github-metadata (= 2.13.0)
|
||||
jekyll-mentions (= 1.5.1)
|
||||
jekyll-optional-front-matter (= 0.3.2)
|
||||
jekyll-paginate (= 1.1.0)
|
||||
jekyll-readme-index (= 0.2.0)
|
||||
jekyll-redirect-from (= 0.13.0)
|
||||
jekyll-relative-links (= 0.5.3)
|
||||
jekyll-remote-theme (= 0.2.3)
|
||||
jekyll-readme-index (= 0.3.0)
|
||||
jekyll-redirect-from (= 0.15.0)
|
||||
jekyll-relative-links (= 0.6.1)
|
||||
jekyll-remote-theme (= 0.4.1)
|
||||
jekyll-sass-converter (= 1.5.2)
|
||||
jekyll-seo-tag (= 2.4.0)
|
||||
jekyll-sitemap (= 1.2.0)
|
||||
jekyll-swiss (= 0.4.0)
|
||||
jekyll-seo-tag (= 2.6.1)
|
||||
jekyll-sitemap (= 1.4.0)
|
||||
jekyll-swiss (= 1.0.0)
|
||||
jekyll-theme-architect (= 0.1.1)
|
||||
jekyll-theme-cayman (= 0.1.1)
|
||||
jekyll-theme-dinky (= 0.1.1)
|
||||
@@ -59,33 +61,32 @@ GEM
|
||||
jekyll-theme-midnight (= 0.1.1)
|
||||
jekyll-theme-minimal (= 0.1.1)
|
||||
jekyll-theme-modernist (= 0.1.1)
|
||||
jekyll-theme-primer (= 0.5.3)
|
||||
jekyll-theme-primer (= 0.5.4)
|
||||
jekyll-theme-slate (= 0.1.1)
|
||||
jekyll-theme-tactile (= 0.1.1)
|
||||
jekyll-theme-time-machine (= 0.1.1)
|
||||
jekyll-titles-from-headings (= 0.5.1)
|
||||
jemoji (= 0.9.0)
|
||||
kramdown (= 1.16.2)
|
||||
liquid (= 4.0.0)
|
||||
listen (= 3.1.5)
|
||||
jekyll-titles-from-headings (= 0.5.3)
|
||||
jemoji (= 0.11.1)
|
||||
kramdown (= 1.17.0)
|
||||
liquid (= 4.0.3)
|
||||
mercenary (~> 0.3)
|
||||
minima (= 2.4.0)
|
||||
nokogiri (>= 1.8.5, < 2.0)
|
||||
rouge (= 2.2.1)
|
||||
minima (= 2.5.1)
|
||||
nokogiri (>= 1.10.4, < 2.0)
|
||||
rouge (= 3.19.0)
|
||||
terminal-table (~> 1.4)
|
||||
github-pages-health-check (1.4.0)
|
||||
github-pages-health-check (1.16.1)
|
||||
addressable (~> 2.3)
|
||||
net-dns (~> 0.8)
|
||||
dnsruby (~> 1.60)
|
||||
octokit (~> 4.0)
|
||||
public_suffix (~> 2.0)
|
||||
public_suffix (~> 3.0)
|
||||
typhoeus (~> 1.3)
|
||||
html-pipeline (2.7.1)
|
||||
html-pipeline (2.13.0)
|
||||
activesupport (>= 2)
|
||||
nokogiri (>= 1.8.5)
|
||||
nokogiri (>= 1.4)
|
||||
http_parser.rb (0.6.0)
|
||||
i18n (0.9.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jekyll (3.7.4)
|
||||
jekyll (3.8.7)
|
||||
addressable (~> 2.4)
|
||||
colorator (~> 1.0)
|
||||
em-websocket (~> 0.5)
|
||||
@@ -98,51 +99,50 @@ GEM
|
||||
pathutil (~> 0.9)
|
||||
rouge (>= 1.7, < 4)
|
||||
safe_yaml (~> 1.0)
|
||||
jekyll-avatar (0.5.0)
|
||||
jekyll (~> 3.0)
|
||||
jekyll-avatar (0.7.0)
|
||||
jekyll (>= 3.0, < 5.0)
|
||||
jekyll-coffeescript (1.1.1)
|
||||
coffee-script (~> 2.2)
|
||||
coffee-script-source (~> 1.11.1)
|
||||
jekyll-commonmark (1.2.0)
|
||||
jekyll-commonmark (1.3.1)
|
||||
commonmarker (~> 0.14)
|
||||
jekyll (>= 3.0, < 4.0)
|
||||
jekyll-commonmark-ghpages (0.1.5)
|
||||
jekyll (>= 3.7, < 5.0)
|
||||
jekyll-commonmark-ghpages (0.1.6)
|
||||
commonmarker (~> 0.17.6)
|
||||
jekyll-commonmark (~> 1)
|
||||
rouge (~> 2)
|
||||
jekyll-commonmark (~> 1.2)
|
||||
rouge (>= 2.0, < 4.0)
|
||||
jekyll-default-layout (0.1.4)
|
||||
jekyll (~> 3.0)
|
||||
jekyll-feed (0.9.3)
|
||||
jekyll (~> 3.3)
|
||||
jekyll-feed (0.13.0)
|
||||
jekyll (>= 3.7, < 5.0)
|
||||
jekyll-gist (1.5.0)
|
||||
octokit (~> 4.2)
|
||||
jekyll-github-metadata (2.9.4)
|
||||
jekyll (~> 3.1)
|
||||
jekyll-github-metadata (2.13.0)
|
||||
jekyll (>= 3.4, < 5.0)
|
||||
octokit (~> 4.0, != 4.4.0)
|
||||
jekyll-mentions (1.3.0)
|
||||
activesupport (~> 4.0)
|
||||
jekyll-mentions (1.5.1)
|
||||
html-pipeline (~> 2.3)
|
||||
jekyll (~> 3.0)
|
||||
jekyll-optional-front-matter (0.3.0)
|
||||
jekyll (~> 3.0)
|
||||
jekyll (>= 3.7, < 5.0)
|
||||
jekyll-optional-front-matter (0.3.2)
|
||||
jekyll (>= 3.0, < 5.0)
|
||||
jekyll-paginate (1.1.0)
|
||||
jekyll-readme-index (0.2.0)
|
||||
jekyll (~> 3.0)
|
||||
jekyll-redirect-from (0.13.0)
|
||||
jekyll (~> 3.3)
|
||||
jekyll-relative-links (0.5.3)
|
||||
jekyll (~> 3.3)
|
||||
jekyll-remote-theme (0.2.3)
|
||||
jekyll (~> 3.5)
|
||||
rubyzip (>= 1.3.0, < 3.0)
|
||||
typhoeus (>= 0.7, < 2.0)
|
||||
jekyll-readme-index (0.3.0)
|
||||
jekyll (>= 3.0, < 5.0)
|
||||
jekyll-redirect-from (0.15.0)
|
||||
jekyll (>= 3.3, < 5.0)
|
||||
jekyll-relative-links (0.6.1)
|
||||
jekyll (>= 3.3, < 5.0)
|
||||
jekyll-remote-theme (0.4.1)
|
||||
addressable (~> 2.0)
|
||||
jekyll (>= 3.5, < 5.0)
|
||||
rubyzip (>= 1.3.0)
|
||||
jekyll-sass-converter (1.5.2)
|
||||
sass (~> 3.4)
|
||||
jekyll-seo-tag (2.4.0)
|
||||
jekyll (~> 3.3)
|
||||
jekyll-sitemap (1.2.0)
|
||||
jekyll (~> 3.3)
|
||||
jekyll-swiss (0.4.0)
|
||||
jekyll-seo-tag (2.6.1)
|
||||
jekyll (>= 3.3, < 5.0)
|
||||
jekyll-sitemap (1.4.0)
|
||||
jekyll (>= 3.7, < 5.0)
|
||||
jekyll-swiss (1.0.0)
|
||||
jekyll-theme-architect (0.1.1)
|
||||
jekyll (~> 3.5)
|
||||
jekyll-seo-tag (~> 2.0)
|
||||
@@ -170,8 +170,8 @@ GEM
|
||||
jekyll-theme-modernist (0.1.1)
|
||||
jekyll (~> 3.5)
|
||||
jekyll-seo-tag (~> 2.0)
|
||||
jekyll-theme-primer (0.5.3)
|
||||
jekyll (~> 3.5)
|
||||
jekyll-theme-primer (0.5.4)
|
||||
jekyll (> 3.5, < 5.0)
|
||||
jekyll-github-metadata (~> 2.9)
|
||||
jekyll-seo-tag (~> 2.0)
|
||||
jekyll-theme-slate (0.1.1)
|
||||
@@ -183,62 +183,60 @@ GEM
|
||||
jekyll-theme-time-machine (0.1.1)
|
||||
jekyll (~> 3.5)
|
||||
jekyll-seo-tag (~> 2.0)
|
||||
jekyll-titles-from-headings (0.5.1)
|
||||
jekyll (~> 3.3)
|
||||
jekyll-watch (2.0.0)
|
||||
jekyll-titles-from-headings (0.5.3)
|
||||
jekyll (>= 3.3, < 5.0)
|
||||
jekyll-watch (2.2.1)
|
||||
listen (~> 3.0)
|
||||
jemoji (0.9.0)
|
||||
activesupport (~> 4.0, >= 4.2.9)
|
||||
jemoji (0.11.1)
|
||||
gemoji (~> 3.0)
|
||||
html-pipeline (~> 2.2)
|
||||
jekyll (~> 3.0)
|
||||
kramdown (1.16.2)
|
||||
liquid (4.0.0)
|
||||
listen (3.1.5)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
ruby_dep (~> 1.2)
|
||||
jekyll (>= 3.0, < 5.0)
|
||||
kramdown (1.17.0)
|
||||
liquid (4.0.3)
|
||||
listen (3.2.1)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
mercenary (0.3.6)
|
||||
mini_portile2 (2.3.0)
|
||||
minima (2.4.0)
|
||||
jekyll (~> 3.5)
|
||||
mini_portile2 (2.4.0)
|
||||
minima (2.5.1)
|
||||
jekyll (>= 3.5, < 5.0)
|
||||
jekyll-feed (~> 0.9)
|
||||
jekyll-seo-tag (~> 2.1)
|
||||
minitest (5.11.3)
|
||||
multipart-post (2.0.0)
|
||||
net-dns (0.8.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
mini_portile2 (~> 2.3.0)
|
||||
octokit (4.8.0)
|
||||
minitest (5.14.1)
|
||||
multipart-post (2.1.1)
|
||||
nokogiri (1.10.9)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
octokit (4.18.0)
|
||||
faraday (>= 0.9)
|
||||
sawyer (~> 0.8.0, >= 0.5.3)
|
||||
pathutil (0.16.1)
|
||||
pathutil (0.16.2)
|
||||
forwardable-extended (~> 2.6)
|
||||
public_suffix (2.0.5)
|
||||
rb-fsevent (0.10.3)
|
||||
rb-inotify (0.9.10)
|
||||
ffi (>= 0.5.0, < 2)
|
||||
rouge (2.2.1)
|
||||
ruby-enum (0.7.2)
|
||||
public_suffix (3.1.1)
|
||||
rb-fsevent (0.10.4)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
rouge (3.19.0)
|
||||
ruby-enum (0.8.0)
|
||||
i18n
|
||||
ruby_dep (1.5.0)
|
||||
rubyzip (1.3.0)
|
||||
safe_yaml (1.0.4)
|
||||
sass (3.5.6)
|
||||
rubyzip (2.3.0)
|
||||
safe_yaml (1.0.5)
|
||||
sass (3.7.4)
|
||||
sass-listen (~> 4.0.0)
|
||||
sass-listen (4.0.0)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
sawyer (0.8.1)
|
||||
addressable (>= 2.3.5, < 2.6)
|
||||
faraday (~> 0.8, < 1.0)
|
||||
sawyer (0.8.2)
|
||||
addressable (>= 2.3.5)
|
||||
faraday (> 0.8, < 2.0)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
thread_safe (0.3.6)
|
||||
typhoeus (1.3.0)
|
||||
typhoeus (1.4.0)
|
||||
ethon (>= 0.9.0)
|
||||
tzinfo (1.2.5)
|
||||
tzinfo (1.2.7)
|
||||
thread_safe (~> 0.1)
|
||||
unicode-display_width (1.3.0)
|
||||
unicode-display_width (1.7.0)
|
||||
zeitwerk (2.3.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
@@ -248,4 +246,4 @@ DEPENDENCIES
|
||||
jekyll-redirect-from
|
||||
|
||||
BUNDLED WITH
|
||||
1.16.1
|
||||
2.1.4
|
||||
|
||||
+4
-1
@@ -1,5 +1,8 @@
|
||||
theme: jekyll-theme-minimal
|
||||
exclude: [ruby-bundle]
|
||||
exclude: [ruby-bundle, vendor]
|
||||
plugins:
|
||||
- jekyll-redirect-from
|
||||
google_analytics: UA-93396600-3
|
||||
collections:
|
||||
api:
|
||||
output: true
|
||||
|
||||
+16
-13
@@ -3,34 +3,37 @@
|
||||
# https://jekyllrb.com/tutorials/navigation/#scenario-8-retrieving-items-based-on-front-matter-properties
|
||||
|
||||
sections:
|
||||
- title: For Users
|
||||
- title: General
|
||||
docs:
|
||||
- title: Getting Started
|
||||
url: /
|
||||
- title: ODrive Tool
|
||||
url: odrivetool
|
||||
url: /odrivetool
|
||||
- title: Parameters & Commands
|
||||
url: commands
|
||||
url: /commands
|
||||
- title: Interfaces
|
||||
url: interfaces
|
||||
url: /interfaces
|
||||
- title: Encoders
|
||||
url: encoders
|
||||
url: /encoders
|
||||
- title: Homing & Endstops
|
||||
url: endstops
|
||||
url: /endstops
|
||||
- title: Control & Tuning
|
||||
url: control
|
||||
- title: Hoverboard Guide
|
||||
url: hoverboard
|
||||
url: /control
|
||||
- title: Troubleshooting
|
||||
url: troubleshooting
|
||||
url: /troubleshooting
|
||||
- title: Tutorials
|
||||
docs:
|
||||
- title: Hoverboard Guide
|
||||
url: /hoverboard
|
||||
- title: API Reference
|
||||
- title: For ODrive Developers
|
||||
docs:
|
||||
- title: Firmware Developer Guide
|
||||
url: developer-guide
|
||||
url: /developer-guide
|
||||
- title: Configuring Visual Studio Code
|
||||
url: configuring-vscode
|
||||
url: /configuring-vscode
|
||||
- title: Configuring Eclipse
|
||||
url: configuring-eclipse
|
||||
url: /configuring-eclipse
|
||||
- title: Component Guides
|
||||
docs:
|
||||
- title: Motor Guide
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
---
|
||||
title: '[% if interface %][[interface.fullname]][% else %][[enum.fullname]][% endif %]'
|
||||
layout: default
|
||||
edit_url: 'Firmware/odrive-interface.yaml'
|
||||
download:
|
||||
url: 'Firmware/odrive-interface.yaml'
|
||||
text: 'download as YAML'
|
||||
---
|
||||
|
||||
[%- macro interface_ref(type) -%]
|
||||
**[['[']]<span [% if type.brief %]title="[[type.brief]]"[% endif %]>[[type.name]]</span>[[']']]([[type.fullname | lower]])**
|
||||
[%- endmacro %]
|
||||
|
||||
[%- macro value_type_ref(type) -%]
|
||||
[%- if type.builtin -%]
|
||||
<span title="C type: [[type.c_name]], Python type: [[type.py_type]]">[[type.name]]</span>
|
||||
[%- else -%]
|
||||
[['[']]<span [% if type.brief %]title="[[type.brief]]"[% endif %]>[[type.name]]</span>[[']']]([[type.fullname | lower]])
|
||||
[%- endif %]
|
||||
[%- endmacro %]
|
||||
|
||||
[% macro attr_ref(token, attr) -%]
|
||||
**[['[']]<span [% if attr.brief %]title="[[attr.brief]]"[% endif %]>[[token]]</span>[[']']]([[attr.parent.fullname | lower]]#[[attr.name]])**
|
||||
[%- endmacro %]
|
||||
|
||||
[% if interface %]
|
||||
[% set scope = interface %]
|
||||
[% else %]
|
||||
[% set scope = enum.parent %]
|
||||
[% endif %]
|
||||
|
||||
[%- macro doc_tokenize(text) %][[ text | tokenize(scope, interface_ref, value_type_ref, attr_ref) ]][% endmacro %]
|
||||
|
||||
[%- macro status_badge(status) %]
|
||||
[%- if status == 'experimental' %]
|
||||
<span style="border: 1px solid; border-radius: 3px; padding: 1px 10px; color: #c35400; float: right;" title="This feature is still experimental. It may be buggy or change later. Use with caution.">Experimental</span>
|
||||
[%- endif %]
|
||||
[%- if status == 'deprecated' %]
|
||||
<span style="border: 1px solid; border-radius: 3px; padding: 1px 10px; color: #c35400; float: right;" title="This feature is deprecated and may be removed in future versions.">Deprecated</span>
|
||||
[%- endif %]
|
||||
[%- endmacro %]
|
||||
|
||||
[%- macro breadcrumbs(title) %]
|
||||
# [% for item in title.split('.') | diagonalize -%]
|
||||
<a href="[[item | join('.') | lower]]">[[item[-1]]]</a>
|
||||
[%- if not loop.last %]<span style="font-size: x-large;opacity: 50%;"> 〉</span>[% endif %]
|
||||
[%- endfor %]
|
||||
[%- endmacro %]
|
||||
|
||||
[% if interface %]
|
||||
|
||||
[[breadcrumbs(interface.fullname)]]
|
||||
|
||||
[%- if interface.doc or interface.brief %]
|
||||
[[doc_tokenize(interface.brief)]][% if interface.brief and interface.doc %]
|
||||
|
||||
[% endif %][[doc_tokenize(interface.doc)]]
|
||||
[%- endif %]
|
||||
|
||||
## Attributes
|
||||
|
||||
[% if interface.attributes %]
|
||||
[% for attr in interface.attributes.values() %]
|
||||
[%- if attr.type.purename == 'fibre.Property' %]
|
||||
<a name="[[attr.name]]"></a><span style="font-size: medium;">**<code markdown="span">[[attr.name]]</code>** — <code markdown="span">[[value_type_ref(attr.type.value_type)]]</code></span> <span style="font-size: small;">_[[attr.type.mode]]_</span>
|
||||
[%- else %]
|
||||
<a name="[[attr.name]]"></a><span style="font-size: medium;">**<code markdown="span">[[attr.name]]</code>** — <code markdown="span">[[interface_ref(attr.type)]]</code></span>
|
||||
[%- endif %]
|
||||
[[-status_badge(attr.status)]]
|
||||
|
||||
<ul markdown="block">
|
||||
[% if attr.doc or attr.brief %]
|
||||
[[doc_tokenize(attr.brief)]][% if attr.brief and attr.doc %]
|
||||
|
||||
[% endif %][%- if attr.unit %]
|
||||
|
||||
**Unit:** [[attr.unit]]
|
||||
|
||||
[% endif %][[doc_tokenize(attr.doc)]]
|
||||
[%- else %]
|
||||
_No description_
|
||||
[%- endif %]
|
||||
</ul>
|
||||
[% endfor %]
|
||||
[% else %]
|
||||
This interface has no attributes.
|
||||
[% endif %]
|
||||
|
||||
## Functions
|
||||
|
||||
[% if interface.functions %]
|
||||
[% for function in interface.functions.values() %]
|
||||
<a name="[[function.name]]"></a><span style="font-size: medium;"><code markdown="span">**[[function.name]]**([% for arg in function.in.values() | skip_first %][[arg.name]]: [[value_type_ref(arg.type)]][[', ' if not loop.last]][% endfor %])</code>[% if function.out %] ➔ <code markdown="span">[% for arg in function.out.values() %][[arg.name]]: [[value_type_ref(arg.type)]][[', ' if not loop.last]][% endfor %]</code>[% endif %]</span>
|
||||
|
||||
<ul markdown="block">
|
||||
[% if function.doc or function.brief %]
|
||||
[[doc_tokenize(function.brief)]][% if function.brief and function.doc %]
|
||||
|
||||
[% endif %][[doc_tokenize(function.doc)]]
|
||||
[%- else %]
|
||||
_No description_
|
||||
[%- endif %]
|
||||
[% if function.in.values() | skip_first %]
|
||||
**Inputs:**
|
||||
[%- for arg in function.in.values() | skip_first %]
|
||||
- `[[arg.name]]`: [% if arg.doc %][[doc_tokenize(arg.doc)]][% else %] _No description_[% endif %]
|
||||
[%- endfor %]
|
||||
[%- endif %]
|
||||
[% if function.out.values() %]
|
||||
**Outputs:**
|
||||
[%- for arg in function.out.values() %]
|
||||
- `[[arg.name]]`: [% if arg.doc %][[doc_tokenize(arg.doc)]][% else %] _No description_[% endif %]
|
||||
[%- endfor %]
|
||||
[%- endif %]
|
||||
</ul>
|
||||
[% endfor %]
|
||||
[% else %]
|
||||
This interface has no functions.
|
||||
[% endif %]
|
||||
|
||||
[% else %]
|
||||
|
||||
[[breadcrumbs(enum.fullname)]]
|
||||
|
||||
[%- if enum.doc or enum.brief %]
|
||||
[[doc_tokenize(enum.brief)]][% if enum.brief and enum.doc %]
|
||||
|
||||
[% endif %][[doc_tokenize(enum.doc)]]
|
||||
[%- endif %]
|
||||
|
||||
## [% if enum.is_flags %]Flags[% else %]Values[% endif %]
|
||||
|
||||
[% for k, value in enum['values'].items() %]
|
||||
<a name="[[value.name]]"></a><span style="font-size: medium;">**<code markdown="span">[[(enum.name + value.name) | to_macro_case]]</code>** — [% if enum.is_flags %]0x[['%08x' | format(value.value)]][% else %][[value.value]][% endif %]</span>
|
||||
[[-status_badge(value.status)]]
|
||||
|
||||
<ul markdown="block">
|
||||
[% if value.doc or value.brief %]
|
||||
[[doc_tokenize(value.brief)]][% if value.brief and value.doc %]
|
||||
|
||||
[% endif %][[doc_tokenize(value.doc)]]
|
||||
[%- else %]
|
||||
_No description_
|
||||
[%- endif %]
|
||||
</ul>
|
||||
[% endfor %]
|
||||
|
||||
[% endif %]
|
||||
@@ -0,0 +1,41 @@
|
||||
[%- macro dump_interfaces(interfaces, level) %]
|
||||
[%- for intf in interfaces %]
|
||||
[%- if intf.interfaces or intf.value_types %]
|
||||
<li>
|
||||
{% assign myvar = (page.title + '.') | split: "[[intf.fullname + '.']]" %}
|
||||
<input id="chk-[[intf.fullname]]" type="checkbox" {% if myvar[0] == "" %}checked{% endif %} hidden />
|
||||
<p class="navitem{% if page.title == "[[intf.fullname]]" %} currentitem{% endif %}">
|
||||
[% for i in range(level) %]<a class="levelbar"> </a>[% endfor %]
|
||||
<label style="margin-left: [[level*0]]px;" for="chk-[[intf.fullname]]" class="chevron"></label>
|
||||
<a href="{{site.baseurl}}/api/[[intf.fullname | lower]]">[[intf.name]]</a>
|
||||
</p>
|
||||
<ul class="expandable-list">
|
||||
[[dump_interfaces(intf.interfaces, level + 1) | indent(4)]]
|
||||
[[dump_value_types(intf.enums, level + 1) | indent(4)]]
|
||||
</ul>
|
||||
</li>
|
||||
[%- else %]
|
||||
<li>
|
||||
<p class="navitem{% if page.title == "[[intf.fullname]]" %} currentitem{% endif %}">
|
||||
[% for i in range(level) %]<a class="levelbar"> </a>[% endfor %]
|
||||
<span style="margin-left: 7px; margin-right: 10px; float: inline-start;">•</span>
|
||||
<a href="{{site.baseurl}}/api/[[intf.fullname | lower]]">[[intf.name]]</a>
|
||||
</p>
|
||||
</li>
|
||||
[%- endif %]
|
||||
[%- endfor %]
|
||||
[%- endmacro %]
|
||||
|
||||
[%- macro dump_value_types(value_types, level) %]
|
||||
[%- for enum in value_types %]
|
||||
<li>
|
||||
<p class="navitem{% if page.title == "[[enum.fullname]]" %} currentitem{% endif %}">
|
||||
[% for i in range(level) %]<a class="levelbar"> </a>[% endfor %]
|
||||
<span style="margin-left: 7px; margin-right: 10px; float: inline-start;">•</span>
|
||||
<a href="{{site.baseurl}}/api/[[enum.fullname | lower]]">[[enum.name]]</a>
|
||||
</p>
|
||||
</li>
|
||||
[%- endfor %]
|
||||
[%- endmacro %]
|
||||
|
||||
[[dump_interfaces(toplevel_interfaces, 0)]]
|
||||
+46
-14
@@ -1,3 +1,6 @@
|
||||
{% assign pagename = page.url | replace_first: '/', '' | replace: '.html', '' %}
|
||||
{% if pagename == '' %}{% assign pagename = 'getting-started' %}{% endif %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!-- source: https://github.com/pages-themes/minimal/blob/master/_layouts/default.html -->
|
||||
<html lang="{{ site.lang | default: "en-US" }}">
|
||||
@@ -23,20 +26,29 @@
|
||||
{% endif %}
|
||||
|
||||
<p>{{ site.description | default: site.github.project_tagline }}</p>
|
||||
|
||||
</div>
|
||||
<div style="overflow-y: auto;">
|
||||
<ul id="navbar">
|
||||
{% for section in site.data.index.sections %}
|
||||
<li>
|
||||
<p>{{ section.title }}</p>
|
||||
<li class="navgroup">
|
||||
<p class="navheader">{{ section.title }}</p>
|
||||
<ul>
|
||||
{% if section.title != "API Reference" %}
|
||||
{% for item in section.docs %}
|
||||
<li><a href="{{ item.url }}" alt="{{ item.title }}">{{ item.title }}</a></li>
|
||||
{% assign prefix = item.url | slice: 0 %}
|
||||
{% assign itemname = item.url | replace_first: '/', '' | replace: '.html', '' %}
|
||||
{% if itemname == '' %}{% assign itemname = 'getting-started' %}{% endif %}
|
||||
<li><a class="navitem{% if pagename == itemname %} currentitem{% endif %}" href="{% if prefix == '/' %}{{ site.baseurl }}{% endif %}{{ item.url }}" alt="{{ item.title }}">{{ item.title }}</a></li>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% include apiindex.html %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div style="margin-top: 10px;">
|
||||
{% if site.github.is_project_page %}
|
||||
<p class="view"><a href="{{ site.github.repository_url }}">View the Project on GitHub <small>{{ site.github.repository_nwo }}</small></a></p>
|
||||
{% endif %}
|
||||
@@ -59,15 +71,30 @@
|
||||
</header>
|
||||
<section>
|
||||
|
||||
<div class="edit">
|
||||
{% assign filename = page.url | replace_first: '/', '' | replace: '.html', '.md' %}
|
||||
{% if filename == '' %}{% assign filename = 'getting-started.md' %}{% endif %}
|
||||
<!-- edit icon taken from GitHub -->
|
||||
<svg transform="translate(0,1)" class="octicon octicon-pencil" viewBox="0 0 14 16" version="1.1" width="10" height="12" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M0 12v3h3l8-8-3-3-8 8zm3 2H1v-2h1v1h1v1zm10.3-9.3L12 6 9 3l1.3-1.3a.996.996 0 0 1 1.41 0l1.59 1.59c.39.39.39 1.02 0 1.41z"></path>
|
||||
</svg>
|
||||
<a href="https://www.github.com/madcowswe/ODrive/edit/master/docs/{{ filename }}">edit on GitHub</a>
|
||||
</div>
|
||||
<div class="pageactions">
|
||||
<div>
|
||||
<!-- edit icon taken from GitHub -->
|
||||
<svg transform="translate(0,1)" class="octicon octicon-pencil" viewBox="0 0 14 16" version="1.1" width="10" height="12" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M0 12v3h3l8-8-3-3-8 8zm3 2H1v-2h1v1h1v1zm10.3-9.3L12 6 9 3l1.3-1.3a.996.996 0 0 1 1.41 0l1.59 1.59c.39.39.39 1.02 0 1.41z"></path>
|
||||
</svg>
|
||||
{% if page.edit_url %}
|
||||
{% assign edit_url = "https://www.github.com/madcowswe/ODrive/edit/master/" | append: edit_url %}
|
||||
{% else %}
|
||||
{% assign edit_url = "https://www.github.com/madcowswe/ODrive/edit/master/docs/" | append: pagename | append: ".md" %}
|
||||
{% endif %}
|
||||
<a href="{{edit_url}}">edit on GitHub</a>
|
||||
</div>
|
||||
|
||||
{% if page.download %}
|
||||
<div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="10" height="10" style="fill: #656565;">
|
||||
<path d="M216 0h80c13.3 0 24 10.7 24 24v168h87.7c17.8 0 26.7 21.5 14.1 34.1L269.7 378.3c-7.5 7.5-19.8 7.5-27.3 0L90.1 226.1c-12.6-12.6-3.7-34.1 14.1-34.1H192V24c0-13.3 10.7-24 24-24zm296 376v112c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V376c0-13.3 10.7-24 24-24h146.7l49 49c20.1 20.1 52.5 20.1 72.6 0l49-49H488c13.3 0 24 10.7 24 24zm-124 88c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20zm64 0c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20z"/>
|
||||
</svg>
|
||||
<a href="https://www.github.com/madcowswe/ODrive/edit/master/{{page.download.url}}">{{page.download.text}}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
{{ content }}
|
||||
|
||||
@@ -105,6 +132,11 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
// Scroll the navbar to the position of the selected item
|
||||
var element = document.getElementsByClassName("currentitem")[0];
|
||||
element.scrollIntoView(false);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
+96
-25
@@ -100,7 +100,7 @@ table {
|
||||
width:100%;
|
||||
border-collapse:collapse;
|
||||
display: block;
|
||||
overflow-x: scroll;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
th, td {
|
||||
@@ -128,10 +128,12 @@ header {
|
||||
float:left;
|
||||
position:fixed;
|
||||
-webkit-font-smoothing:subpixel-antialiased;
|
||||
|
||||
overflow-y: auto;
|
||||
top: 50px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -261,7 +263,11 @@ a {
|
||||
}
|
||||
|
||||
h1 a {
|
||||
color: unset;
|
||||
color: unset;
|
||||
}
|
||||
|
||||
.navitem a {
|
||||
color: unset;
|
||||
}
|
||||
|
||||
// a:hover, a:focus {
|
||||
@@ -270,6 +276,7 @@ h1 a {
|
||||
// }
|
||||
|
||||
/*** Navigation bar ***/
|
||||
|
||||
header > div {
|
||||
margin-right: 20px;
|
||||
}
|
||||
@@ -287,42 +294,68 @@ header li {
|
||||
|
||||
#navbar {
|
||||
max-width: 250px;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
header ul p {
|
||||
margin:0;
|
||||
.navgroup {
|
||||
background: #cbcbcb;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.navgroup:first-child {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
#navbar ul {
|
||||
background-color: rgba(255, 255, 255, 0.87);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.navheader {
|
||||
margin:0px;
|
||||
padding-left:5px;
|
||||
display: block;
|
||||
// color: #d60000;
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
background-color: #cbcbcb;
|
||||
}
|
||||
|
||||
header ul ul li a {
|
||||
background: #f8f8f8;
|
||||
.navitem {
|
||||
//border:1px solid #e0e0e0;
|
||||
line-height:1;
|
||||
font-size:12px;
|
||||
font-weight: bold;
|
||||
color:#676767;
|
||||
display:block;
|
||||
display:flex;
|
||||
text-align:left;
|
||||
padding:12px 0px 5px 5px;
|
||||
//margin:12px;
|
||||
height:20px;
|
||||
padding:0px 5px;
|
||||
margin:0px;
|
||||
height:37px;
|
||||
line-height:37px;
|
||||
}
|
||||
|
||||
//// rounded edges (look bad)
|
||||
//header ul p {
|
||||
// border-radius:5px 5px 0 0;
|
||||
//}
|
||||
//header ul ul li:last-child a {
|
||||
// border-radius:0 0 5px 5px;
|
||||
//}
|
||||
.navitem a {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.levelbar {
|
||||
float: inline-start;
|
||||
margin-left: 8px;
|
||||
margin-right: 5px;
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.3);
|
||||
width: 1px !important;
|
||||
}
|
||||
|
||||
.currentitem {
|
||||
//-webkit-box-shadow: inset 0px 0px 5px 3px #aa0000a6;
|
||||
//-moz-box-shadow: inset 0px 0px 5px 3px #aa0000a6;
|
||||
//box-shadow: inset 0px 0px 5px 3px #aa0000a6;
|
||||
color: #d60000;
|
||||
}
|
||||
|
||||
/*** Navbar Hover ***/
|
||||
header ul a:hover, header ul a:focus {
|
||||
.navitem:hover, .navitem:focus {
|
||||
color: #d60000;
|
||||
// color:rgb(0, 0, 0);
|
||||
// background-color: rgba(0, 0, 0, 0.24);
|
||||
@@ -418,11 +451,14 @@ details > div > p:last-child {
|
||||
border-left-color: #5bc0de;
|
||||
}
|
||||
|
||||
/*** edit link ***/
|
||||
.edit {
|
||||
/*** edit/download link ***/
|
||||
.pageactions {
|
||||
float: right;
|
||||
font-size: 12px;
|
||||
}
|
||||
.pageactions > div {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/*** inline code ***/
|
||||
:not(pre) > code {
|
||||
@@ -441,3 +477,38 @@ table th {
|
||||
table tr:nth-child(2n) {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
|
||||
.expandable-list {
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
//background-color: #ffbfbf61;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
-webkit-transition: max-height .5s ease-in-out;
|
||||
transition: max-height .5s ease-in-out;
|
||||
}
|
||||
|
||||
#navbar input[type=checkbox]:checked ~ .expandable-list { /* reset the height when checkbox is checked */
|
||||
max-height: 1000px;
|
||||
}
|
||||
|
||||
.chevron:before {
|
||||
text-align: left;
|
||||
content: "\3009"
|
||||
}
|
||||
|
||||
.chevron {
|
||||
float: left;
|
||||
-webkit-transition: -webkit-transform .5s ease;
|
||||
transition: transform .5s ease;
|
||||
transform-origin: 40% 50%;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
#navbar input[type=checkbox]:checked ~ p .chevron { /* rotate down when checkbox is checked */
|
||||
-webkit-transform: rotate(90deg);
|
||||
-ms-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
+7
-55
@@ -18,30 +18,7 @@ For the most part, both axes on the ODrive can be controlled independently.
|
||||
|
||||
### State Machine
|
||||
|
||||
The current state of an axis is indicated by `<axis>.current_state`. The user can request a new state by assigning a new value to `<axis>.requested_state`. The default state after startup is `AXIS_STATE_IDLE`.
|
||||
|
||||
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.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`.
|
||||
5. `AXIS_STATE_SENSORLESS_CONTROL` Run sensorless control.
|
||||
* The motor must be calibrated (`<axis>.motor.is_calibrated`)
|
||||
* [`<axis>.controller.control_mode`](#control-mode) must be `True`.
|
||||
6. `AXIS_STATE_ENCODER_INDEX_SEARCH` Turn the motor in one direction until the encoder index is traversed. This state can only be entered if `<axis>.encoder.config.use_index` is `True`.
|
||||
7. `AXIS_STATE_ENCODER_OFFSET_CALIBRATION` Turn the motor in one direction for a few seconds and then back to measure the offset between the encoder position and the electrical phase.
|
||||
* Can only be entered if the motor is calibrated (`<axis>.motor.is_calibrated`).
|
||||
* A successful encoder calibration will make the `<axis>.encoder.is_ready` go to true.
|
||||
8. `AXIS_STATE_CLOSED_LOOP_CONTROL` Run closed loop control.
|
||||
* The action depends on the [control mode](#control-mode).
|
||||
* Can only be entered if the motor is calibrated (`<axis>.motor.is_calibrated`) and the encoder is ready (`<axis>.encoder.is_ready`).
|
||||
9. `AXIS_STATE_LOCKIN_SPIN` Run lockin spin.
|
||||
* Can only be entered if the motor is calibrated (`<axis>.motor.is_calibrated`) or the motor direction is unspecified (`<axis>.motor.config.direction == 1`)
|
||||
10. `AXIS_STATE_ENCODER_DIR_FIND` Run encoder direction search.
|
||||
* Can only be entered if the motor is calibrated (`<axis>.motor.is_calibrated`).
|
||||
11. `AXIS_STATE_HOMING` Run axis homing function.
|
||||
* Endstops must be enabled to use this feature.
|
||||
The current state of an axis is indicated by [`<axis>.current_state`](api/odrive.axis#current_state). The user can request a new state by assigning a new value to [`<axis>.requested_state`](api/odrive.axis#current_state). The default state after startup is `AXIS_STATE_IDLE`. A description of all states can be found [here](api/odrive.axis.axisstate).
|
||||
|
||||
|
||||
### Startup Procedure
|
||||
@@ -56,49 +33,24 @@ The ODrive will sequence all enabled startup actions selected in the order shown
|
||||
* `<axis>.config.startup_closed_loop_control`
|
||||
* `<axis>.config.startup_sensorless_control`
|
||||
|
||||
See [state machine](#state-machine) for a description of each state.
|
||||
See [here](api/odrive.axis.axisstate) for a description of each state.
|
||||
|
||||
### Control Mode
|
||||
The default control mode is position control.
|
||||
If you want a different mode, you can change `<axis>.controller.config.control_mode`.
|
||||
Possible values are:
|
||||
* `CONTROL_MODE_POSITION_CONTROL`
|
||||
* `CONTROL_MODE_VELOCITY_CONTROL`
|
||||
* `CONTROL_MODE_CURRENT_CONTROL`
|
||||
* `CONTROL_MODE_VOLTAGE_CONTROL` - this one is not normally used.
|
||||
Possible values are listed [here](api/odrive.axis.controller.controlmode).
|
||||
|
||||
### 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).
|
||||
As of version v0.5.0, 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:
|
||||
|
||||
# Control Commands
|
||||
* `<axis>.controller.input_pos = <encoder_counts>`
|
||||
* `<axis>.controller.input_vel = <encoder_counts/s>`
|
||||
* `<axis>.controller.input_current = <current_in_A>`
|
||||
|
||||
### Input Mode
|
||||
To modify the way the control command affects the motor, you can use the input mode. The default input mode is pass through.
|
||||
If you want a different mode, you can change `<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`
|
||||
Modes can be selected by changing `<axis>.controller.config.input_mode`.
|
||||
The default input mode is `INPUT_MODE_PASSTHROUGH`.
|
||||
Possible values are listed [here](api/odrive.axis.controller.inputmode).
|
||||
|
||||
## System monitoring commands
|
||||
|
||||
|
||||
@@ -258,9 +258,14 @@ To run the docs server locally:
|
||||
|
||||
```bash
|
||||
cd docs
|
||||
gem install bundler
|
||||
bundle install --path ruby-bundle
|
||||
bundle exec jekyll serve --host=0.0.0.0
|
||||
gem install bundler # The gem command typically comes with a Ruby installation
|
||||
#export PATH="$PATH:~/.gem/ruby/2.7.0/bin" # or similar (depends on OS)
|
||||
rm Gemfile.lock # only if below commands cause trouble
|
||||
bundle config path ruby-bundle
|
||||
bundle install
|
||||
mkdir -p _api _includes
|
||||
python ../Firmware/interface_generator_stub.py --definitions ../Firmware/odrive-interface.yaml --template _layouts/api_documentation_template.j2 --outputs _api/'#'.md && python ../Firmware/interface_generator_stub.py --definitions ../Firmware/odrive-interface.yaml --template _layouts/api_index_template.j2 --output _includes/apiindex.html
|
||||
bundle exec jekyll serve --incremental --host=0.0.0.0
|
||||
```
|
||||
|
||||
## Releases
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
# 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:
|
||||
* `CONTROL_MODE_VOLTAGE_CONTROL`
|
||||
* `CONTROL_MODE_CURRENT_CONTROL`
|
||||
* `CONTROL_MODE_VELOCITY_CONTROL`
|
||||
* `CONTROL_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:
|
||||
* `CONTROL_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:
|
||||
* `CONTROL_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:
|
||||
* `CONTROL_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:
|
||||
* `CONTROL_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
|
||||
* `CONTROL_MODE_POSITION_CONTROL`
|
||||
+6
-92
@@ -4,10 +4,6 @@ Table of Contents:
|
||||
<!-- TOC depthFrom:2 depthTo:2 -->
|
||||
|
||||
- [Error codes](#error-codes)
|
||||
- [Common Axis Errors](#common-axis-errors)
|
||||
- [Common Motor Errors](#common-motor-errors)
|
||||
- [Common Encoder Errors](#common-encoder-errors)
|
||||
- [Common Controller Errors](#common-controller-errors)
|
||||
- [USB Connectivity Issues](#usb-connectivity-issues)
|
||||
- [Firmware Issues](#firmware-issues)
|
||||
- [Other issues that may not produce an error code](#other-issues-that-may-not-produce-an-error-code)
|
||||
@@ -17,94 +13,12 @@ Table of Contents:
|
||||
## Error codes
|
||||
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).
|
||||
* Controller error flags defined [here](../Firmware/MotorControl/controller.hpp).
|
||||
* Sensorless estimator error flags defined [here](../Firmware/MotorControl/sensorless_estimator.hpp).
|
||||
|
||||
## Common Axis Errors
|
||||
|
||||
* `ERROR_INVALID_STATE = 0x01`
|
||||
|
||||
You tried to run a state before you are allowed to. Typically you tried to run encoder calibration or closed loop control before the motor was calibrated, or you tried to run closed loop control before the encoder was calibrated.
|
||||
|
||||
* `ERROR_DC_BUS_UNDER_VOLTAGE = 0x02`
|
||||
|
||||
Confirm that your power leads are connected securely. For initial testing a 12V PSU which can supply a couple of amps should be sufficient while the use of low current 'wall wart' plug packs may lead to inconsistent behaviour and is not recommended.
|
||||
|
||||
You can monitor your PSU voltage using liveplotter in odrive tool by entering `start_liveplotter(lambda: [odrv0.vbus_voltage])`. If you see your votlage drop below ~ 8V then you will trip this error. Even a relatively small motor can draw multiple kW momentary and so unless you have a very large PSU or are running of a battery you may encounter this error when executing high speed movements with a high current limit. To limit your PSU power draw you can limit your motor current and/or velocity limit `odrv0.axis0.controller.config.vel_limit` and `odrv0.axis0.motor.config.current_lim`.
|
||||
|
||||
* `ERROR_DC_BUS_OVER_VOLTAGE = 0x04`
|
||||
|
||||
Confirm that you have a brake resistor of the correct value connected securly and that `odrv0.config.brake_resistance` is set to the value of your brake resistor.
|
||||
|
||||
You can monitor your PSU voltage using liveplotter in odrive tool by entering `start_liveplotter(lambda: [odrv0.vbus_voltage])`. If during a move you see the voltage rise above your PSU's nominal set voltage then you have your brake resistance set too low. This may happen if you are using long wires or small gauge wires to connect your brake resistor to your odrive which will added extra resistance. This extra resistance needs to be accounted for to prevent this voltage spike. If you have checked all your connections you can also try increasing your brake resistance by ~ 0.01 Ohm at a time to a maximum of 0.05 greater than your brake resistor value.
|
||||
|
||||
## Common Motor Errors
|
||||
|
||||
* `ERROR_PHASE_RESISTANCE_OUT_OF_RANGE = 0x0001` and `ERROR_PHASE_INDUCTANCE_OUT_OF_RANGE = 0x0002`
|
||||
|
||||
During calibration the motor resistance and [inductance](https://en.wikipedia.org/wiki/Inductance) is measured. If the measured motor resistance or inductance falls outside a set range this error will be returned. Check that all motor leads are connected securely.
|
||||
|
||||
The measured values can be viewed using odrivetool as is shown below:
|
||||
```
|
||||
In [2]: odrv0.axis0.motor.config.phase_inductance
|
||||
Out[2]: 1.408751450071577e-05
|
||||
|
||||
In [3]: odrv0.axis0.motor.config.phase_resistance
|
||||
Out[3]: 0.029788672924041748
|
||||
```
|
||||
Some motors will have a considerably different phase resistance and inductance than this. For example, gimbal motors, some small motors (e.g. < 10A peak current). If you think this applies to you try increasing `odrv0.axis0.motor.config.resistance_calib_max_voltage` from its default value of 1 using odrivetool and repeat the motor calibration process. If your motor has a small peak current draw (e.g. < 20A) you can also try decreasing `odrv0.axis0.motor.config.calibration_current` from its default value of 10A.
|
||||
|
||||
In general, you need
|
||||
```text
|
||||
resistance_calib_max_voltage > calibration_current * phase_resistance
|
||||
resistance_calib_max_voltage < 0.5 * vbus_voltage
|
||||
```
|
||||
|
||||
* `ERROR_DRV_FAULT = 0x0008`
|
||||
|
||||
The ODrive v3.4 is known to have a hardware issue whereby the motors would stop operating
|
||||
when applying high currents to M0. The reported error of both motors in this case
|
||||
is `ERROR_DRV_FAULT`.
|
||||
|
||||
The conjecture is that the high switching current creates large ripples in the
|
||||
power supply of the DRV8301 gate driver chips, thus tripping its under-voltage fault detection.
|
||||
|
||||
To resolve this issue you can limit the M0 current to 40A. The lowest current at which the DRV fault was observed is 45A on one test motor and 50A on another test motor. Refer to [this post](https://discourse.odriverobotics.com/t/drv-fault-on-odrive-v3-4/558) for instructions for a hardware fix.
|
||||
|
||||
* `ERROR_MODULATION_MAGNITUDE = 0x0080`
|
||||
|
||||
The bus voltage was insufficent to push the requested current through the motor.
|
||||
If you are getting this during motor calibration, make sure that `motor.config.resistance_calib_max_voltage` is no more than half your bus voltage.
|
||||
|
||||
For gimbal motors, it is recommended to set the `motor.config.calibration_current` and `motor.config.current_lim` to half your bus voltage, or less.
|
||||
|
||||
## Common Encoder Errors
|
||||
|
||||
* `ERROR_CPR_POLEPAIRS_MISMATCH = 0x02`
|
||||
|
||||
Confirm you have entered the correct count per rotation (CPR) for [your encoder](https://docs.odriverobotics.com/encoders). The ODrive uses your supplied value for the motor pole pairs to measure the CPR. So you should also double check this value.
|
||||
|
||||
Note that the AMT encoders are configurable using the micro-switches on the encoder PCB and so you may need to check that these are in the right positions. If your encoder lists its pulse per rotation (PPR) multiply that number by four to get CPR.
|
||||
|
||||
* `ERROR_NO_RESPONSE = 0x04`
|
||||
|
||||
Confirm that your encoder is plugged into the right pins on the odrive board.
|
||||
|
||||
* `ERROR_INDEX_NOT_FOUND_YET = 0x20`
|
||||
|
||||
Check that your encoder is a model that has an index pulse. If your encoder does not have a wire connected to pin Z on your odrive then it does not output an index pulse.
|
||||
|
||||
## Common Controller Errors
|
||||
|
||||
* `ERROR_OVERSPEED = 0x01`
|
||||
|
||||
Try increasing `<axis>.controller.config.vel_limit`. The default `vel_limit` of 20,000 encoder counts per second gives a motor speed of only ~146 RPM with the common CUI-AMT102 8192 count per rotation encoder. Note: Even if you do not commanded your motor to exceed `vel_limit` sudden changes in the load placed on a motor may cause this speed to be temporarily exceeded, resulting in this error.
|
||||
|
||||
You can also try increasing `<axis>.controller.config.vel_limit_tolerance`. The default value of 1.2 means it will only allow a 20% violation of the speed limit. You can set the `vel_limit_tolerance` to 0 to disable the check altogether.
|
||||
With this information you can look up the API documentation for your error(s):
|
||||
* Axis error flags documented [here](api/odrive.axis.error).
|
||||
* Motor error flags documented [here](api/odrive.motor.error).
|
||||
* Encoder error flags documented [here](api/odrive.encoder.error).
|
||||
* Controller error flags documented [here](api/odrive.controller.error).
|
||||
* Sensorless estimator error flags documented [here](odrive.sensorlessestimator.error).
|
||||
|
||||
## USB Connectivity Issues
|
||||
|
||||
|
||||
Reference in New Issue
Block a user