ros2-ufactory-lite6: imx95-frdm retarget, spiral demo, arm threading fixes - #26
Merged
Conversation
…etarget imx95-frdm/next - sequences.py: add spiral() helix sequence; http_api.py: expose POST /spiral. - arm.py: rework the ArmController locking strategy; node.py docstring updated. - avocado.yaml: default_target imx8mp-evk -> imx95-frdm, add imx95-frdm to supported_targets, distro channel edge -> next, add curl to the app extension. - container-app.env: bump LITE6_IP to 192.168.1.152.
…telemetry threading
- sequences.py: rework spiral() into a 2D Archimedean spiral (fixed X, sweeping
Y/Z), dropping the unused z_bottom/z_top helix params.
- static/index.html: add a Spiral button.
- arm.py (code-review fixes):
* _wait_for_idle: xArm state==1 means "in motion", not idle -- the old check
returned immediately, or spun forever holding _cmd_lock on a fault/e-stop.
Now it waits for motion to start then finish, returns on fault/stop, and is
bounded by a timeout.
* telemetry poller: keep the thread handle and reap the old thread before
starting a new one, so connect/disconnect churn can't leave two pollers
writing the cache.
* disconnect(): refresh the cached snapshot so status() stops reporting
connected=true after a disconnect.
Avocado References — Build Check
Totals: 1 ✅ passed · 0 ❌ failed Per-reference logs: workflow run |
There was a problem hiding this comment.
Pull request overview
This PR updates the ROS 2 + UFactory Lite 6 reference to target the imx95-frdm platform, adds a new “Spiral” motion demo exposed via the HTTP API/UI, and reworks arm-controller threading to prevent telemetry publishing from blocking on SDK I/O.
Changes:
- Retargets the reference configuration to
imx95-frdmand moves the distro channel tonext(including addingcurlto the app extension). - Adds an Archimedean spiral demo sequence, a
POST /spiralendpoint, and a corresponding UI button. - Refactors
ArmControllerlocking and introduces a background telemetry poller with cached, lock-freestatus()reads.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| ros2-ufactory-lite6/overlay/app/etc/container-app/container-app.env | Updates the default LITE6_IP used by the container app environment. |
| ros2-ufactory-lite6/avocado.yaml | Retargets default/supported boards, switches to next channel, and adds curl to the app extension packages. |
| ros2-ufactory-lite6/app/ros2_lite6/ros2_lite6/static/index.html | Adds a “Spiral” button that triggers the new HTTP endpoint. |
| ros2-ufactory-lite6/app/ros2_lite6/ros2_lite6/sequences.py | Introduces sequences.spiral generating a 2D spiral toolpath. |
| ros2-ufactory-lite6/app/ros2_lite6/ros2_lite6/node.py | Updates the threading model comment to match the new locking strategy. |
| ros2-ufactory-lite6/app/ros2_lite6/ros2_lite6/http_api.py | Exposes the spiral sequence via POST /spiral. |
| ros2-ufactory-lite6/app/ros2_lite6/ros2_lite6/arm.py | Splits locks into SDK vs command serialization, adds telemetry poller + cached status, and revises motion-wait logic. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Address PR review: treat only IDLE (2) and STOPPED (4) as motion completion. The previous "any state != moving" check returned during PAUSED (3) and DECELERATING (6) — both still-active states — which could let the next command fire while the arm was still moving. Keep polling through the transitional states until a terminal one (bounded by the existing timeout).
lee-reinhardt
approved these changes
Aug 19, 2026
…E targets Address PR review (lee-reinhardt): - e-stop is now sticky: emergency_stop() latches _estopped and no longer re-arms the arm; motion methods refuse to run while latched, so a sequence thread can't resume moving right after /estop. Recovery is explicit via clear_faults() (POST /clear), which re-arms and clears the latch (mock too). - telemetry: flip status() to disconnected after _TELEMETRY_MAX_FAILURES consecutive read failures, instead of freezing at the last connected snapshot when the link drops. - README: add imx95-frdm to the frontmatter targets and lead with it (matches the new default_target).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Updates to the ROS 2 / UFactory Lite 6 reference.
Changes
imx95-frdm(added tosupported_targets) on thenextdistro channel; addcurlto the app extension; bumpLITE6_IP.sequences.spiral) exposed atPOST /spiralwith a Spiral button in the web UI._sdk_lock(short) +_cmd_lock(serialises motion), and added a background telemetry poller sostatus()is lock-free and the 30 Hz ROS timer never blocks on SDK I/O.Code-review fixes (in this branch)
_wait_for_idle: xArmstate == 1means in motion, not idle — the naive check returned immediately (or, on a fault/e-stop, spun forever holding_cmd_lock). It now waits for motion to start then finish, returns on fault/stop states, and is bounded by a timeout.disconnect(): refresh the cached snapshot sostatus()stops reportingconnected=trueafter a disconnect.Mock mode (
LITE6_IP=mock) exercises the full stack without hardware; motion methods short-circuit before the wait loop.