Wolflib 0.1.0
PROS differential-drive motion, mapping, and Monte Carlo localization
Loading...
Searching...
No Matches
Using motions

Wolflib motions move a differential-drive chassis to absolute field coordinates. Distances are inches and angles are degrees. The field origin is at its center, positive X points right, positive Y points forward, and headings increase clockwise from positive Y.

Every controller reads getPose(). That pose is raw odometry when MCL fusion is disabled, or confidence-gated odometry plus a bounded MCL correction when fusion is enabled.

Before the first move

Calibrate, establish the known starting pose, and load the map before issuing autonomous motions:

void initialize() {
if (!chassis.calibrate()) return;
chassis.setPose(0, -60, 0);
chassis.loadMap(); // Motions still work from odometry if this fails.
}

Tune the angular and lateral PID controllers with setMclFusionEnabled(false). Re-enable fusion only after straight distances, turn angles, tracking-wheel signs, and IMU direction are correct.

Synchronous and asynchronous calls

Motion calls are asynchronous by default. A successful call adds a copied command to the FIFO queue and returns immediately:

chassis.turnToHeading(90, 1500);
chassis.moveToPoint(36, 24, 2500);
chassis.waitUntilDone();

Set async to false when the next line must not run until the motion exits:

turn.async = false;
turn.maxSpeed = 90;
chassis.turnToHeading(90, 1500, turn);
// This runs after the turn settles, exits early, is cancelled, or times out.
activateClamp();
double maxSpeed
Definition chassis.hpp:15
bool async
Definition chassis.hpp:20
Definition chassis.hpp:23

The Boolean return value says whether the command was accepted. It does not distinguish settling from a timeout. An asynchronous command can be rejected when the configured motion queue is full.

Angular motions

Turn to a heading

turnToHeading turns in place to an absolute heading:

chassis.turnToHeading(135, 1800);

Use direction to force the longer or shorter side of an obstacle instead of letting Wolflib choose the shortest turn:

turn.async = false;
chassis.turnToHeading(270, 2200, turn);
AngularDirection direction
Definition chassis.hpp:24

Forced direction applies to the entire command. Use AngularDirection::Automatic for normal shortest-angle behavior.

Turn to a point

turnToPoint continuously aims at a field coordinate. This is useful when the target may be approached from slightly different starting poses:

chassis.turnToPoint(48, 48, 1600);

Set forwards = false to point the back of the robot at the coordinate:

rearFacing.forwards = false;
rearFacing.async = false;
chassis.turnToPoint(0, -60, 1600, rearFacing);
bool forwards
Definition chassis.hpp:25

Avoid a point at or extremely close to the robot's current position because the target bearing becomes poorly defined there.

Swing turns

A swing turn holds one side of the drivetrain at zero and drives the other:

