Skip to content

docs: fix the onboarding gaps found by a new-user walkthrough - #18

Merged
X-F-R merged 1 commit into
mainfrom
docs/fix-new-user-onboarding
Oct 10, 2026
Merged

X-F-R merged 1 commit into
mainfrom
docs/fix-new-user-onboarding

Conversation

@cao-xiao-hao

Copy link
Copy Markdown
Contributor

Summary

A new-user walkthrough was run on real hardware (Litearm 7-axis, /dev/ttyACM0,
firmware Litearm1.10.0-7J), following only what this repository documents. Several
steps a new user hits first either fail outright or mislead. This corrects the
documentation; no code or behaviour changes.

The blocking one: right after power-up the arm sits in the EMERGENCY latch, so the
quick start's first enable() throws ERR{0x10,0x06} before sending a single retry —
and the quick start never mentions reset(). The two Cartesian lines that follow fail
as well: the movej before them leaves the arm fully extended (a singular pose), and
both the move_l target and the ik() target are unusable from there.

Changes

README.zh-CN.md and README.md:

  • Quick start — add the reset() that clears the power-on latch, and say why it is
    not optional. Replace movej([0.1, 0, 0, 0, 0, 0, 0]) with a pose whose joints all
    keep a healthy margin to their limits. Drive move_l / ik from the measured TCP
    instead of (0.30, 0.0, 0.40, 3.1416, 0.0, 0.0), which has no IK solution.
  • Install — usermod -aG dialout is not always required: check
    ls -l /dev/ttyACM0 first. Document the udev rule that makes the node crw-rw-rw-,
    including that any local user on such a machine can drive the arm.
  • Life / safety — clear_faults() clears the single FAULT bit; EMERGENCY and
    FB_STALE are latches only reset() clears.
  • Persistence — save_params() requires the arm to be disabled
    (ERR{0x25,0x04} otherwise), and disabling drops it out of the position loop, so a
    side-mounted or loaded arm sags. Support it first.
  • Things to watch out for — new subsection on mode / flags: the 8 mode_name
    values, why WD_TRIPPED is normal rather than a fault, why FB_STALE is a live
    condition, and that mode == ZERO_G (the arm) and zero_g_active (this session) can
    disagree. Also the exception to the "hz and timestamp are both 0" rule: the first
    frame a process reads reports hz=0.0.
  • Development — a ROS 2 install makes pytest die during collection
    (ModuleNotFoundError: No module named 'lark'); give the two working invocations.
  • Link the troubleshooting guide from the notes section; it had no entry point from
    either top-level README.

TROUBLESHOOTING.zh-CN.md and TROUBLESHOOTING.md:

  • New §17 — the arm is stuck in ZERO_G and zero_g_stop() does nothing. A new
    session cannot send the exit frame, and the firmware rejects every motion command
    until one arrives. Give the enter/exit pairing that recovers, and how to recognise
    the state (mode_name == "ZERO_G" while zero_g_active reads False).

Testing

$ env -u PYTHONPATH pytest -q          # in litearm-python
638 passed, 22 skipped in 62.99s

$ HOME=$(mktemp -d) env -u PYTHONPATH python -m pytest daemon/tests -q   # in litearm-studio
551 passed, 237 warnings in 74.12s

The firmware-sync tests skip unless a litearm-stm32 checkout is present; they account
for 20 of the 22 skips above.

The replacement quick start was extracted from the edited README and run verbatim on the
arm, from power-up, with no exception handling around it:

$ PYTHONPATH=src LITEARM_PORT=/dev/ttyACM0 python3 -u /tmp/qs_zh.py
Litearm1.10.0-7J 7
[0.048511505126953125, 0.3894338607788086, -0.814640998840332, ...]
(0.22064509987831116, 0.3976973295211792, 0.47747859358787537, ...)
[0.061382636427879333, 0.3946659564971924, -0.8173605799674988, ...]
EXIT=0

reset() → enable() → movej → move_l → get_state → get_tcp → ik → home,
every step returning a valid result.

Issues

None — no issue was filed for this; the findings come from the walkthrough. Happy to
file the code-side findings separately if you want them tracked.

A walkthrough was run on real hardware, following only what this
repository documents. Several steps either fail outright or mislead;
this corrects the documentation without changing any code.

Quick start: the arm boots into the EMERGENCY latch, so enable() was
rejected with ERR{0x10,0x06} before a single motion. Add the reset()
that clears it, replace the fully extended joint pose -- a singular
pose no Cartesian motion can be planned out of -- with one whose
joints all stay clear of their limits, and drive the Cartesian moves
from the measured TCP instead of a hand-written pose with no IK
solution.

Also documents serial permissions, the save_params() and
clear_faults() preconditions, the state frame's mode and flags, the
ROS 2 pytest failure, and links the troubleshooting guide, which had
no entry point from the README.
X-F-R pushed a commit that referenced this pull request Oct 10, 2026
Follow-up to the onboarding walkthrough in #18, which covers the quick
start, the install steps and the serial permissions. What is left here is
the part that walkthrough did not reach.

