This release is a pre-release and may not be stable for production use.
dls_motor_scanning
Tools for characterising the motion performance of EPICS motors.
Two commands are provided:
scandrives a motor through a range in fixed steps, recording the position actually reached and the time each move took, then reports the positioning error and move time as statistics, a data file and a plot.calibratefits a 5th order polynomial that converts an unscaled feedback device, such as a potentiometer read as raw ADC counts, into engineering units, and emits it as an EPICS calc record and an Excel formula.
| What | Where |
|---|---|
| Source | https://github.com/DiamondLightSource/dls-motor-scanning |
| PyPI | pip install dls-motor-scanning |
| Docker | docker run ghcr.io/diamondlightsource/dls-motor-scanning:latest |
| Releases | https://github.com/DiamondLightSource/dls-motor-scanning/releases |
Scanning a motor
dls-motor-scanning scan MOTOR START STOP STEP DELAY [options]
START, STOP and STEP are in the motor's engineering units, and DELAY is
the settling time in seconds to wait after each move before reading back. Scan
PS-MO-WIRE-01:Y from 40 to 45 in half-EGU steps, with no settling time:
dls-motor-scanning scan PS-MO-WIRE-01:Y 40 45 0.5 0
The scan direction follows START and STOP, so a reverse scan needs no sign
on the step:
dls-motor-scanning scan PS-MO-WIRE-01:Y 45 40 0.5 0
Each run writes Scan_<motor>_<date>_<start>_<stop>_<step>.txt and .png into
the current directory, and prints a summary of the move times and position
errors.
| Option | Effect |
|---|---|
--extra-pv PV |
Read PV at each step and add it as a column and a third plot panel |
--trigger-pv PV |
Pulse PV high then low after each move, for example to fire a detector |
--trigger-width SECS |
How long the trigger is held high (default 1.0) |
--trigger-post-delay SECS |
How long to wait after the trigger returns low (default 0.0) |
--timestamp |
Add a UTC timestamp column taken from the EPICS timestamp of the readback |
--no-txt |
Do not write the data file |
--no-png |
Do not save the plot |
--no-plot |
Do not open a plot window |
The output file
The data file is space separated, with a header row naming the columns:
Desired Actual MoveTime Timestamp(UTC)
40.5 40.499 1.1394305229187012 2026-08-14T09:15:56.375000Z
41.0 40.9992 1.1742472648620605 2026-08-14T09:15:57.625000Z
Timestamp(UTC) is the timestamp the IOC put on the readback record, not the
time the client received it, which makes it directly comparable with archiver
data. It appears only when --timestamp is given, as does the --extra-pv
column.
Plotting on a remote machine
--plot needs a working display. Over a slow link, or on a headless machine,
prefer:
dls-motor-scanning scan PS-MO-WIRE-01:Y 40 45 0.5 0 --no-plot
which skips the interactive window entirely and just writes the png.
A note on backends. cothread integrates with Qt and not with Tk, and the two segfault if combined.
PyQt5is therefore a dependency, and the tool selectsqtaggexplicitly rather than letting matplotlib work through its own candidate list, which would fall back totkagg. If Qt cannot be imported, orDISPLAYis unset, the interactive plot is skipped with a message instead of taking the process down with it.The png is always rendered under Agg and written to disk before any GUI toolkit is touched, so a display problem can never cost you the saved plot.
Calibrating a feedback device
dls-motor-scanning calibrate CSV_PATH [options]
The CSV needs one integer column, taken as the raw feedback, and one float column, taken as the scaled position to calibrate against:
raw,encoder
0,2.0
200,2.5
400,3.0
dls-motor-scanning calibrate pot.csv --raw-input-pv BL01I-MO-POT-01:ADC --excel-cell C2
This prints the six coefficients, a Builder records.calc entry with them
loaded into fields B to G, and an equivalent Excel formula referencing
--excel-cell.
Development
uv sync
uv run pytest
The scan code reaches EPICS through cothread.catools, which is imported lazily
so the tests, --help and the calibrate command all work without an IOC. The
test suite substitutes a fake Channel Access layer, so a full scan can be
exercised without hardware.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dls_motor_scanning-1.0.0b2.tar.gz.
File metadata
- Download URL: dls_motor_scanning-1.0.0b2.tar.gz
- Upload date:
- Size: 78.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bbb2955bcad3d0b62aa3504e906d5c976fa14c62ba159c38289b607fff163b15
|
|
| MD5 |
f3eb5f0a2ea96100c96c13e5a7b54e4e
|
|
| BLAKE2b-256 |
23bdfffa59e8e6b54ad63a27a689d200bf1695698beb8f2e057a3264183a2c8f
|
File details
Details for the file dls_motor_scanning-1.0.0b2-py3-none-any.whl.
File metadata
- Download URL: dls_motor_scanning-1.0.0b2-py3-none-any.whl
- Upload date:
- Size: 21.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
40682e259bae7f48caea1ec3156c7bab559d43c4115652736fde6f23af263ee9
|
|
| MD5 |
820c9bf72cd7cd81385c3c2c7f6af663
|
|
| BLAKE2b-256 |
d42d3fd16d8d12d88fef67407e34e4af53f4f54ad8050631b7253d5c7d3fb90c
|