mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-08-18 18:20:15 +08:00
Merge branch 'devel' of https://github.com/madcowswe/Odrive into A_to_Nm
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())
|
||||
|
||||
|
||||
+319
-39
File diff suppressed because it is too large
Load Diff
+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);
|
||||
}
|
||||
|
||||
+17
-25
@@ -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
|
||||
|
||||
|
||||
@@ -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_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.
|
||||
|
||||

|
||||
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_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://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
|
||||
|
||||
|
||||
@@ -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),
|
||||
])
|
||||
|
||||
@@ -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']
|
||||
|
||||
Reference in New Issue
Block a user