The blocking one is TROUBLESHOOTING.md:144, which says a cartesian move
from the fully-extended home pose "always" fails with err=1. Measured on
hardware: a 1-4 mm step is accepted and reconstructs the arm by 13-60 deg
while the tool moves 1-3 mm. The gate catches large steps, not small ones,
so "always" sends the reader the wrong way about the one pose that is
actually dangerous.

examples/03_move_p.py described its default as "a small step you can step
back from". From the zero pose the same 1 cm target reconstructs the arm by
86.88 deg (J1 74 deg, J3 52 deg) and the script still prints move_p arrived.
The mechanism is firmware-side: move_p reaches the bus through
kin_runner_request_move_p, which has no adjacent-solution gate, while
move_l/move_c/move_path go through cart_plan.c and reject a jump beyond
CART_MAX_IK_STEP (0.35 rad). Both this example and examples/06_cartesian.py
now leave the singularity before issuing a cartesian command.

Three API claims corrected in docs/DEVELOPER_GUIDE.md and README.md:

  * wait=False skips only the wait for the arm to settle. Both values block
    for the plan reply, so poll_cart() never yields a result from one -- its
    real use is recovering a call whose ACK timed out.
  * enable() returns before the state stream reflects it: 2.0-2.7 ms to
    return against 7.0-7.8 ms for the flag to turn true, so reading enabled
    on the next line always shows False. Also recorded in the docstring.
  * the cartesian snippet used three absolute poses with rpy=(pi,0,0), an
    orientation that solves only about half the time; it now offsets the
    measured pose.

Testing: LITEARM_LIVE=1 pytest -> 659 passed. Both examples and the revised
snippet run against the arm: 03_move_p.py --go EXIT=0,
06_cartesian.py --go EXIT=0 (n_wp 5/7/9/6).
@X-F-R
X-F-R merged commit a5cbebb into main Oct 10, 2026
2 checks passed
@X-F-R
X-F-R deleted the docs/fix-new-user-onboarding branch October 10, 2026 09:54
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.1.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@github-actions github-actions Bot added the released Shipped in a release label Oct 10, 2026
X-F-R added a commit that referenced this pull request Oct 10, 2026
…es (#23)

* docs: fix the onboarding gaps found by a new-user walkthrough

A walkthrough was run on real hardware, following only what this
repository documents. Several steps either fail outright or mislead;
this corrects the documentation without changing any code.

Quick start: the arm boots into the EMERGENCY latch, so enable() was
rejected with ERR{0x10,0x06} before a single motion. Add the reset()
that clears it, replace the fully extended joint pose -- a singular
pose no Cartesian motion can be planned out of -- with one whose
joints all stay clear of their limits, and drive the Cartesian moves
from the measured TCP instead of a hand-written pose with no IK
solution.

Also documents serial permissions, the save_params() and
clear_faults() preconditions, the state frame's mode and flags, the
ROS 2 pytest failure, and links the troubleshooting guide, which had
no entry point from the README.

* docs: correct the singular-pose claim, three API notes and two examples

Follow-up to the onboarding walkthrough in #18, which covers the quick
start, the install steps and the serial permissions. What is left here is
the part that walkthrough did not reach.

The blocking one is TROUBLESHOOTING.md:144, which says a cartesian move
from the fully-extended home pose "always" fails with err=1. Measured on
hardware: a 1-4 mm step is accepted and reconstructs the arm by 13-60 deg
while the tool moves 1-3 mm. The gate catches large steps, not small ones,
so "always" sends the reader the wrong way about the one pose that is
actually dangerous.

examples/03_move_p.py described its default as "a small step you can step
back from". From the zero pose the same 1 cm target reconstructs the arm by
86.88 deg (J1 74 deg, J3 52 deg) and the script still prints move_p arrived.
The mechanism is firmware-side: move_p reaches the bus through
kin_runner_request_move_p, which has no adjacent-solution gate, while
move_l/move_c/move_path go through cart_plan.c and reject a jump beyond
CART_MAX_IK_STEP (0.35 rad). Both this example and examples/06_cartesian.py
now leave the singularity before issuing a cartesian command.

Three API claims corrected in docs/DEVELOPER_GUIDE.md and README.md:

  * wait=False skips only the wait for the arm to settle. Both values block
    for the plan reply, so poll_cart() never yields a result from one -- its
    real use is recovering a call whose ACK timed out.
  * enable() returns before the state stream reflects it: 2.0-2.7 ms to
    return against 7.0-7.8 ms for the flag to turn true, so reading enabled
    on the next line always shows False. Also recorded in the docstring.
  * the cartesian snippet used three absolute poses with rpy=(pi,0,0), an
    orientation that solves only about half the time; it now offsets the
    measured pose.

Testing: LITEARM_LIVE=1 pytest -> 659 passed. Both examples and the revised
snippet run against the arm: 03_move_p.py --go EXIT=0,
06_cartesian.py --go EXIT=0 (n_wp 5/7/9/6).

---------

Co-authored-by: thetooler <wuruihao@nexform.tech>
Co-authored-by: YOLO-DT <3199429837@qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

released Shipped in a release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants