Skip to content

About

Simulated ISOBUS implements for developing task controllers and virtual terminals (AgIsoStack++, SocketCAN)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

36 Commits

Folders and files

Repository files navigation

isobus-implement-sim

Simulated ISOBUS implements (sprayers, seeders, planters, spreaders) for developing task controllers and virtual terminals without owning the machines. Built on AgIsoStack++, on Linux SocketCAN.

Each implement comes from a profile file (booms, sections, rates, screens), is driven by commands, reports what the system under test did as events, and can misbehave on demand: drop off the bus, restart, upload a new pool, answer late.

Status: v0.1.0, phases 0 to 5, 7 and 8 of docs/PLAN.md, with phase 6 (capture and replay) still to do: a task controller client and a terminal client built from a profile, driven by commands, with rates, totals, faults on demand and auxiliary functions. The DDOP comes from the profile's booms, sections and products; sections follow the task controller's setpoints after the profile's delay; the profile's pool goes to a terminal, with the stack's seeder screen behind it for now; commands arrive on stdin or a TCP port and events go out as JSON lines; the implement can go silent, answer late, restart, re-upload its pool or a bad DDOP, and claim a held address. The machines are described in docs/MODEL.md, docs/SEEDER.md, docs/SPRAYER.md and docs/SPREADER.md; the shipped profiles are in profiles/, the pools in pools/ (the spreader's screens are our own, built from PoolEdit XML: pools/README.md).

Run

build/implement --profile profiles/sprayer-24.json --interface vcan0

Options: --driver virtual for the stack's in-process bus, --driver peak --interface 1 for a PEAK PCAN-USB on macOS (the stack's MacCAN driver; the first channel is 1), --driver aowlink --interface <host[:port]> for the bus through an AOW link gateway over the network (SharpIsoTerm's ESP32 gateway or aow-linkd, src/aow_link_driver.hpp; one control client per gateway, so two programs need two gateways or a gateway for one and a CAN interface for the other), every tool takes it too, --port 0 (or a number) to take commands on a local TCP port as well as stdin, --pool <file.iop> to show another pool than the profile's (one extracted from a capture, or pools/aux_functions.iop), --section-control setpoint|actualSettable|perElement to override the profile's section control method, --log debug|info|warn|error for the stack's log on stderr, --trace to print every CAN frame in and out on stderr (candump style, through the fault driver). Events are one JSON object a line on stdout and to every TCP client, for example:

{"t":622,"event":"address","address":128}
{"t":9120,"event":"tc","connected":true,"booms":1,"sections":64,"version":3,"address":247}
{"t":9850,"event":"set","element":2,"ddi":290,"value":1365,"boom":0,"what":"sections","chunk":0}
{"t":10150,"event":"sections","boom":0,"setpoint":"101010101010","commanded":"101010101010","actual":"101010101010"}

Commands are one a line, answered with a command event: switch <section> on|off, master on|off [boom], auto on|off [boom], rate <value> [product], bin <level> [product] (tank on a sprayer), fill [product], depth <mm>, speed <km/h> or speed bus, fault row|nozzle <section> blocked|clear, alarm <name> or alarm clear, key <object>, mask <id>, value <object> <n>, status, help, quit; and the faults of PLAN.md section 7: fault silent <s>, fault slow <ms>, fault restart, fault version <label>, fault bigpool <kB>, fault ddop bad, fault conflict [address], fault busoff [frames]. Try it by hand:

build/implement --profile profiles/sprayer-24.json --driver virtual
speed 12
switch 3 off
status

build/can_sniff [--driver peak|socketcan|virtual] [--interface 1|can0] [--seconds 10] [--probe] is candump for the stack's drivers, for a Mac with a PEAK adapter: every frame received or sent, with PGN, source and destination and the names of the PGNs an implement meets, and a count line every second. --probe sends a request for address claim to every node after the first second, so a node on the bus has to show itself. The MacCAN driver reports no bus state, so a silent bus looks the same whether the frames were acknowledged or not; a sniffer on the other end settles that.

build/ddop_check <file.ddop> parses a binary DDOP, such as one a task controller saved, and prints its element tree and any broken child references. build/vt_stub --interface vcan0 is a headless virtual terminal for the scenarios: it takes the implement's pool and injects key presses and values from stdin, and AUX-N assignments (assign <function id> <input id>), which the stack's server cannot make itself. build/tc_stub --interface vcan0 is a headless task controller that takes any DDOP, sends set-value, request and measurement commands from stdin, and prints every value the implement reports. build/aux_input --interface vcan0 is a joystick with a button and a slider for AUX-N, driven from stdin (with --pool pools/joystick.iop, two axes and five buttons: axis x|y <0..64255>, button a|b|c|d|ok on|off); on Linux, --joystick /dev/i2c-1 drives it from a real stick too, the I2C joystick module at 0x5A (one stick, five buttons) on a Raspberry Pi's I2C pins: the X axis is the slider, button A the button, or with the joystick pool every axis and button. Where no I2C bus is free, the module hangs off an ESP32: --joystick-serial <port> with tools/i2c_bridge or the ESP32 AOW link gateway on USB, or --joystick-tcp <gateway> over the network to the gateway.

Releases

A tag v* builds release tarballs for Linux x64 and arm64 (.github/workflows/release.yml): the binaries, the profiles, the pools, the scenario harness and the documents, with a RELEASE.md that says how to start. ./package.sh build v0.1.0 makes the same tarball from a local build.

Tests

ctest --test-dir build runs the model and DDOP tests without a bus. tests/scenario_commands.py build/implement drives one implement over its TCP port on the virtual driver, on any platform. On Linux with vcan0, tests/scenario_tc.py runs every shipped profile against a headless AOG-TaskController and checks that sections follow with the profile's delay and that the operator's commands override it; tests/scenario_vt.py runs the screens against vt_stub; tests/scenario_rates.py drives rates and totals through tc_stub; tests/scenario_faults.py runs every fault against AOG-TaskController and vt_stub; tests/harness.py is the library the scenarios share.

Build

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release   # fetches AgIsoStack++
cmake --build build

Linux builds the stack with SocketCAN and the virtual driver; macOS with the virtual driver and the stack's MacCAN PCAN driver, so a PEAK PCAN-USB plugged into the Mac works with --driver peak (the MacCAN library has UV Software's EULA, so it stays a local build and is not in the release tarballs). OrbStack's Linux kernel has no peak_usb, only gs_usb, so a PEAK adapter passed through to a machine there gets no can0; a candleLight-class adapter would. The fetched stack carries one patch, cmake/agisostack-aux-maintenance.patch: its VT server takes an auxiliary input unit's maintenance message before the unit has connected instead of NACKing it, which since the stack's #655 kept every input unit from connecting (PLAN.md, AUX-N after #655). The restart races of PLAN.md's phase 4 record are fixed upstream (AgIsoStack++ PR #798, in the pin). To see the seeder example claim an address on a virtual bus (what CI checks):

sudo modprobe vcan && sudo ip link add vcan0 type vcan && sudo ip link set vcan0 up
tests/phase0_vcan.sh build/seeder_example/SeederExample vcan0

Not ISO 11783 certified: a test tool, not a machine.

Licence

MIT. See LICENSE.

About

Simulated ISOBUS implements for developing task controllers and virtual terminals (AgIsoStack++, SocketCAN)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages