diff --git a/README.md b/README.md new file mode 100644 index 0000000..9ae06d9 --- /dev/null +++ b/README.md @@ -0,0 +1,160 @@ +Load Cycle Test Jig +=================== +![Test jig overview](img/test-jig-front.jpg) + +This is the control software for a machine that runs repeated rotational load +cycles on (3d-printed) mechanical parts, until they fail. I was originally +motivated to build this to test ISO 5211 valve adapters (related to [ISO 5211 +Adapter for PVC Ball Valve][iso-5211-pvc]). But it can be used to test any +mechanical joint. + +You can use this codebase as an example for the +[`profirust`](https://github.com/rahix/profirust) PROFIBUS DP master stack +running on a Raspberry Pi. + +[iso-5211-pvc]: https://www.printables.com/model/605515-iso-5211-adapter-for-pvc-ball-valve + +## How it works +A pneumatic vane cylinder twists the part back and forth at a torque set by +the pressure regulator. The software counts each reversal and stops the run +as soon as one of the two end-stop sensors trips, which means the part has +given way and the cylinder is free to rotate past its normal travel. + +#### Main hardware components +- pneumatic vane cylinder (FESTO [DSRL-40-180P-FW][festo-30658]) + * 5/3-way solenoid valve to control the cylinder + * two inductive end-stop sensors on the cylinder (detect part failure) +- filter-regulator maintenance unit (regulator controls the maximum torque) + * pressure switch (detect low air pressure) +- stack light (white, blue, orange) - see [Stack Lights][stack-light-post] on my blog +- HD44780 LCD (20×4 characters) as the operator display +- WAGO [750-303][wago-750-303] PROFIBUS fieldbus coupler for I/O signals +- Raspberry Pi as the PROFIBUS master, with a MAX485 transceiver (See + [Running RS-485 with a MAX485 on a Raspberry Pi](#running-rs-485-with-a-max485-on-a-raspberry-pi) + below) + +[festo-30658]: https://www.festo.com/de/en/a/30658/ +[stack-light-post]: https://blog.rahix.de/stack-lights/ +[wago-750-303]: https://www.wago.com/de-en/io-systems/fieldbus-coupler-profibus-dp/p/750-303 + +![Control side with WAGO stack, stack light, FRL and solenoid valve](img/test-jig-controls.jpg) + +## Operating modes +There are two switches which control the machine: +- Mode selector (continuous or single) +- Start/stop button + +The modes do the following: + +- **Continuous**: The cylinder alternates left and right every 5 seconds, the + counter increments on each reversal, and the run ends when a limit switch + trips. This is the standard "how many cycles until it breaks" test. +- **Single**: One short preparation move, then a timed swing toward the opposite + end stop. This is used to measure time to failure for a single event. + +Once failure occurs, the buzzer on the stack light pulses to let you know it's done. + +The LCD shows the current state together with either the cycle counter +(continuous mode) or the elapsed cycle time (single mode). + +![LCD readout during a run](img/test-jig-display.jpg) + +## Software architecture +This is a pattern that I find to work well for control system software on +hosted systems (the Linux on the Raspberry Pi in this case). It is not +particularly efficient, but very simple and robust. + +There are three threads: + +- The main thread runs the 20 ms control loop that computes the control system + logic (`Logic::run()`). Before and after, it copies I/O data to and from the + fieldbus process image and display. + +- A background thread runs the PROFIBUS DP master and the cyclic data exchange + with the WAGO coupler ([`fieldbus.rs`]). The cycle time is adjusted + to be optimal for the selected bus speed. + +- A third thread drives the HD44780 LCD over I2C ([`display.rs`]). It is woken + from a condvar whenever a line changes. + +For any further I/O channels, you'd add more threads. Data is shared through +mutexes which are only locked briefly to read or update data. This is very +important to ensure no thread is ever blocked for long periods of time. + +You can find another example of this pattern in the +[crab-control-center](https://github.com/muccc-rs/crab-control-center) code. + +#### Source layout +- [`main.rs`] runs the control loop and does the data plumbing. +- [`logic.rs`] contains the actual control logic: machine mode state machine, + cylinder sequencing, status reporting. +- [`fieldbus.rs`] contains the PROFIBUS communication, and peripheral configuration. +- [`display.rs`] is the HD44780 over I2C driver thread. +- [`util.rs`] contains small helpers that mirror the ones found in industrial PLC + programming (e.g. `TimerOn`, `TimerOff`, `PulseTimer`). + +## PROFIBUS +The fieldbus module ([`fieldbus.rs`]) contains everything related to PROFIBUS +communication: +- Setup a DP peripheral with `profirust` using the Linux RS-485 PHY implementation +- Peripheral parameters from a vendor GSD file (this was autogenerated with profirust's [`gsdtool`](https://github.com/rahix/profirust/tree/main/gsdtool)) +- Exposing the process image to the rest of the application via Mutex + +#### Running RS-485 with a MAX485 on a Raspberry Pi +PROFIBUS uses an 11-bit character frame with even parity. The Pi's default +"mini UART" (`/dev/ttyS0`) does not accept `PARENB` (=even parity bit) and is +therefore not usable. The proper PL011 UART has to be enabled instead, and the +MAX485's DE/RE driver-enable line has to be tied to the UART's RTS pin so the +kernel can switch the transceiver in step with each frame. + +Switch the primary UART to the PL011 by adding the following to +`/boot/firmware/config.txt` and disabling the Bluetooth HCI service: + +``` +dtoverlay=disable-bt +``` + +```bash +sudo systemctl disable --now hciuart +``` + +After a reboot the PL011 is available as `/dev/ttyAMA0`, which is the device +the code opens in [`fieldbus.rs`]. + +Hardware flow control on the primary UART is not exposed by the stock +overlays, so a small device tree overlay is needed that routes RTS (and +optionally CTS) to a GPIO. + +This overlay source can be used as is: + +Compile and install the overlay with: + +```bash +dtc -@ -Hepapr -I dts -O dtb -o uart0-ctsrts.dtbo uart-ctsrts.dts +sudo cp uart0-ctsrts.dtbo /boot/firmware/overlays/ +``` + +Then append the following line to `/boot/firmware/config.txt` and reboot: + +``` +dtoverlay=uart0-ctsrts +``` + +Wire the MAX485 so that +- DI to Pi's TXD (GPIO 14) +- RO to Pi's RXD (GPIO 15) +- combined DE and RE pins to the RTS GPIO chosen in the overlay (GPIO 17) + +Add the usual 120 ohm termination at both physical ends of the bus. + +## References +- [`profirust`](https://github.com/rahix/profirust) + * [Blog post about `profirust`](https://blog.rahix.de/profirust/) + * [Blog post generally explaining PROFIBUS](https://blog.rahix.de/profibus-primer/) +- [`hd44780-driver`](https://github.com/JohnDoneth/hd44780-driver) LCD display driver + +[`main.rs`]: ./src/main.rs +[`logic.rs`]: ./src/logic.rs +[`fieldbus.rs`]: ./src/fieldbus.rs +[`display.rs`]: ./src/display.rs +[`util.rs`]: ./src/util.rs diff --git a/img/test-jig-controls.jpg b/img/test-jig-controls.jpg new file mode 100644 index 0000000..73bde3e Binary files /dev/null and b/img/test-jig-controls.jpg differ diff --git a/img/test-jig-display.jpg b/img/test-jig-display.jpg new file mode 100644 index 0000000..ba259ae Binary files /dev/null and b/img/test-jig-display.jpg differ diff --git a/img/test-jig-front.jpg b/img/test-jig-front.jpg new file mode 100644 index 0000000..a39099f Binary files /dev/null and b/img/test-jig-front.jpg differ