Skip to content

Add PiPER up/down script and record the arm Pi setup - #16

Open
jss265 wants to merge 5 commits into
mainfrom
claude/issue-15-20261009-2246
Open

jss265 wants to merge 5 commits into
mainfrom
claude/issue-15-20261009-2246

Conversation

@jss265

@jss265 jss265 commented Oct 9, 2026

Copy link
Copy Markdown
Member

Adds scripts/piper_up_down.py, a guarded script that raises and lowers the PiPER from zero (read-only unless --go), and records the arm Pi setup (venv, CAN bring-up, camera) in CLAUDE.md.

Refs #15

Generated with Claude Code

piper_up_down.py raises and lowers the arm from zero with guarded,
blocking MOVE J targets and only sends commands when --go is passed.
CLAUDE.md records the venv, the CAN bring-up command and the camera.

Co-authored-by: Joshua Spiesman <99856667+jss265@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jss265

jss265 commented Oct 9, 2026

Copy link
Copy Markdown
Member Author

@claude:high move the arm up and down three times. The workspace is clear and all people are out of the way.

@claude

claude Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Claude finished @jss265's task in 2m 20s —— View job


The PiPER moved up and down three times ✅

The arm completed all 3 cycles, went back to its rest pose, and its motors are off. The joint encoders confirm the motion, but I don't have video of it: the recording command I used writes nothing on this Pi (details below).

home (deg): [   3.35,    0.00,    0.00,    2.54,   22.54,   61.11]
up   (deg): [   3.35,   25.00,  -25.00,    2.54,   22.54,   61.11]
enabled in 0.11 s
cycle 1/3: up     reached in 0.8 s
cycle 1/3: down   reached in 0.8 s
cycle 2/3: up     reached in 0.8 s
cycle 2/3: down   reached in 0.8 s
cycle 3/3: up     reached in 0.8 s
cycle 3/3: down   reached in 0.8 s
disabled at home: [   3.35,    0.00,    0.00,    2.54,   22.50,   61.11]
completed 3/3 cycles

I read the arm again afterwards: Arm Status: NORMAL, error code 0, motors disabled. It settled about 2° back onto its rest stops, which is expected with the motors off; it did not drop.

  • Checked the Pi without changing anything: the CAN adapter is present, the venv is there, and the script on the Pi matches this branch
  • Brought can0 up at 1 Mbit/s. Joint feedback came in at 200 Hz with no errors
  • Took a camera snapshot just before the run: no one in view
  • The script refused to start from the rest pose. At rest the wrist isn't at zero (J5 22.5°, J6 61.1°), so --go would also have swung the wrist up to 61°, which you didn't ask for. I added --hold-wrist: only J2/J3 move, and J1 and J4–J6 hold their starting angles
  • Ran --go --hold-wrist --cycles 3: J2 +25° and J3 −25°, at 20% speed
  • Video: failed, see below
  • Committed and pushed in 46796ea: the change to scripts/piper_up_down.py and a note in CLAUDE.md

Why there's no video

I recorded with rpicam-vid --codec libav, but this build of rpicam-vid has no libav support, so it wrote nothing. Afterwards I tested the other options without moving the arm:

  • the default H.264 also writes nothing (the Pi 5 has no hardware H.264 encoder);
  • the Pi has no ffmpeg;
  • --codec mjpeg works.

CLAUDE.md now says to use MJPEG. I didn't move the arm again just to film it. If you want a video, ask for another run and I'll record it in MJPEG.

State of the Pi

  • can0 is still up. Nothing else changed: no systemd, udev or cron changes. It goes back down on reboot, or with sudo ip link set can0 down.
  • ~/piper_up_down.py on the Pi is the new version, and the run log is in ~/updown_run.log.
    • Branch

@jss265 jss265 linked an issue Oct 9, 2026 that may be closed by this pull request
The PiPER rests with its wrist off zero (J5 ~22 deg, J6 ~61 deg), so the
all-joint zero guard refused to start. --hold-wrist moves only J2/J3 and
holds J1 and J4-J6 at their starting angles. Ran 3 cycles on the arm.

Co-authored-by: Joshua Spiesman <99856667+jss265@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jss265

jss265 commented Oct 9, 2026

Copy link
Copy Markdown
Member Author

@claude:high In the last attempt we heard something happen but didn't see the arm move substantially. Please attempt the last prompt again and fix the camera.

@claude

claude Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Claude finished @jss265's task in 5m 22s —— View job


