Skip to main content
StrokeEngine is a library for creating a variety of stroking motions with stepper or servo motors on an ESP32. You can use it with any DIY machine featuring a linear position drive powered by a stepper or servo motor.

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.
Understanding these concepts helps you get up and running with StrokeEngine faster.

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.
Coordinate system diagram showing the relationship between physicalTravel, keepoutBoundary, depth, and stroke parameters

StrokeEngine coordinate system showing physical travel, keepout boundaries, and stroke parameters

Key coordinate concepts:
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:

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)

Manual homing is dangerous. Calling thisIsHome() when not at the physical endstop causes an incorrect coordinate system, resulting in a crash that could damage your machine.
If your machine lacks a homing switch, you can use manual homing:
  1. Physically move the machine to the rear endstop
  2. Call Stroker.thisIsHome()
This enables the driver, sets the current position as -keepoutBoundary, and slowly moves to position 0.

Retrieve available patterns

Use getNumberOfPattern() and getPatternName() to enumerate available patterns:
patterns.cpp

Motion control

Start and stop motion

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:
Update the depth position with Stroker.setDepth(float) and read the current value with Stroker.getDepth().
Fancy Mode: Call Stroker.setupDepth(10.0, true) to adjust both depth and stroke interactively. The sensation slider maps to the interval [depth-stroke, depth]:
  • sensation = 100 — Adjusts depth position
  • sensation = -100 — Adjusts stroke position
  • sensation = 0 — Positions at stroke midpoint

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.
Read back the constrained values actually used by StrokeEngine:

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.