Import LinuxCNC source tree
This commit is contained in:
279
configs/sim/axis/mtconnect/README.md
Normal file
279
configs/sim/axis/mtconnect/README.md
Normal file
@@ -0,0 +1,279 @@
|
||||
# MTConnect agent for LinuxCNC — demo config
|
||||
|
||||
First-class MTConnect support for LinuxCNC: a userspace, non-realtime agent that
|
||||
exposes machine **status**, a rich **kinematic description**, and **tool data**
|
||||
over MTConnect. It ships an embedded HTTP agent (no external dependency) and can
|
||||
optionally publish over the standard MTConnect **MQTT** binding. The `/probe`
|
||||
response carries enough kinematic detail for an external tool (e.g. a FreeCAD
|
||||
Path plugin) to auto-configure a machine.
|
||||
|
||||
This directory is a demo sim config. The agent itself installs with LinuxCNC
|
||||
(`bin/mtconnect-agent`, package `lib/python/mtc`, assets under
|
||||
`share/linuxcnc/mtconnect`). For the full reference see the `mtconnect-agent(1)`
|
||||
man page and the `[MTCONNECT]` section of the INI configuration chapter.
|
||||
|
||||
## Quick start
|
||||
|
||||
```sh
|
||||
# From this directory:
|
||||
linuxcnc example.ini # launches the sim + the MTConnect agent
|
||||
|
||||
# In another terminal:
|
||||
curl http://localhost:5000/probe # MTConnectDevices (structure + kinematics)
|
||||
curl http://localhost:5000/current # latest value of every DataItem
|
||||
curl http://localhost:5000/sample?from=1&count=100
|
||||
curl http://localhost:5000/assets # CuttingTool assets (tool table)
|
||||
```
|
||||
|
||||
You can inspect the generated device model without launching LinuxCNC (after
|
||||
sourcing `scripts/rip-environment` in a RIP build, or with LinuxCNC installed):
|
||||
|
||||
```sh
|
||||
mtconnect-agent --dump-probe example.ini
|
||||
mtconnect-agent --dump-probe ../vismach/5axis/table-rotary-tilting/xyzac-trt.ini
|
||||
```
|
||||
|
||||
## Enabling it in your own config
|
||||
|
||||
Add a few lines to your INI. The device model is generated automatically from
|
||||
`[TRAJ]`, `[KINS]`, `[AXIS_*]` and `[JOINT_*]`.
|
||||
|
||||
```ini
|
||||
[MTCONNECT]
|
||||
ENABLE = 1
|
||||
DEVICE_NAME = my_mill
|
||||
UUID = linuxcnc-my-mill-0001
|
||||
HTTP_PORT = 5000
|
||||
# HTTP_BIND defaults to 127.0.0.1 (loopback); set 0.0.0.0 to expose on the LAN.
|
||||
# HTTP_BIND = 127.0.0.1
|
||||
# TRANSPORT: comma list of http, mqtt, shdr (no inline comments in INI values)
|
||||
TRANSPORT = http
|
||||
SAMPLE_HZ = 10
|
||||
# MQTT_BROKER = localhost
|
||||
# MQTT_PORT = 1883
|
||||
# MQTT_PREFIX = MTConnect
|
||||
```
|
||||
|
||||
Load the agent from a HAL file (see `mtconnect.hal`):
|
||||
|
||||
```
|
||||
loadusr -W mtconnect-agent
|
||||
```
|
||||
|
||||
`-W` waits until the component is ready; the INI comes from `$INI_FILE_NAME`.
|
||||
Loading it in the HAL file (rather than `[APPLICATIONS]`) makes the status pins
|
||||
(`active`, `connected`) available for linking.
|
||||
|
||||
## What is exposed
|
||||
|
||||
| Endpoint | Content |
|
||||
|------------|---------|
|
||||
| `/probe` | Device structure: Controller/Path, Axes (Linear/Rotary + Motion), spindle, and the `x:Kinematics` extension |
|
||||
| `/current` | Latest value of every DataItem (execution, mode, positions, spindle, feed, tool) |
|
||||
| `/sample` | Sequence-numbered observation history (`?from=&count=`) |
|
||||
| `/assets` | Tool table as `CuttingTool` assets (location, diameter, length offsets) |
|
||||
|
||||
### LinuxCNC → MTConnect mapping (`linuxcnc.stat()`)
|
||||
|
||||
| MTConnect DataItem | Source |
|
||||
|---|---|
|
||||
| `EMERGENCY_STOP` | `task_state` |
|
||||
| `CONTROLLER_MODE` | `task_mode` |
|
||||
| `EXECUTION` | `interp_state`, `task_paused` |
|
||||
| `PROGRAM`, `LINE_NUMBER` | `file`, `motion_line` (executing line, not interp read-ahead) |
|
||||
| `PATH_FEEDRATE` (+ OVERRIDE) | `current_vel`, `feedrate` |
|
||||
| `POSITION` / `ANGLE` (ACTUAL/COMMANDED) | `actual_position`, `position` |
|
||||
| `ROTARY_VELOCITY`, `ROTARY_MODE`, `DIRECTION` | `spindle[0]` |
|
||||
| `TOOL_NUMBER`, `TOOL_ASSET_ID` | `tool_in_spindle` |
|
||||
| `ASSET_CHANGED` | tool change detection |
|
||||
| `CuttingTool` assets | `tool_table` |
|
||||
|
||||
## The kinematic description (`x:Kinematics`)
|
||||
|
||||
Standard MTConnect models axes as `Linear`/`Rotary` components with `Motion`
|
||||
elements (`PRISMATIC`/`REVOLUTE`, direction vector). LinuxCNC specifics that do
|
||||
not map cleanly are carried in a versioned extension namespace
|
||||
`urn:linuxcnc:mtconnect:1` — the primary contract for auto-configuration:
|
||||
|
||||
```xml
|
||||
<x:Kinematics module="xyzac-trt-kins" coordinates="XYZAC" joints="5"
|
||||
params="sparm=identityfirst">
|
||||
<x:JointMap>
|
||||
<x:Joint number="0" kind="LINEAR" axis="X" min="-200" max="200" home="0"/>
|
||||
<x:Joint number="3" kind="ANGULAR" axis="A" min="-100" max="50" home="0"/>
|
||||
<x:Joint number="4" kind="ANGULAR" axis="C" min="-36000" max="36000" home="0"/>
|
||||
</x:JointMap>
|
||||
<x:Axis name="X" kind="LINEAR" vector="1 0 0" min="-200" max="200"/>
|
||||
<x:Axis name="A" kind="ANGULAR" vector="1 0 0" min="-100" max="50"/>
|
||||
<x:Axis name="C" kind="ANGULAR" vector="0 0 1" min="-36000" max="36000"/>
|
||||
</x:Kinematics>
|
||||
```
|
||||
|
||||
A FreeCAD plugin reads the standard `Axes`/`Motion` tree, or the compact
|
||||
`x:Kinematics` block, to create/configure a machine: axis list and type,
|
||||
travel limits, home positions, kinematics module/type, and the joint↔axis map.
|
||||
|
||||
## Solid models (geometry)
|
||||
|
||||
A standard MTConnect twin viewer (e.g. the one at demo.mtconnect.org, or
|
||||
TrakHound) renders a machine from `/probe` alone: geometry is **referenced, never
|
||||
streamed**. The device model carries `<SolidModel href="...">` elements pointing
|
||||
to external mesh files, plus `<CoordinateSystems>` and a `<Motion>` chain; the
|
||||
viewer fetches each mesh once (from the agent's `/models/<name>`) and animates it
|
||||
using the streamed positions. LinuxCNC bundles no viewer and no JavaScript — this
|
||||
is plain, standards-compliant MTConnect.
|
||||
|
||||
### Zero-config geometry (`MODEL_AUTO`)
|
||||
|
||||
```ini
|
||||
[MTCONNECT]
|
||||
MODEL_AUTO = 1
|
||||
```
|
||||
|
||||
The agent generates simple placeholder **box** meshes for the base and each axis
|
||||
straight from the travel limits and serves them from memory — any machine gets a
|
||||
functional twin with **no mesh files**. This is what the example config uses.
|
||||
|
||||
### Real geometry (per-link meshes)
|
||||
|
||||
Supply your own meshes (STL / OBJ / glTF) for fidelity:
|
||||
|
||||
```ini
|
||||
[MTCONNECT]
|
||||
MODEL_DIR = models ; base dir for relative paths (default: INI dir)
|
||||
MODEL_BASE = frame.stl ; static frame / column (device-level SolidModel)
|
||||
MODEL_X = x_table.stl ; link that moves with X
|
||||
MODEL_Y = y_saddle.stl
|
||||
MODEL_Z = spindle.stl
|
||||
MODEL_SPINDLE = spindle.stl
|
||||
```
|
||||
|
||||
Author each mesh in **millimetres** (MTConnect's canonical unit — the SolidModel
|
||||
element carries no per-mesh unit) in the machine frame at the all-axes-zero pose.
|
||||
An explicit
|
||||
`MODEL_<axis>` overrides the generated box for that link, so files and
|
||||
`MODEL_AUTO` can be mixed.
|
||||
|
||||
### Topology and direction (both modes)
|
||||
|
||||
These describe the mechanics and are **not** derivable from a trivkins INI:
|
||||
|
||||
```ini
|
||||
MODEL_CHAIN = Y X Z ; nesting order of the moving links (base -> tip)
|
||||
MODEL_PARENT_Z = BASE ; branch: Z (quill/tool) hangs off the base, not X/Y
|
||||
MODEL_INVERT = X Y ; work-carrying links move opposite the reported coord
|
||||
```
|
||||
|
||||
The agent then serves each mesh at `GET /models/<name>`, emits a device-level
|
||||
`<SolidModel>` for the base and a per-axis `<SolidModel>` in each axis's
|
||||
`<Configuration>`, and emits `<CoordinateSystems>` (WORLD → MACHINE) plus a
|
||||
`<Motion>` chain (`parentIdRef`) so the twin nests transforms correctly.
|
||||
|
||||
### Viewing the twin
|
||||
|
||||
The agent serves the geometry but **bundles no viewer** — rendering is left to a
|
||||
standard MTConnect client, so no third-party JavaScript lives in LinuxCNC. Two
|
||||
paths:
|
||||
|
||||
- **A standard MTConnect twin viewer (recommended).** Point one at the agent and
|
||||
it renders the machine from `/probe` + `/models/` with zero extra setup: the
|
||||
demo viewer at <https://demo.mtconnect.org>, TrakHound, or cppagent's demo
|
||||
twin. Expose the agent first with `[MTCONNECT]HTTP_BIND = 0.0.0.0` (it defaults
|
||||
to loopback only) and give the viewer `http://<machine>:5000`.
|
||||
|
||||
- **Self-host a small viewer.** An earlier revision of this config shipped a
|
||||
~12 KB three.js viewer (`twin.html`) that was removed from the tree to keep
|
||||
third-party JS out of core. It still works against this agent — it fetches
|
||||
`/probe` and `/current` and loads the `/models/` meshes. To run it yourself,
|
||||
recover it from git history
|
||||
(`git show <commit>:share/linuxcnc/mtconnect/twin.html`), repoint its three.js
|
||||
import map at a CDN or a local `libjs-three`, and serve it same-origin as the
|
||||
agent (e.g. behind a small reverse proxy, since the relative `fetch` calls
|
||||
assume one origin).
|
||||
|
||||
## Using the official cppagent instead of the embedded agent
|
||||
|
||||
Put `shdr` in `TRANSPORT` and the agent acts as an SHDR adapter (default port
|
||||
7878), streaming `<ts>|id|value` lines to an external cppagent. Configure that
|
||||
cppagent with a `Devices.xml`, which the generated `/probe` document doubles as:
|
||||
|
||||
```sh
|
||||
mtconnect-agent --dump-probe example.ini > Devices.xml
|
||||
```
|
||||
|
||||
The `dataItemId`s in the SHDR stream match the ids in that `Devices.xml`.
|
||||
|
||||
## MQTT
|
||||
|
||||
With `mqtt` in `TRANSPORT` and `python3-paho-mqtt` installed, the agent publishes
|
||||
the standard (vendor-neutral) MTConnect MQTT topics:
|
||||
`<prefix>/Probe/<uuid>` (retained), `<prefix>/Current/<uuid>`,
|
||||
`<prefix>/Sample/<uuid>`, `<prefix>/Asset/<uuid>/<assetId>`. A consumer discovers
|
||||
the whole device from the retained Probe topic.
|
||||
|
||||
**Home Assistant** is not part of the core agent (its MQTT Discovery format is
|
||||
HA-specific). An optional bridge, `contrib/mtconnect-ha-bridge`, reuses the
|
||||
device model to publish HA discovery; configure it with arguments so no HA key
|
||||
touches the machine INI:
|
||||
|
||||
```
|
||||
loadusr -W mtconnect-ha-bridge --broker=[HA]BROKER --username=[HA]USER --password=[HA]PASSWORD
|
||||
```
|
||||
|
||||
## Layout (installed)
|
||||
|
||||
```
|
||||
src/hal/user_comps/mtconnect-agent.py entry point -> bin/mtconnect-agent
|
||||
lib/python/mtc/ the agent package:
|
||||
ini_reader.py INI access (linuxcnc.ini, with offline fallback)
|
||||
kinematics.py build the kinematic model from the INI
|
||||
observations.py shared DataItem registry (keeps probe and streams in sync)
|
||||
device_model.py /probe MTConnectDevices document (+ CLI --dump-probe)
|
||||
lcnc_source.py live status + tool table from linuxcnc.stat()
|
||||
models.py solid-model config + served mesh registry (SolidModel geometry)
|
||||
streams.py /current, /sample buffer + XML; /assets XML
|
||||
agent.py transport-agnostic agent core (document builders)
|
||||
http_agent.py embedded HTTP server
|
||||
mqtt_agent.py optional MQTT publisher (vendor-neutral MTConnect binding)
|
||||
share/linuxcnc/mtconnect/mtconnect-linuxcnc-1.xsd extension schema
|
||||
configs/sim/axis/mtconnect/ this demo config + tests
|
||||
contrib/mtconnect-ha-bridge opt-in Home Assistant MQTT-discovery bridge
|
||||
contrib/ha.py HA discovery helper (used by the bridge)
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
```sh
|
||||
. scripts/rip-environment # so mtc is importable and bin/ is on PATH
|
||||
python3 test_mtc.py # offline suite (no running LinuxCNC required)
|
||||
python3 validate_schemas.py # validate the documents against the MTConnect XSDs
|
||||
# (needs the 'xmlschema' package)
|
||||
```
|
||||
|
||||
`test_mtc.py` covers kinematics mapping, probe↔registry consistency (3- and
|
||||
5-axis), the observation buffer + streams, assets, the live HTTP endpoints, and
|
||||
(when `xmlschema` is available) schema validation of all four documents.
|
||||
|
||||
## Custom HAL pins
|
||||
|
||||
Expose any HAL pin/signal as a data item with `HAL_ITEM` lines (read via
|
||||
`hal.get_value`, no HAL wiring):
|
||||
|
||||
```ini
|
||||
[MTCONNECT]
|
||||
HAL_ITEM = pin=spindle.0.load, id=spindle_load, type=LOAD, units=PERCENT, component=spindle
|
||||
HAL_ITEM = pin=hm2_5i25.temp, id=board_temp, type=TEMPERATURE, units=CELSIUS
|
||||
```
|
||||
|
||||
Standard MTConnect SAMPLE types only (LOAD, TEMPERATURE, PRESSURE, VOLTAGE,
|
||||
AMPERAGE, FREQUENCY, ANGLE, VELOCITY, TORQUE, …). `component=` hosts it under a
|
||||
generic `Sensor` (default) or an existing component (spindle/controller/path/an
|
||||
axis). Unsupported types are skipped with a warning. See `mtconnect-agent(1)`.
|
||||
|
||||
## Status
|
||||
|
||||
Complete and packaged for the build: the HTTP transport, HAL component and
|
||||
schema-valid documents; the vendor-neutral MQTT binding plus the optional
|
||||
Home Assistant bridge contrib; `SolidModel` geometry under `/models/` for any
|
||||
standard MTConnect twin viewer; and the SHDR adapter for an external cppagent.
|
||||
Realtime servo-rate data is explicitly out of scope.
|
||||
Reference in New Issue
Block a user