stepperMotor#
Stepper Motor#
Introduction#
The stepper motor module simulates the actuation of a stepper motor. Given the initial motor angle \(\theta_0\), a
fixed motor step angle \(\Delta\theta\), a fixed motor step time \(\Delta t\), and an input message containing
an integer number of steps commanded, the motor states are computed at each time step and output from the module.
The motor states include the scalar motor angle \(\theta\), scalar angle rate \(\dot{\theta}\), scalar angular
acceleration \(\ddot{\theta}\), the current motor step count \(c_s\) (within the active command, reset on each
new non-interrupting command), the absolute motor position \(p_s\) in steps (cumulative net signed step count,
never reset; motorPosition in the output payload, with motorPosition * stepAngle ≈ \(\theta\)), the number
of steps commanded to the motor \(n_s\), and a boolean isMotorMoving flag that is true while the motor is
actively actuating through a command and false when no actuation is in progress. The motor actuation through each
step of the command sequence is profiled using a bang-bang acceleration profile.
The module supports two types of incoming commands. A standard step command (stopMotorCommand = false) sets the
number of steps to actuate; if the motor is already moving, the new command interrupts the current actuation and the
motor finishes the current step before beginning to follow the new command. A stop command (stopMotorCommand =
true) halts the motor after the current step completes; because a stepper motor cannot stop actuating mid-step, the
motor reports isMotorMoving = true until the in-progress step finishes, then transitions to isMotorMoving =
false at a step-aligned angle.
Module Input/Output Messages#
The following table lists the module input and output messages.
Msg Variable Name |
Msg Type |
Description |
|---|---|---|
motorStepCommandInMsg |
Input message containing the number of commanded motor steps ( |
|
stepperMotorOutMsg |
Output message containing the stepper motor states |
Motor Step Actuation Profile#
The motor states are profiled identically for each step in the command sequence. Specifically, a bang-bang acceleration profile is used to profile the motor states as a function of time. Given the motor step time \(\Delta t\) and motor step angle \(\Delta \theta\) as fixed parameters, the module calculates the required acceleration \(\ddot{\theta}_{\text{max}}\) that must be applied during each motor step.
Note that the motor can take either positive or negative steps. For a forward actuation command (\(n_s > 0\)), the calculated acceleration is applied positively for the first half of the step and negatively during the second half of the step. For a backward actuation command (\(n_s < 0\)), the acceleration is applied negatively during the first half of the step and positively during the second half of the step.
Given the initial time \(t_0\), the switch time \(t_s\) where the acceleration is alternated and the final time \(t_f\) when the step is complete is determined as
The other motor states can be kinematically profiled as a function of time by integrating the applied acceleration profile. The equations used to profile each motor step are
Note that the parameters \(t_0, t_s\) and \(t_f\) must be continually updated after each step is complete to reflect the advancement of time. Doing so enables use of the above equations for each motor step. Specifically, \(t_0\) for the next step is anchored to the previous step’s \(t_f\) (rather than to the current sample time at which the step-complete event is detected). This preserves the long-run motor rate of \(1 / \Delta t\) when the module update period does not divide \(\Delta t\) evenly; otherwise the residual \((t - t_f)\) would be lost at each step boundary and the effective step rate would drop below \(1 / \Delta t\).
Important
If the motor actuation is interrupted by a new reference message while actuating through a step, the motor must finish actuating through the current step before it can begin following a new reference command. If the interrupting message is written when the motor is not in the midst of a step, the module resets the motor step count and immediately begins actuating to follow the new reference command.
Stop Command Handling#
When an input message arrives with stopMotorCommand = true, the module sets an internal pendingStop flag
instead of immediately resetting the actuation. The stop is then honored at the next step-boundary:
If the motor is mid-step when the stop arrives, the in-progress step runs to completion through the normal bang-bang profile. At the step boundary the module sets
actuationComplete = true, zeroes \(\dot\theta\) and \(\ddot\theta\), and reportsisMotorMoving = falseon the next tick.If the motor is between steps (
stepComplete = true) when the stop is honored, the module halts before starting the next step.If the motor is already idle (
actuationComplete = true) when the stop arrives, the stop is a no-op —pendingStopis not set.If a fresh non-stop command arrives before a pending stop is honored,
pendingStopis cleared and the new command is processed normally (interrupting the current actuation if applicable).
Because the stop halts at a step boundary, \(\theta\) lands on an integer multiple of \(\Delta\theta\) from the
origin, motorPosition remains consistent with \(\theta\) (motorPosition * stepAngle ≈ \(\theta\)), and
the algorithm consuming isMotorMoving sees the motor as settled only when it is physically at rest.
Module Functions#
Below is a list of functions that this simulation module performs
Reads the incoming motor step command message (
stepsCommandedandstopMotorCommand)Computes the motor states as a function of time using a bang-bang acceleration profile
Tracks the absolute motor position (
motorPosition) across commandsWrites the motor states to the module output message
Handles interruptions to motor actuation by resetting the motor actuation after the current step is complete
Honors stop commands by halting after the current step completes, preserving step-aligned \(\theta\) and consistent
motorPosition
Module Assumptions and Limitations#
The motor step angle and step time are fixed parameters (Cannot be negative)
The motor cannot stop actuating in the middle of a step
When the motor actuation is interrupted by a new reference command, the motor must complete its actuation through the current step before following the new command
Stop commands are likewise honored only at the next step boundary
The module update rate must be faster than or equal to the provided motor step time \(\Delta t\)
The module update rate cannot be slower than the motor step rate, or the motor actuation cannot be resolved
Test Description and Success Criteria#
The unit tests for this module live in simulation/dynamics/stepperMotor/_UnitTest/test_stepperMotor.py. The common
success criterion across all tests is that the motor states converge to independently computed reference values at
the end of each actuation sequence. Specifically, the motor angle, rate, acceleration, and step count are checked
to converge to the reference values at the end of each simulation chunk. The motor rate is zero at the completion of
each motor step, while the motor acceleration is nonzero at the instant of step completion and is therefore checked
one time step later, after the acceleration has been cleared.
test_stepper_motor_nominal configures two actuation command segments separated by a 5-second rest period, with a
trailing 5-second rest for plot clarity. The initial motor angle, motor step angle, step time, and steps commanded
for each actuation sequence are varied so that the motor actuates both forwards and backwards. A zero-step command
is also exercised to verify the module correctly handles a no-op command.
test_stepper_motor_interrupt verifies that the module correctly handles reference messages that interrupt an
unfinished motor actuation sequence. The first command is interrupted after half of its commanded steps have been
completed. The time the second command message is written is parameterized by an interruption factor specifying what
fraction of the next step has completed before the interrupt arrives. Interruption factors of 0 and 1 are included
to ensure the module correctly resets when the interrupt falls precisely on a step boundary. A 5-second trailing
rest is added for plot clarity.
test_stepper_motor_timestep_overshoot verifies the motor correctly completes actuation when the simulation
timestep does not divide evenly into the motor step time. In this scenario the simulation time overshoots the step
completion time \(t_f\). The test guards against a regression in which the leftover \((t - t_f)\) residual
was dropped at each step boundary, causing the motor to either never reach step-complete or to fall behind the
expected step rate of \(1 / \Delta t\).
test_stepper_motor_single_step verifies the motor correctly actuates for a single-step command in both forward
(stepsCommanded = +1) and backward (stepsCommanded = -1) directions — an edge case where the motor must
complete exactly one step and immediately come to rest.
test_stepper_motor_rapid_commands verifies the module’s behavior under multiple back-to-back command interrupts.
Three commands are sent in rapid succession, each interrupting the previous after only 2 steps have completed. The
test checks that the motor angle, rate, and step count converge to the expected values after the final command
completes.
-
class StepperMotor : public SysModel#
Stepper motor class.
Public Functions
-
StepperMotor() = default#
Constructor.
-
~StepperMotor() = default#
Destructor.
-
void reset(uint64_t currentSimNanos) override#
Reset member function.
Module reset method.
- Parameters:
callTime – [ns] Time the method is called
- Returns:
void
-
void updateState(uint64_t currentSimNanos) override#
Update member function.
Module update method. This method profiles the stepper motor actuation as a function of time. The motor states are then written to the output message.
- Parameters:
callTime – [ns] Time the method is called
- Returns:
void
-
double getThetaInit() const#
Getter method for the initial motor angle.
Getter method for the initial motor angle.
- Returns:
double
-
double getStepAngle() const#
Getter method for the motor step angle.
Getter method for the motor step angle.
- Returns:
double
-
double getStepTime() const#
Getter method for the motor step time.
Getter method for the motor step time.
- Returns:
double
-
double getThetaDDotMax() const#
Getter method for the maximum motor angular acceleration.
Getter method for the maximum motor angular acceleration.
- Returns:
double
-
void setThetaInit(const double thetaInit)#
Setter method for the initial motor angle.
Setter method for the initial motor angle.
- Parameters:
thetaInit – [rad] Initial motor angle
- Returns:
void
-
void setStepAngle(const double stepAngle)#
Setter method for the motor step angle.
Setter method for the motor step angle.
- Parameters:
stepAngle – [rad] Motor step angle
- Returns:
void
-
void setStepTime(const double stepTime)#
Setter method for the motor step time.
Setter method for the motor step time.
- Parameters:
stepTime – [s] Motor step time
- Returns:
void
Public Members
-
ReadFunctor<MotorStepCommandMsgPayload> motorStepCommandInMsg#
Input msg for the number of commanded motor step counts.
-
Message<StepperMotorMsgPayload> stepperMotorOutMsg#
Output msg for the stepper motor state information.
-
StepperMotor() = default#