Capture script for the UMD Loop spectrometer (STM32 + TCD1304 CCD).
The Jetson (on the rover) has the spectrometer plugged into USB. It runs
get_spectro_image.py, which captures CCD frames for 20 seconds (one PNG every
2 seconds), zips them, and SFTPs the zip to the base station at
192.168.88.10.
┌─────────────┐ USB CDC ┌─────────────┐ SFTP (zip) ┌─────────────────────────┐
│ Spectrometer│ ───────────▶ │ Jetson │ ─────────────▶ │ Base station │
│ (STM32 CCD) │ /dev/spectro│ (rover) │ 192.168.88.10 │ ~/Desktop/spectro_captures│
└─────────────┘ └─────────────┘ └─────────────────────────┘
On both machines this lives inside the ~/infrastructure repo, at
~/infrastructure/spectro-script.
Python 3 plus three pip packages (needed wherever you run get_spectro_image.py,
i.e. the Jetson — and on any machine you want to test the transfer from):
pip3 install pyserial matplotlib paramiko| Package | Used for |
|---|---|
pyserial |
reading CCD frames from the USB serial port |
matplotlib |
rendering each frame to a PNG plot |
paramiko |
SFTP upload of the zip to the base station |
The base station needs no Python packages — just an SSH server (see step 2).
git clone <repo-url> ~/infrastructure
cd ~/infrastructure/spectro-scriptReplace
<repo-url>with the actual remote. All commands below assume the script is at~/infrastructure/spectro-script/get_spectro_image.py.
sudo apt update
sudo apt install -y python3-pip
pip3 install pyserial matplotlib paramiko # see Requirements aboveThe spectrometer enumerates as a USB CDC serial port. The udev rule grants
non-root access and creates a stable /dev/spectro symlink so the script
doesn't depend on the kernel-assigned /dev/ttyACM* number.
cd ~/infrastructure/spectro-script
./install_udev_rule.sh # self-elevates with sudoPlug in (or replug) the spectrometer, then confirm:
ls -l /dev/spectro # should be a symlink to /dev/ttyACM*If /dev/spectro doesn't appear, verify the device is enumerating with the
expected ID (0483:5740):
lsusb | grep 0483The destination base station and credentials are set at the top of
get_spectro_image.py:
REMOTE_HOST = "192.168.88.10"
REMOTE_USER = "umdloop"
REMOTE_PASSWORD = "..." # base-station SSH password
REMOTE_PORT = 22
REMOTE_DIR = "/home/umdloop/Desktop/spectro_captures" # created automatically if missingMake sure these match the base-station account from step 2.
cd ~/infrastructure/spectro-script
python3 get_spectro_image.pyYou should see it capture ~10 frames over 20 seconds, zip them, and report
Transfer complete.
The base station just needs to accept SSH/SFTP connections from the Jetson. The
script creates REMOTE_DIR automatically, so no directory prep is required.
sudo apt update
sudo apt install -y openssh-server
sudo systemctl enable --now ssh- A user matching
REMOTE_USER(e.g.umdloop) must exist with the password set inREMOTE_PASSWORD. - The base station's IP must be
192.168.88.10(static, or a DHCP reservation). Check withip addr.
That's it — incoming zips land on the Desktop in
~/Desktop/spectro_captures/ as spectro_<YYYYmmdd_HHMMSS>.zip.
- On the Jetson:
python3 ~/infrastructure/spectro-script/get_spectro_image.py - On the base station:
A new
ls -lt ~/Desktop/spectro_captures/ | head
spectro_*.zipshould appear. Unzip to view the PNG plots.
All knobs are constants at the top of get_spectro_image.py:
| Setting | Default | Meaning |
|---|---|---|
CAPTURE_DURATION_S |
20 |
Total capture time (seconds) |
CAPTURE_INTERVAL_S |
2 |
Seconds between saved frames |
NUM_PIXELS |
6000 |
Pixels per CCD frame (must match firmware) |
PORT |
/dev/spectro |
Serial device (use COM13 etc. on Windows) |
SFTP transfer failed: ... Authentication failed— wrongREMOTE_USER/REMOTE_PASSWORD, or the base-station account doesn't allow password auth (PasswordAuthentication yesin/etc/ssh/sshd_config).SFTP transfer failed: ... timed out— base station unreachable; check the network and that the IP is192.168.88.10.Timeout waiting for FRAME header— the spectrometer isn't streaming; confirm/dev/spectroexists and the firmware is running.- The password is hardcoded in the script. This is acceptable only because it's a throwaway account on the isolated rover network — don't reuse it elsewhere.