Classes to describe interacting in a physical world. The intent is to provide a means to smoothly cause changes, avoiding large, immediate movements that can over-stress the physical systems, as well as allowing for bounds-checking and interrupts during execution.
- A
Movement
describes some physical change that is desired- A "stop check" function can be supplied to also execute code as a limiter (or call-back)
- A special case is provided for "just run some code" without requiring a physical component
- An
Actuator<Movement>
is the controller for a thing that does a type ofMovement
Rotator
for moving things in arcs (RotationMovement
)LinearActuator
for pushme-pullyou operations (LinearMovement
)
- An
Action
is a set ofActuator
/Movement
pairs to be performed as a single unit, until allMovement
s are complete- note that only one
Movement
perActuator
is allowed: multiple definitions will over-write one another - the exception are
execution
blocks, which are treated independently
- note that only one
- An
ActionSequence
is a basic list ofActions
to be done sequentially
The sequences and actions are contained within a type-safe DSL. Actions and movements are rebuilt when retrieved from a sequence: this allows altering external variables that would influence subseqeuent re-invocations of that same sequence.
Actuators have a small set of operators that are supported:
+=
and-+
for relative changes%
on aLinearActuator
for positioning
Each Actuator
type may also contain specific infix
capable functions for more DSL-like behavior. Note that these functions are "direct drive" and should immediately affect the device.
Fairly self-descriptive, a Rotator
has a "turning" component. All instances of this type have a RotationMovement
defined in terms of angles of degrees.1
A gear-ratio determines how much an angular change of the motor translates to the physical change in the system. Motors may also have restrictions on their spindle movements (e.g. servos can only move 180 degrees).
This Rotator
uses stepper motors to move to a position by keeping track of "steps from zero". Note only that motors that will "single-step" can be used here.
- the number of steps per rotation is translated to steps per degree
- positioning is not very precise due to rounding errors
- "zero" position is entirely arbitrary and is assumed to be pre-calibrated
- there are no angular limits imposed, so over-rotation is a possibility
A basic interface that defines a rotator with a physical limit. This is usually applied to servo motors with limited rotation spans. This class also defines some extension functions to directly create ServoRotator
objects from ServoDevice
s.
Models the attachment to a non-continuous servo. The physical movement is "mapped" to the servo's angular displacement. Accuracy is determined by the gear-ratio: sufficiently large ratios can cause physical angles to be mapped to the same servo angle, resutling in the servo not moving between them
- mapping is calcuated on object creation and cannot be changed
- overly large servo deltas may cause the servo to ignore smaller movements
- the current position is the closest approximation from the mapping table
A LinearMovement
causes a LinearActuator
to move x
percentage of the physical movement: this is mapped to 0->100
(fully retracted to fully extended),
Only a single actuator is currently defined:
ServoLinearActuator
which maps the0->100
range to servo angles (e.g. gear-driven slider or piston)
- ExecutionMovement is a "pseudo actuator and movement" that does not require a physical component, only executes the given code block as the stop check.
The SequenceExecutor provides one means of executing sequences and actions.
This class provides functions to execute sequences in a background thread. The actions are executed sequentially, invoking the stopCheck functions prior to moving each component, as well as providing a mans of signalling an immediate stop. The actions are executed in a way to provide pauses between invocations: this allows the physical systems to move incrementally, reducing stress (this speed can obviously be modified). The actual spped a step can execute will be limited by the hardware I/O.
Implementations of this class MUST handle any device or I/O contention -- this class does not provide any "locking" of devices.
lateinit var rotatorOne:Rotator
lateinit var rotatorTwo:Rotator
lateinit var pusher:LinearActuator
val exampleSequence = sequence {
var execDone = false
// defines a set of movement to be performed as a unit
// the action is finished when all actuators are "complete"
action {
// move rotatorOne to 90 degrees or until the check returns `true`
rotatorOne rotate {
angle = 90
stopCheck = { someExternalBooleanCheck() }
}
// move 5 degrees
rotatorTwo rotate 5
// linear works the same way = 50% "extended"
pusher extend {
distance = 50
stopCheck = { anotherCheck() }
}
}
// another action - executed after the previous
action {
// rotates until the stop condition or the rotator's "limits" are reached
rotatorOne backwardUntil { execDone }
rotatorTwo forwardUntil {
val foo = bar()
foo > 3000
}
pusher goTo 66
// RUN CODE!
execution {
if (!execDone) execDone = someProcess()
execDone
}
}
// add an externally defined action (builder)
this + externallyDefinedAction
// concatenate sequences
this += concatenatedSequences
}
1Need to accommodate continuous rotation servos and "chopper" steppers - e.g. conditions where "angle" won't work.