Metadata-Version: 2.5
Name: plesty-anc300-piezo-controller
Version: 0.1.0
Summary: A plesty anc300 piezo controller device.
Author-email: Yunshuang Yuan <yuanyunshuang@gmail.com>
Maintainer-email: Plesty Development Team <plesty.dev@example.com>
License-Expression: LGPL-3.0-or-later
License-File: LICENSE
License-File: LICENSES/LGPL-3.0-or-later.txt
Requires-Python: >=3.12
Requires-Dist: plesty-lib>=0.5.0
Description-Content-Type: text/markdown

# Plesty ANC300 Piezo Controller Device

A PLESTY device module for the Attocube ANC300 piezo controller. It drives the
controller's analog outputs: each axis can be grounded, set to a DC offset
voltage, filtered, and its positioner's capacitance measured. All of it is
reachable from Python and, through the PLESTY device server, over the network.

The module talks to the controller's text console, over USB (a serial port, no
login) or Ethernet (a login session on TCP port 7230): you send one command per
line and the controller answers with data lines and then a final `OK` or `ERROR`
line.

## Supported hardware

| Part | Support |
|---|---|
| ANC300 controller, USB console (serial port, 38400 baud) | Supported |
| ANC300 controller, Ethernet console (TCP 7230) | Supported |
| ANC300 controller, RS232 console | Assumed to behave like USB; not tried |
| ANM200 axis module | Supported, including the filters 1.6, 16, 160 and 1600 Hz |
| ANM300 axis module | Supported; it accepts only the filters off, 16 and 160 Hz, and rejects the others with `ERROR` |

An ANC300 has up to seven axes, one per module slot. By default the module
exposes axes 1 and 2; pass `axes=(1, 2, 3, ...)` to expose others.

## Installation

```bash
git clone https://gitlab.com/plesty/hub/devices/attocube/plesty-anc300-piezo-controller.git
cd plesty-anc300-piezo-controller
uv sync
```

## Quick start

Without hardware, `host="mock"` selects an in-memory simulator that follows the
same protocol:

```python
from plesty.anc300_piezo_controller import Device

with Device(host="mock", axes=(1, 2)) as device:
    device.write("axis_1.mode", "off")  # offset-voltage mode
    device.ramp_offset(axis=1, voltage=5.0)  # move gently to 5 V
    print(device.query("axis_1.offset_voltage"))  # 5.0
    print(device.measure_capacitance(axis=1))  # {"axis": 1, "capacitance": ...}
    device.shutdown_to_ground()  # zero the offsets, mode gnd
```

With a controller, give its serial port (USB) or its address and password
(Ethernet), not both:

```python
Device(serial_port="COM5", axes=(1, 2))  # USB
Device(host="192.168.1.10", port=7230, password="...", axes=(1, 2))  # Ethernet
```

## Run as a server

Copy `.env.example` to `.env` and set the controller's connection:
`DEVICE_ADDRESS` (the serial port, e.g. `COM5`) for USB, or `DEVICE_HOST`,
`DEVICE_PORT` (7230) and `DEVICE_PASSWORD` for Ethernet. `DEVICE_TCP_PORT` is
the port the server binds (default 5555). Then:

```bash
cp .env.example .env
uv run python -m plesty.anc300_piezo_controller --axes 1,2 --max-offset-voltage 100
```

`--serial-port` and `--baudrate` override the serial settings. Each value
resolves as command line, then environment, then default. Before binding, the
server checks that the controller is there: the serial port is listed by the
operating system, or the host resolves and its port accepts a connection. It
stops with the reason if not; `--skip-preflight` serves anyway. `--gui` opens a control panel instead of serving (needs the `gui` extra:
`uv sync --extra gui`). The controller grants one console session, so serve or
use the panel, not both.

## Schema reference

Parameters exist once per axis, as `axis_<n>.<name>` (n = 1 to 7).

| Parameter | Type | Unit | Range / options | Controller commands |
|---|---|---|---|---|
| `mode` | str | | `gnd`, `off`, `inp`, `stp`, `stp+`, `stp-` | `setm` / `getm` |
| `offset_voltage` | float | V | 0 to 150 (lower with `max_offset_voltage`) | `seta` / `geta` |
| `filter` | str | Hz | `off`, `1.6`, `16`, `160`, `1600` | `setfil` / `getfil` |

Operations:

| Operation | Returns | Controller commands |
|---|---|---|
| `get_info()` | firmware `version`, board `serial` | `ver`, `getcser` |
| `get_output_voltage(axis)` | measured output voltage, V | `geto` |
| `get_capacitance(axis)` | saved capacitance, nF | `getc` |
| `wait_capacitance(axis)` | blocks until a measurement ends | `capw` |
| `stop(axis)` | stops any motion on the axis | `stop` |
| `measure_capacitance(axis)` | fresh capacitance, nF; restores mode and offset | `setm cap`, `capw`, `getc` |
| `ramp_offset(axis, voltage, steps=100, duration=1.0)` | offset read back after the ramp | `seta` repeatedly |
| `shift_offset(axis, delta, steps=10, duration=0.1)` | offset read back after the shift | `geta`, then `seta` repeatedly |
| `move_xy(x, y, steps=100, duration=1.0)` | x and y offsets read back | `seta` on both axes, in lockstep |
| `shift_xy(dx, dy, steps=10, duration=0.1)` | x and y offsets read back | `geta`, then `seta` on both axes |
| `shutdown_to_ground()` | grounded axes | `stop`, `seta`, `setm gnd` |

Disconnecting ramps every selected axis's offset to 0 V and leaves its mode as it is; an
offset is never left non-zero, because a controller that loses power or freezes drops it
to zero in one jump. Call `shutdown_to_ground()` to also ground the axes.
The full generated reference is in `docs/`.

## Communication requirements

| | |
|---|---|
| Transport | USB serial port, 38400 baud 8N1; or TCP, controller port 7230 (Ethernet console) |
| Login | USB: none. Ethernet: password on connect (`DEVICE_PASSWORD`); the factory default is in the vendor manual |
| Framing | One command per line, CR LF; replies end with `OK` or `ERROR`, followed on USB by a `> ` prompt |
| Reply time | About 30 ms; the module waits up to 5 s, and 60 s for `capw` |

## Not yet verified on hardware

This module was written from the vendor manual and tested against its simulator;
the first bench session checks these points. See `docs/index.md` for detail.

- The shape of the replies to `getm`, `geta`, `getfil` and `getc`. Only
  `voltage = 2.345000 V` is documented; the others are assumed to be `key = value`.
- The capacitance unit, assumed to be nF.
- The text printed after login has no known end, so it is read until the line has
  been quiet for 0.5 s.
- The reply format of `getcser`. (`ver` was seen over USB.)
- The filter list is the ANM200 one.
- What the controller does on a wrong password.

## Left out on purpose

Stepping (`setf`, `getf`, `setv`, `getv`, `stepu`, `stepd`, `stepw`), the
AC/DC-IN switches (`setaci`, `getaci`, `setdci`, `getdci`), the pulse-count
commands (`setpu`, `setpd`, `getpu`, `getpd`), the trigger commands, `setfc`,
`getser`, `help` and the Lua console on port 7231. Stepping moves positioners
under load and needs a design of its own. The stepping modes `stp`, `stp+` and
`stp-` can be selected, but nothing drives steps.

## License

LGPL-3.0-or-later.