chassis.swingToHeading(
chassis.swingToPoint(

DriveSide::Left means the left side is locked; DriveSide::Right locks the right side. Swing turns need their own real-robot testing because their effective turning geometry and traction differ from an in-place turn.

Lateral motions

Move to a point

moveToPoint drives to an absolute X/Y coordinate while steering toward it:

chassis.moveToPoint(0, 24, 2500);

It is the simplest choice when the final heading does not need to be exact. Drive backward without changing the coordinate by setting forwards = false:

reverse.forwards = false;
reverse.maxSpeed = 100;
reverse.async = false;
chassis.moveToPoint(0, -36, 2500, reverse);
Definition chassis.hpp:28
bool forwards
Definition chassis.hpp:29

Move to a pose

moveToPose drives to X/Y and also controls the desired final heading. Its boomerang-style controller aims at a moving carrot point behind the target pose; this is a single pose motion, not path following or pure pursuit.

pose.maxSpeed = 110;
pose.lead = 0.6;
pose.horizontalDrift = 8;
pose.async = false;
chassis.moveToPose(36, 36, 90, 3200, pose);
Definition chassis.hpp:32
double lead
Definition chassis.hpp:34
double horizontalDrift
Definition chassis.hpp:35

lead is clamped from 0 to 1. Larger values place the carrot farther behind the target and generally produce a broader approach. horizontalDrift controls how strongly heading correction is allowed while the robot is still far away; a non-positive value uses Drivetrain::horizontalDrift. Treat both as geometry-dependent tuning values, not universal constants.

For a reverse pose approach, set forwards = false and verify the approach and settling behavior on the real drivetrain before using it near field elements.

Motion options

All option structures inherit these fields from MotionOptions:

Field Meaning
maxSpeed Maximum motor command magnitude, from 0 to 127.
minSpeed Minimum nonzero command. Useful for chaining through an early exit, but too much can overshoot.
slew Maximum output change per motion update. Negative inherits the tuned controller value, zero disables it, and positive overrides it.
earlyExitRange Optional error threshold for leaving while still moving. It is active only when both this and minSpeed are positive.
async Queue and return when true; wait for this command when false.

TurnOptions adds forced turn direction and front/rear point-facing behavior. MoveToPointOptions adds forward or reverse travel. MoveToPoseOptions adds forward or reverse travel, lead, and horizontalDrift.

Every motion also receives a timeout in milliseconds. It is a hard safety limit, so allow enough time for the slowest expected legal movement without using it as a substitute for correctly tuned exit conditions.

Chaining motions

Asynchronous calls are queued in issue order:

through.minSpeed = 45;
through.earlyExitRange = 3;
finishTurn.maxSpeed = 80;
chassis.moveToPoint(0, 24, 1800, through);
chassis.moveToPoint(24, 48, 2200, through);
chassis.turnToHeading(90, 1500, finishTurn);
chassis.waitUntilDone();
double minSpeed
Definition chassis.hpp:16
double earlyExitRange
Definition chassis.hpp:19

For point and pose motions, earlyExitRange is inches from the target. For turn and swing motions, it is degrees from the target. The next queued command starts as soon as the current command exits. This is motion chaining, not a continuous path follower, so it does not calculate one smooth trajectory through all targets.

Check enqueue results if queue saturation must be handled explicitly:

if (!chassis.moveToPoint(24, 24, 2000)) {
chassis.cancelAllMotions();
// Enter a known-safe autonomous fallback.
}

Waiting for progress

waitUntil lets mechanism actions overlap a motion. Progress is accumulated distance for point/pose moves and accumulated rotation for turn/swing moves:

chassis.moveToPoint(0, 36, 2500);
chassis.waitUntil(12); // 12 inches of accumulated travel.
startIntake();
chassis.waitUntilDone();
chassis.turnToHeading(180, 2500);
chassis.waitUntil(70); // 70 degrees of accumulated rotation.
releaseLatch();
chassis.waitUntilDone();

Call waitUntil immediately after the command it should observe. It tracks the most recently issued command at the time of the call and returns early if that command finishes before reaching the requested progress.

Cancellation

cancelMotion() requests cancellation of only the active command. Already queued commands remain:

chassis.moveToPoint(0, 48, 3000);
chassis.turnToHeading(90, 1500);
if (goalDetected()) chassis.cancelMotion();

cancelAllMotions() stops the active command and clears the queue. Use it for an autonomous abort or before deliberately taking direct control of the drive:

if (pros::competition::is_disabled()) {
chassis.cancelAllMotions();
}

isInMotion() reports true while a command is running or waiting in the queue. waitUntilDone() blocks until both are empty.

Complete autonomous example

void autonomous() {
chassis.setPose(-48, -60, 0);
collect.maxSpeed = 105;
collect.minSpeed = 35;
collect.earlyExitRange = 2.5;
if (!chassis.moveToPoint(-48, -24, 2200, collect)) return;
chassis.waitUntil(8);
startIntake();
faceGoal.maxSpeed = 85;
if (!chassis.turnToPoint(24, 48, 1800, faceGoal)) {
chassis.cancelAllMotions();
return;
}
score.maxSpeed = 95;
score.lead = 0.55;
score.horizontalDrift = 8;
if (!chassis.moveToPose(24, 48, 90, 3200, score)) {
chassis.cancelAllMotions();
return;
}
chassis.waitUntilDone();
scoreGameObject();
}

The sample values are placeholders. Tune PID gains, exit conditions, slew, minimum output, timeouts, lead, and horizontalDrift on the actual robot.