Beat-synced dance for the UFactory xArm 7-DOF. Plays a song, detects beats with librosa, and moves the arm through a small bank of safe joint poses on each beat.
- UFactory xArm (7 joints) on the LAN, default IP
192.168.1.241. - The script uses joint-angle control in degrees via
xarm-python-sdk.
# macOS audio + video backends
brew install portaudio ffmpeg
# python deps
pip install -r requirements.txtffmpeg is required for muxing the song audio into the saved webcam video.
If you already have the semvs conda env from visual_servoing_for_suction_grippers, xarm-python-sdk and opencv-python are already installed; you only need to add the audio stack:
conda activate semvs
brew install portaudio ffmpeg
pip install librosa sounddevice soundfileA no-copyright song is bundled at samples/eliveta.mp3 and is the default audio. You can run with no arguments at all.
Dry run (preview choreography, no arm motion, no recording):
python3 dance.py --dry-run --no-recordWhen you're happy, connect to the arm. Webcam recording is on by default and outputs land in runs/:
python3 dance.pyEach run writes:
runs/dance_<song>_<timestamp>.mp4— webcam video with the song muxed as audioruns/dance_<song>_<timestamp>.log— full stdout log including detected tempo, arm IP / ping, motion params
Override the video path with --record-path out.mp4 or disable recording with --no-record.
The runs/ directory is tracked in git so you can push runs back to the repo for analysis. The script prints the exact git add / commit / push lines at the end of each run.
For the ZED Mini in webcam mode, point at the right camera index:
python dance.py song.mp3 --camera 0 # try 0 first
python dance.py song.mp3 --camera 1 # if 0 is the laptop's FaceTime cameraFor high-BPM songs, dance on every other beat:
python dance.py /path/to/song.mp3 --every-nth 2While the script is running you can stop it with any of:
- press
q(orQ, orESC) in the terminal - press
Ctrl-C(first press = graceful stop, second press = hard kill)
Graceful stop halts the arm at its current pose, finishes recording, muxes the song into the saved video, then disconnects. The video is always written:
- if
ffmpegsucceeds:runs/dance_<song>_<ts>.mp4with audio - if
ffmpegfails or isn't installed:runs/dance_<song>_<ts>.silent.mp4(no audio, can be remuxed later)
This script is intentionally conservative. The arm will not be sent into wild swings.
- All target poses are clipped to a per-joint envelope around a comfortable home pose (
HOME_POSE_DEGandMAX_JOINT_DELTA_DEGindance.py). Envelope verified inside published xArm 7 joint limits with wide margin. - Default joint speed
12 deg/s, accel300 deg/s^2— gentle. Hard refuses values above35 deg/s/800 deg/s^2. (Bump with--speed N --acc Nonce you're confident.) - Beat throttle (
MIN_MOVE_PERIOD_S = 0.75s) drops beats that arrive too close together, so fast songs don't whip the arm. - Camera index falls back: if
--camera 0doesn't open, the script scans indices 0..9 and uses the first working device — works regardless of whether the ZED Mini, a USB webcam, or anything else is plugged in. - On startup the arm moves to home before any beat command is sent. On shutdown it returns to zero pose.
--dry-runruns the full pipeline (audio analysis, scheduling, audio playback) without ever connecting to the arm.
- Add or replace poses in
POSE_BANKindance.py. Each row is a delta in degrees added toHOME_POSE_DEG. Stay withinMAX_JOINT_DELTA_DEG. - Change
HOME_POSE_DEGto face the dance toward your audience. - Increase
--every-nthfor slower, calmer dancing on busy songs.