FuckIO Example
Reference implementation using StrokeEngine
OSSM Project
Popular open-source implementation by Kinky Makers
Core concepts
StrokeEngine takes full advantage of servo and stepper driven machines over fixed cam-driven designs. Under the hood, it uses the FastAccelStepper library to interface with motors using standard STEP/DIR signals.Coordinate system
The machine uses an internal coordinate system that converts real-world metric units into encoder/stepper steps. This abstraction works with all machine sizes regardless of the motor you choose.StrokeEngine coordinate system showing physical travel, keepout boundaries, and stroke parameters
| Term | Description |
|---|---|
| physicalTravel | The real physical travel from one hard endstop to the other |
| keepoutBoundary | Safety distance subtracted from each side to prevent crashes |
| _travel | Working distance: physicalTravel - (2 * keepoutBoundary) |
| Home | Position at -keepoutBoundary (typically at the rear) |
| MIN = 0 | Zero position, keepoutBoundary away from home |
| Depth | The furthest point the machine extends (adjustable at runtime) |
| Stroke | The working distance of a stroking motion (adjustable at runtime) |
Think of Stroke as the amplitude and Depth as a linear offset added to it. The positive move direction is towards the front (towards the body).
Patterns
StrokeEngine uses a pattern generator to provide a wide variety of sensations. Patterns dynamically adjust parameters like speed, stroke, and depth on a motion-by-motion basis using trapezoidal motion profiles. Each pattern accepts four parameters:- depth — Maximum extension point
- stroke — Motion amplitude
- speed — Cycles per minute
- sensation — Arbitrary modifier for pattern behavior (-100 to 100)
See the Pattern documentation for detailed descriptions of available patterns and instructions for creating your own.
Graceful error handling
StrokeEngine handles invalid parameters gracefully without interrupting operation:- All setter functions use
constrain()to limit inputs to the machine’s physical capabilities - Values outside bounds are automatically cropped
- Pattern commands that exceed machine limits result in shortened strokes or adjusted ramps
- Motion completes over the full distance but may take slightly longer than expected
Mid-stroke parameter updates
You can update depth, stroke, speed, and pattern parameters mid-stroke for a responsive, fluid user experience. Built-in safeguards ensure the machine stays within bounds at all times.State machine
An internal finite state machine manages the machine states:| State | Description |
|---|---|
| UNDEFINED | Initial state before homing. Motor is disabled and position is unknown. |
| READY | Homing complete. Machine accepts motion commands. |
| PATTERN | Pattern generator is running cyclic motions. |
| SETUPDEPTH | Motor follows the depth position for interactive adjustment. |
Usage
StrokeEngine provides a simple yet powerful API. Specify all input parameters in real-world metric units.Initialize the library
1
Define pin configurations
Set up the pins for your motor driver and optional homing switch:
main.cpp
2
Configure motor properties
Calculate steps per millimeter based on your hardware:
main.cpp
3
Define machine geometry
Specify the physical dimensions of your machine:
main.cpp
4
Configure homing
Set up the endstop switch properties:
main.cpp
5
Initialize in setup()
Call the initialization functions and wait for homing to complete:
main.cpp
When
getState() returns READY, the machine is homed and ready for motion commands.Manual homing (no endstop switch)
If your machine lacks a homing switch, you can use manual homing:- Physically move the machine to the rear endstop
- Call
Stroker.thisIsHome()
-keepoutBoundary, and slowly moves to position 0.
Retrieve available patterns
UsegetNumberOfPattern() and getPatternName() to enumerate available patterns:
patterns.cpp
Motion control
Start and stop motion
| Function | Description |
|---|---|
Stroker.startPattern() | Start the pattern-based stroking motion |
Stroker.stopMotion() | Stop immediately with maximum deceleration |
Position commands
Move to either end of the machine for setup purposes:These functions can be called from
PATTERN or READY states and stop any current motion. They return false if called in an invalid state.Interactive depth setup
Enter depth setup mode where the motor follows the depth position in real-time:Stroker.setDepth(float) and read the current value with Stroker.getDepth().
Parameter functions
Update parameters at any time. Values are automatically constrained to machine limits:Set
applyNow to true to apply changes immediately mid-stroke. Otherwise, changes take effect after the current stroke completes.Advanced features
Telemetry callback
Register a callback to receive telemetry data for each trapezoidal move:Consult StrokeEngine.h in the source repository for the complete API reference, including overloaded functions and additional features.

