mcpositioner/CLAUDE.md
Ryan Malloy ce93070a04 Add README and CLAUDE.md
README covers installation, hardware setup, tools, prompts, and
cross-server integration with mcnanovna for 3D pattern measurement.
CLAUDE.md provides project guidance for Claude Code.
2026-02-03 09:10:36 -07:00

103 lines
4.2 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code when working with code in this repository.
## What This Is
mcpositioner is a FastMCP server that gives LLMs direct control of an ESP32 dual-axis antenna positioner over WiFi HTTP. It exposes 5 MCP tools and 3 guided workflow prompts for moving stepper motors, homing axes via StallGuard, and orchestrating 3D antenna radiation pattern measurement in coordination with a VNA MCP server (mcnanovna).
## Commands
```bash
# Run the server
uv run mcpositioner # from source
uvx mcpositioner # from installed package
python -m mcpositioner # module invocation
# Lint and format
ruff check src/
ruff format src/
# Install dependencies
uv sync
# Build/verify ESP32 firmware (requires PlatformIO)
cd firmware && pio run
# Add to Claude Code for testing
claude mcp add mcpositioner-local --scope project -- uv run --directory /home/rpm/claude/ham/nanovna/mcpositioner mcpositioner
```
There are no tests yet. The project has no README.
## Architecture
```
src/mcpositioner/
__init__.py Package docstring
__main__.py python -m mcpositioner
server.py FastMCP server -- tool registration, version banner, entry point
positioner.py Async HTTP client for the ESP32 (httpx)
tools.py 5 MCP tool methods on a simple PositionerTools class
prompts.py 3 guided workflow prompts (home, configure, measure_pattern_grid)
firmware/ PlatformIO ESP32 project for antenna positioner hardware
platformio.ini Build config: espressif32, AccelStepper, TMCStepper, ESPAsyncWebServer
include/config.h Pin assignments, motor constants, TMC2209 UART config
src/main.cpp Dual-axis stepper control, HTTP API, mDNS, StallGuard homing
hardware/ KiCad 9 schematic for positioner wiring
positioner.kicad_pro Project file (JSON)
positioner.kicad_sch Root schematic -- ESP32 + 2x TMC2209 + motors + power
positioner.kicad_sym Local symbol library (6 custom module symbols)
sym-lib-table Registers local symbol lib with project
generate_kicad.py Python generator for all KiCad files (dev tool)
```
### How tools get registered
`server.py` holds a flat list `_TOOL_METHODS` of method name strings. `create_server()` instantiates one `PositionerTools` object, iterates the list, and wraps each bound method with `FunctionTool.from_function()`. To add a new tool: add a public method to `tools.py` then add its name to `_TOOL_METHODS`.
### HTTP client (positioner.py)
The `Positioner` class wraps httpx async calls to the ESP32's HTTP API:
- `GET /status` -- theta/phi position, moving, homed
- `POST /move` -- absolute move to theta/phi
- `POST /move/relative` -- relative offset move
- `POST /home` -- StallGuard sensorless homing
- `POST /stop` -- emergency stop
- `GET /config` -- read motion parameters
- `POST /config` -- update speed, accel, microstepping
Default host: `positioner.local` (mDNS). Override with `MCPOSITIONER_HOST` env var.
### Cross-server orchestration
This server controls physical positioning only. For 3D antenna pattern measurement, the LLM orchestrates both mcpositioner and mcnanovna (VNA MCP server):
1. `positioner_move` (mcpositioner) -- position antenna at theta/phi
2. `scan` (mcnanovna) -- measure S21 transmission
3. Repeat across theta/phi grid
4. Assemble pattern dict from collected measurements
The `measure_pattern_grid` prompt provides step-by-step guidance for this workflow.
### ESP32 firmware (firmware/)
PlatformIO project targeting ESP32. Controls 2x NEMA 17 steppers via TMC2209 drivers in UART mode. Features:
- AccelStepper for smooth acceleration profiles
- TMCStepper for UART configuration and StallGuard sensorless homing
- ESPAsyncWebServer for the HTTP API
- mDNS advertisement as `positioner.local`
- Pin assignments and motor constants in `include/config.h`
## Key conventions
- Date-based versioning: `2026.02.02` in pyproject.toml
- Python 3.11+, ruff at 120-char line length
- `httpx` is a core dependency (not optional -- it IS the transport layer)
- Single `PositionerTools` instance per server lifetime
- No mixin pattern -- flat class with 5 methods (single-concern server)
- Custom exception: `PositionerError`
- Env var: `MCPOSITIONER_HOST` (default `positioner.local`)