Let's build a two-stage elevator driven by a Kraken X60 running CTRE's integrated Talon FX controller. The goal: command the elevator to named heights (stow, L2, L4) and have it slew there on a trapezoidal profile using Motion Magic, Phoenix 6's onboard motion-profiled position control.
Configure the motor#
Motion Magic needs a Slot 0 PID set plus a feedforward (kS/kV/kA) and the profile limits (cruise velocity, acceleration, jerk). All of it lives in a TalonFXConfiguration:
private final TalonFX m_motor = new TalonFX(20); // CAN ID 20
private final MotionMagicVoltage m_request = new MotionMagicVoltage(0);
public Elevator() {
var cfg = new TalonFXConfiguration();
var slot0 = cfg.Slot0;
slot0.kS = 0.25; // volts to overcome static friction
slot0.kV = 0.12; // volts per rotation/sec
slot0.kA = 0.01; // volts per rotation/sec^2
slot0.kG = 0.30; // gravity feedforward (elevator type)
slot0.kP = 4.8;
slot0.kI = 0;
slot0.kD = 0.1;
slot0.GravityType = GravityTypeValue.Elevator_Static;
var mm = cfg.MotionMagic;
mm.MotionMagicCruiseVelocity = 80; // rotations per second
mm.MotionMagicAcceleration = 160; // rps per second
mm.MotionMagicJerk = 1600; // rps per second^2
m_motor.getConfigurator().apply(cfg);
}
GravityTypeValue.Elevator_Static is the correct value for a vertical lift (use Arm_Cosine instead for a rotating arm, where the gravity term scales with the cosine of the angle).
Convert rotations to inches#
Your mechanism doesn't think in motor rotations -- it thinks in inches of travel. If a 24-tooth pulley with 5 mm pitch moves the carriage, and the gearbox is 9:1, one motor rotation = (24 x 5 mm) / 9 = 13.33 mm = 0.525 in. Store that constant and convert at the boundary:
private static final double kRotationsPerInch = 9.0 / (24 * 5.0 / 25.4);
public Command goToHeight(double inches) {
double targetRot = inches * kRotationsPerInch;
return run(() -> m_motor.setControl(m_request.withPosition(targetRot)))
.until(() -> Math.abs(
m_motor.getPosition().getValueAsDouble() - targetRot) < 0.5);
}
Wire it to a button#
In RobotContainer, expose named heights as command factories and bind them:
m_driver.a().onTrue(m_elevator.goToHeight(0.0)); // stow
m_driver.b().onTrue(m_elevator.goToHeight(31.5)); // L2
m_driver.y().onTrue(m_elevator.goToHeight(72.0)); // L4
Tune in this order#
- Set kP=kI=kD=0 and only kG until the carriage holds position against gravity.
- Add kV (from a SysId run or
12 / free-speed-rps), then kS. - Bring up kP until it tracks the profile crisply; add a little kD only if it overshoots.
Because Motion Magic generates the trajectory on the motor controller at 1 kHz, your roboRIO loop just sends a target rotation -- no 20 ms profile math on the RIO. Watch the position-vs-setpoint plot in AdvantageScope while tuning; the measured curve should hug the generated profile with no lag.
the part worth keeping
Key takeaways
- Motion Magic runs a trapezoidal profile on the Talon FX itself; the RIO only sends a target position.
- Slot 0 needs PID plus kS/kV/kA and (for elevators/arms) kG with the correct GravityType (Elevator_Static vs Arm_Cosine).
- Always convert mechanism units (inches) to motor rotations at the API boundary using a single constant.
- Tune gravity first, then velocity feedforward, then kP -- not kP first.
Programming, Controls & SensorsWorked Examples and Mini-Projectslesson 1 of 5
Keep going
Take the quiz+10 XP with an accountMore in Worked Examples and Mini-Projects
where this came from
Sources and corrections
This lesson is AI-assisted: drafted from primary sources, then reviewed and edited by hand. Errors still get through. When one is reported we fix it and write down what changed, in public, in the corrections log.
sources and further reading
- v6.docs.ctr-electronics.comPhoenix 6: Motion Magic Controls
- api.ctr-electronics.comPhoenix 6 Java API: Slot0Configs (GravityType)
- docs.wpilib.orgWPILib Command-Based: Subsystems
clipped to this lesson
Articles that go further on this
The lesson gets you through the topic. These go wider on it, and they read in one sitting.
- 16 min readFRC Elevator and Arm Design: Staging, Rigging, Motors, Gravity, and SafetyA primary-source FRC guide to designing elevators and arms: cascade vs continuous rigging, staging, motor and gear-ratio sizing, gravity math, and safe holding./blogread it
- 7 min readFRC Motion Profiling Explained: TrapezoidProfile and ProfiledPIDControllerHow WPILib's TrapezoidProfile and ProfiledPIDController smooth mechanism motion, how to pick velocity and acceleration constraints, and when a profile beats plain PID./blogread it
- 18 min readCTRE Phoenix for FRC: Kraken X60/X44, TalonFX, Phoenix 6, CANcoder & Pigeon 2A practical guide to the CTRE Phoenix ecosystem for FRC: Kraken X60/X44 motors, TalonFX, Phoenix 6 API, Pro/FOC licensing, CANcoder, Pigeon 2 & CANivore./blogread it
answer sheet
Lesson quiz
All 3 right completes the lesson. Miss one and only that question comes back, anything you already answered correctly stays banked.
0 of 3 answered
01In CTRE Phoenix 6, what does Motion Magic do when you command a TalonFX to a target elevator position?
02For an elevator, why is a gravity feedforward (kG) added to the Motion Magic output?
03Which control request drives a TalonFX elevator to a position with Motion Magic and voltage-based output?
Answer every question to submit.
All 51 lessons in Programming, Controls & Sensorsopenclose
01 / prerequisites
02 / foundations-tools-and-first-program
03 / robot-program-and-command-based
04 / motors-and-control
05 / autonomous-trajectories-simulation
06 / sensing-fundamentals
07 / encoders
08 / gyros-imus-orientation
09 / closed-loop-control
10 / vision-pose-estimation
11 / worked-examples-mini-projects
- Not read yet:Mini-Project: A Closed-Loop Elevator with Motion Magic
- Not read yet:Mini-Project: A Velocity-Controlled Shooter on REVLib
- Not read yet:Mini-Project: A Teleop Swerve Drive Subsystem
- Not read yet:Mini-Project: An Autonomous Routine with PathPlanner
- Not read yet:Mini-Project: Vision-Aligned Scoring with Limelight
12 / common-mistakes-troubleshooting
13 / advanced-techniques-case-studies
- Not read yet:State-Space Control and Kalman Filtering
- Not read yet:Log Replay Architecture with AdvantageKit
- Not read yet:Advanced Pose Estimation: Multi-Tag Fusion and Standard Deviations
- Not read yet:Robot Coordination, Alerts, and Operator Feedback
- Not read yet:Case Study: Hardening Software Before an Event