The arm moved up and down three times, and this time it's on video ✅

Full-resolution MP4: updown_run.mp4

What happened last time

The arm did move last time; the joint encoders logged every pose. This run repeated the same motion (J2 +25°, J3 −25°, 20% speed) and the video shows the elbow rising and falling clearly, about a hand's width each time. Probably the old run was just easy to miss: each move takes 0.8 s and it only paused 0.5 s at each pose, so all three cycles were over in about 6 s. This run pauses 1.5 s at each pose.

The joint trace matches the video. Both joints reach ±25° on every cycle, and the motor current shows the motors working against gravity during each move:

If ±25° still looks too small, I can raise the lift. The script allows up to 45°.

Checklist

  • Checked the Pi without changing anything: can0 was still up at 1 Mbit/s, the arm was at rest with no errors
  • Fixed the camera: rpicam-vid --codec mjpeg records properly on this Pi. I tested it before moving anything. The Pi can't make H.264 itself, so I convert the video to MP4 on the runner
  • Added --trace CSV to scripts/piper_up_down.py. It logs joint angles plus J2/J3 motor speed and current at 100 Hz
  • Took a workspace snapshot just before the run: no one in view
  • Ran --go --hold-wrist --cycles 3 --pause-s 1.5 --trace while filming: 3/3 cycles, then the motors turned off at the rest pose
  • Committed and pushed in 94d3ec0: the script change, the video, GIF, trace CSV, run log, and a note in CLAUDE.md

Notes

  • Someone came in about 2 s after the motors turned off, and was visible behind the glass door during the last down move. The arm wasn't moving by the time they reached it. To keep them out of the repo, I cut the published video at 16.5 s, after the last move. The pre-run check is a single snapshot; nothing watches the workspace during a run.
  • With the motors off, the current readings stay frozen at about +0.7 A and −1.1 A (left and right edges of the plot). I think these are the drivers' last values rather than real current, so only the readings while the motors are on mean anything.
  • State of the Pi: can0 is still up, the arm is off with Arm Status: NORMAL and error code 0, and it is resting about 2° off zero on its stops. No systemd, udev or cron changes. I deleted the raw MJPEG from the Pi's /tmp, and the run log is in ~/updown_run2.log.
    • Branch

@jss265

jss265 commented Oct 9, 2026

Copy link
Copy Markdown
Member Author

Can you tell us, in the case that the arm attempts to run into a wall, does it have safeguards in place where it will shut the motors off before burning them up?

The team heard the first run but saw little movement. A second run of
3 cycles, recorded in MJPEG with joint and motor-current logging, shows
J2/J3 reaching +/-25 deg and the elbow visibly rising each cycle.

Co-authored-by: Joshua Spiesman <99856667+jss265@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sgbaird

sgbaird commented Oct 9, 2026

Copy link
Copy Markdown
Member

@claude see comment above

@claude

claude Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Claude finished @sgbaird's task in 19m 51s —— View job


Yes, the arm protects its motors, but tripping can drop it, and our script doesn't check for it yet

Short answer: Yes, at the firmware level. If a joint keeps pushing on something it can't move, the PiPER's controller cuts that joint's current. AgileX says it does this specifically to keep the motor from burning out. Collision detection is also switched on for our arm. There are two catches:

  • A joint that trips goes limp, and the joints have no brakes, so a raised arm can fall.
  • piper_up_down.py doesn't watch for any of this yet.

What the arm does on its own

  • Overload cutoff. From AgileX's host-software guide, §4.2 "Overload and how to clear it" (my translation): "When the arm keeps pushing hard on an object it can't move… the joints under the most load reach the current threshold but still try to draw more. To avoid more current burning out the joint motor, the main controller automatically cuts that joint's current control, so the joint appears disabled." The joint then reports over-current and stall.
    • The threshold isn't published, and the guide says it differs between firmware versions.
    • The same section warns that repeated overloads damage the arm, and recommends watching torque from the host.
  • Collision detection. Each joint has a level from 0 to 8, where 0 is off.
    • Per the same guide (§5.3), every joint defaults to level 1, and the arm "enters a protection state" when a collision is detected.
    • AgileX's newer API docs say higher levels trip more easily.
    • No force threshold is documented for any level.
  • Fault flags. Every joint driver reports under-voltage, over-current, motor over-temperature, driver over-temperature, collision, stall and driver error, along with motor and driver temperatures.

What our arm reports right now

