Merge branch 'devel' of https://github.com/madcowswe/Odrive into A_to_Nm

This commit is contained in:
PAJohnson
2020-06-23 15:59:51 -04:00
17 changed files with 915 additions and 464 deletions
+67
View File
@@ -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
View File
@@ -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
+12 -7
View File
@@ -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())
File diff suppressed because it is too large Load Diff
+114 -116
View File
@@ -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
View File
@@ -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
View File
@@ -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
+148
View File
@@ -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%;">&ensp;&#x3009;</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>**&nbsp;&nbsp;&mdash;&nbsp;&nbsp;<code markdown="span">[[value_type_ref(attr.type.value_type)]]</code></span>&nbsp;&nbsp;&nbsp;&nbsp;<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>**&nbsp;&nbsp;&mdash;&nbsp;&nbsp;<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 %]&nbsp;&nbsp;&#x2794;&nbsp;&nbsp;<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 %]&nbsp;_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 %]&nbsp;_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>**&nbsp;&nbsp;&mdash;&nbsp;&nbsp;[% 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 %]
+41
View File
@@ -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">&nbsp;</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">&nbsp;</a>[% endfor %]
<span style="margin-left: 7px; margin-right: 10px; float: inline-start;">&bull;</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">&nbsp;</a>[% endfor %]
<span style="margin-left: 7px; margin-right: 10px; float: inline-start;">&bull;</span>
<a href="{{site.baseurl}}/api/[[enum.fullname | lower]]">[[enum.name]]</a>
</p>
</li>
[%- endfor %]
[%- endmacro %]
[[dump_interfaces(toplevel_interfaces, 0)]]
+46 -14
View File
@@ -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
View File
@@ -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);
}
+17 -25
View File
@@ -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,11 +33,12 @@ 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`.
<<<<<<< HEAD
Possible values are:
* `CONTROL_MODE_POSITION_CONTROL`
* `CONTROL_MODE_VELOCITY_CONTROL`
@@ -83,10 +61,19 @@ Possible values are:
For more information, see [input_modes](input_modes.md).
# Control Commands
=======
Possible values are listed [here](api/odrive.axis.controller.controlmode).
### Input Mode
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:
>>>>>>> 99507d2ece83127ca556f8fd34994075d517111e
* `<axis>.controller.input_pos = <encoder_counts>`
* `<axis>.controller.input_vel = <encoder_counts/s>`
* `<axis>.controller.input_torque = <torque in Nm>`
<<<<<<< HEAD
### 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`.
@@ -99,6 +86,11 @@ Possible values are:
* `INPUT_MODE_TRAP_TRAJ`
* `INPUT_MODE_TORQUE_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).
>>>>>>> 99507d2ece83127ca556f8fd34994075d517111e
## System monitoring commands
+8 -3
View File
@@ -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
-113
View File
@@ -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_torque`
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_TORQUE_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_torque`
### Valid Control modes:
* `CONTROL_MODE_VOLTAGE_CONTROL`
* `CONTROL_MODE_TORQUE_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.
![POS Filter Response](secondOrderResponse.png)
Result of a step command from 1000 to 0
### Configuration Values:
* `<axis>.controller.config.input_filter_bandwidth`
* `<axis>.controller.config.inertia`
### Valid inputs:
* `input_pos`
### Valid Control modes:
* `CONTROL_MODE_POSITION_CONTROL`
## INPUT_MODE_MIX_CHANNELS
Not Implemented.
## INPUT_MODE_TRAP_TRAJ
Implementes an online trapezoidal trajectory planner.
![Trapezoidal Planner Response](TrapTrajPosVel.png)
### Configuration Values:
* `<axis>.trap_traj.config.vel_limit`
* `<axis>.trap_traj.config.accel_limit`
* `<axis>.trap_traj.config.decel_limit`
* `<axis>.controller.config.inertia`
### Valid Inputs:
* `input_pos`
### Valid Control Modes:
* `CONTROL_MODE_POSITION_CONTROL`
## INPUT_MODE_TORQUE_RAMP
Ramp a torque command from the current value to the target value.
### Configuration Values:
* `<axis>.controller.config.torque_ramp_rate`
### Valid Inputs:
* `input_torque`
### Valid Control Modes:
* `CONTROL_MODE_TORQUE_CONTROL`
## INPUT_MODE_MIRROR
Implements "electronic mirroring". This is like electronic camming, but you can only mirror exactly the movements of the other motor, according to a fixed ratio
[![](http://img.youtube.com/vi/D4_vBtyVVzM/0.jpg)](http://www.youtube.com/watch?v=D4_vBtyVVzM "Example Mirroring Video")
### Configuration Values
* `<axis>.controller.config.axis_to_mirror`
* `<axis>.controller.config.mirror_ratio`
### Valid Inputs
* None. Inputs are taken directly from the other axis encoder estimates
### Valid Control modes
* `CONTROL_MODE_POSITION_CONTROL`
+6 -92
View File
@@ -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
+5 -5
View File
@@ -121,7 +121,7 @@ class TestIncrementalEncoder(TestEncoderBase):
def run_test(self, enc: ODriveEncoderComponent, teensy: TeensyComponent, teensy_gpio_a: TeensyGpio, teensy_gpio_b: TeensyGpio, logger: Logger):
true_cps = 8192*-0.5 # counts per second generated by the virtual encoder
true_cps = 8192*0.5 # counts per second generated by the virtual encoder
code = teensy_incremental_encoder_emulation_code.replace("{enc_a}", str(teensy_gpio_a.num)).replace("{enc_b}", str(teensy_gpio_b.num))
teensy.compile_and_program(code)
@@ -249,7 +249,7 @@ class TestHallEffectEncoder(TestEncoderBase):
def run_test(self, enc: ODriveEncoderComponent, teensy: TeensyComponent, teensy_gpio_a: TeensyGpio, teensy_gpio_b: TeensyGpio, teensy_gpio_c: TeensyGpio, logger: Logger):
true_cpr = 90
true_rps = -1.0
true_rps = 1.0
code = teensy_hall_effect_encoder_emulation_code.replace("{hall_a}", str(teensy_gpio_a.num)).replace("{hall_b}", str(teensy_gpio_b.num)).replace("{hall_c}", str(teensy_gpio_c.num))
teensy.compile_and_program(code)
@@ -504,9 +504,9 @@ class TestSpiEncoder(TestEncoderBase):
if __name__ == '__main__':
test_runner.run([
TestIncrementalEncoder(),
TestSinCosEncoder(),
TestHallEffectEncoder(),
#TestIncrementalEncoder(),
#TestSinCosEncoder(),
#TestHallEffectEncoder(),
TestSpiEncoder(ENCODER_MODE_SPI_ABS_AMS),
TestSpiEncoder(ENCODER_MODE_SPI_ABS_CUI),
])
+4 -4
View File
@@ -78,11 +78,11 @@ connections:
- ['teensy.gpio6', 'rpi.gpio20']
- ['teensy.gpio7', 'rpi.gpio19']
- ['teensy.gpio23', 'odrive.encoder0.z']
- ['teensy.gpio22', 'odrive.encoder0.a']
- ['teensy.gpio21', 'odrive.encoder0.b']
- ['teensy.gpio22', 'odrive.encoder0.b']
- ['teensy.gpio21', 'odrive.encoder0.a']
- ['teensy.gpio20', 'odrive.encoder1.z']
- ['teensy.gpio19', 'odrive.encoder1.a']
- ['teensy.gpio18', 'odrive.encoder1.b']
- ['teensy.gpio19', 'odrive.encoder1.b']
- ['teensy.gpio18', 'odrive.encoder1.a']
- ['teensy.gpio0', 'real_encoder.z']
- ['teensy.gpio1', 'real_encoder.a']
- ['teensy.gpio2', 'real_encoder.b']