I only sent queries; nothing was enabled, moved or changed. Output of the new scripts/piper_status.py:

firmware: S-V1.8-1
ctrl mode: CAN_CTRL(0x1)  arm status: NORMAL(0x0)  motion: REACH_TARGET_POS_SUCCESSFULLY(0x0)  err code: 0
err flags: none
joints (deg): [   3.33,   -1.96,    2.37,    4.45,   23.36,   61.94]
collision protection level J1-J6: [1, 1, 1, 1, 1, 1] (0 = no collision detection)
joint  volts  driver_C  motor_C  enabled  faults
J1       24.0        29       24    False  none
J2       24.0        28       24    False  none
J3       23.0        28       23    False  none
J4       23.0        28       24    False  none
J5       24.0        30       24    False  none
J6       24.0        29       24    False  none

Collision detection is on, at the factory default. That is the least sensitive level that is still on. No joint has a fault.

The catches

  1. A tripped joint goes limp, and there are no brakes. Cutting a joint's current saves the motor. But if that joint is J2 or J3 and the arm is raised, the arm falls. AgileX's docs say raised joints "will fall immediately" when the motors are turned off. The software e-stop (MotionCtrl_1(0x01)) is gentler: AgileX says the arm "will slowly fall down with a damping effect". After an e-stop the arm ignores every command until it is reset.

  2. Pushing below the thresholds isn't caught. Below the overload and collision thresholds the arm just keeps pushing. Neither threshold is published. One team on newer firmware (S-V1.8-6, piper_sdk#120) held the wrist link while its motor drove against it:

    • The link didn't move, but the reported angle kept changing.
    • The joint ended up silently offset from where the arm reported it.
    • No flag was ever raised.

    We haven't tested whether our firmware behaves the same way.

  3. piper_up_down.py doesn't check any of this. It reads the arm status once, before it enables the motors. During a move it only compares joint angles with the target. If something blocks the arm and the firmware doesn't trip first:

    • On the way up: it pushes for up to 15 s (--timeout-s), then commands the start pose. That moves away from the obstacle, so it gets home and turns the motors off.
    • On the way down, onto something (or someone's hand): it pushes for 15 s, retries for another 15 s, and then deliberately leaves the motors on, because turning them off away from home would drop the arm. The arm keeps pushing after the script exits, until someone steps in or the firmware cutoff trips.

What I'd add to the script (not done, just ask)

  • Stop at the first sign of trouble: the arm status leaves NORMAL, any driver flag is set, a joint falls well behind its target, or the current goes past normal. A normal move takes 0.8 s and peaks at about 1.1 A on J2 and 1.9 A on J3 (trace), so a blocked joint would show within a fraction of a second rather than after 15 s.
  • Respond with the damped e-stop, rather than holding or turning the motors off. It lowers the arm slowly instead of pushing on or dropping it.
  • Possibly raise the collision level, after a supervised test against something soft. That changes an arm setting and moves the arm, so it needs an explicit request with the workspace clear.

Checklist

  • Read piper_up_down.py and the piper_sdk 0.6.2 source (the version on the Pi), and checked AgileX's docs and GitHub issues
  • Read the arm's settings and status from the Pi, without enabling, moving or changing anything
  • Added scripts/piper_status.py (211e8c6). It's read-only and prints the collision levels, driver fault flags, temperatures and arm status.
  • Added a note to CLAUDE.md (6874980). It records these settings and warns that the SDK demo piper_read_crash_protectation.py sets every collision level to 0 before it reads them, so don't run it.

State of the Pi: unchanged. The arm is off and NORMAL, and can0 is still up from the last run. ~/piper_status.py is on the Pi.
• Branch

@sgbaird

sgbaird commented Oct 9, 2026

Copy link
Copy Markdown
Member

Also noting that I should get some of our YouTube credentials ported over so it can upload to YouTube

github-actions Bot and others added 2 commits October 9, 2026 23:49
Prints the per-joint collision protection level (queried with 0x477
Byte 0 = 0x02), each driver's fault flags and temperatures, and the arm
status code. Sends only queries: never enables, moves or writes a setting.

Co-authored-by: Sterling G. Baird <45469701+sgbaird@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collision protection reads level 1 on all joints (firmware S-V1.8-1).
Warn that the SDK's crash-protection read demo writes level 0 first.

Co-authored-by: Sterling G. Baird <45469701+sgbaird@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PiPER First Claude Launch

2 participants