MotionMagic Lesson Guide

How Do You Normally Run a Motor? (.set Percent Output)

Most robot programmers start by running motors with a simple command:

// Run motor at 50% forward power
motor.set(0.5);
  • This sets the motor output as a percentage of full power (from -1.0 to 1.0).
  • It's open-loop: the motor just runs at the speed you ask, with no feedback or position control.
  • Good for simple tasks, but not precise—motors can overshoot, stall, or drift.

What Is MotionMagic?

MotionMagic is a special feature for controlling motors, made by CTRE for their Talon SRX and Talon FX motor controllers. It helps you move parts of your robot (like arms or elevators) smoothly and precisely to a target position, without needing to write complicated code.

What Is PID Control?

Before MotionMagic, people used something called "PID control" to make motors stop at the right spot. PID stands for:

  • Proportional: How far you are from the target.
  • Integral: How long you've been away from the target.
  • Derivative: How quickly you're approaching the target.

PID helps motors reach and hold a position, but tuning it can be tricky. MotionMagic uses PID behind the scenes, so you don’t need to understand all the math—it does the hard work for you!

How Does MotionMagic Work?

MotionMagic creates a plan for your motor to follow, called a "motion profile." It decides how fast to go and how quickly to speed up or slow down, so your robot part moves smoothly to the target position.

Step-by-Step: Using MotionMagic

Output Control: .set vs .setControl

Understanding how you command a motor is essential for using MotionMagic effectively. TalonFX motor controllers support two main ways to control output:

Method What It Does Typical Use Case
.set(value) Sets percent output (-1.0 to 1.0, or -100% to 100%) Simple open-loop speed control
.setControl(request) Uses advanced control modes (MotionMagic, PID, etc.) Precise position or velocity

.set(value) — Percent Output

This is the most basic way to run a motor. You give it a value between -1.0 and 1.0, and the motor runs at that percentage of full power. This does not use any feedback or closed-loop control.

// Define the function in the Motion subsystem 
public void setMotorSpeed(double speed) {
  motor.set(speed);
}
// Usage example of Percent Output
double speed = 0.5;  // This would be stored in constants
motionInstance.setMotorSpeed(speed);  // This would be called in the state
  • Pros: Simple, direct, good for testing.
  • Cons: No position or speed control, can overshoot or stall.

.setControl(request) — Advanced Control

This method lets you use features like MotionMagic, PID, or velocity control. You create a control request object (such as MotionMagicExpoVoltage) that tells the motor controller exactly how to move, including target position, speed, acceleration, and which PID slot to use.

// Define the function in Motion Subsystem
MotionMagicExpoVoltage positionRequest = new MotionMagicExpoVoltage(0); // Create object at top of file and reuse

public void setAngle(Angle targetAngle) {
  motor.setControl(positionRequest.withPosition(targetAngle));
}
// Usage example of angles as Degrees units
Angle targetAngle = Degrees.of(65.15);  // This would be stored in constants
motionInstance.setAngle(targetAngle);  // This would be called in the state
  • Pros: Precise, smooth, uses feedback sensors, supports profiles.
  • Cons: Requires configuration and understanding of control modes.

1. Configure Your Mechanism Settings

Before using MotionMagic, you must configure your mechanism's TalonFX controller with the correct settings. This includes PID values, sensor-to-mechanism ratio, and gravity compensation type.

  • PID values (kP, kI, kD, kS, kG) control how the motor responds to errors and gravity.
// --- PID and Feedforward Constants ---
// NOTE: We start by setting all to 0, we will tune these later
// Feedforward
MOTOR_CONFIG.Slot0.kS = 0;    // Static gain (overcomes friction)
MOTOR_CONFIG.Slot0.kG = 0;   // Gravity feedforward (helps hold up against gravity)
// PID
MOTOR_CONFIG.Slot0.kP = 0;    // Proportional gain (how hard to correct position error)
  • GravityType tells the controller how to compensate for gravity (use Elevator_Static for vertical lifts, Arm_Cosine for rotating arms). DO DEMO
// --- Gravity Compensation Type ---
MOTOR_CONFIG.Slot0.GravityType = GravityTypeValue.Elevator_Static;
// Use Elevator_Static for vertical lifts, Arm_Cosine for rotating arms
  • SensorToMechanismRatio ensures setpoints and feedback are in real-world units (like inches or degrees). This is what we call "Gear Ratio". We just ask mechanical for this value. Each number represents a gear.
// --- Sensor Conversion ---
MOTOR_CONFIG.Feedback.SensorToMechanismRatio = ((12.0 / 60.0) * (26.0 / 52.0));
// MOTOR_CONFIG.Feedback.SensorToMechanismRatio = ((GEAR_1 / GEAR_2) * (GEAR_3 / GEAR_4));
// Converts motor rotations to mechanism units (e.g., inches of elevator travel)
// --- Apply the config to motor like we already do ---
motor.getConfigurator().apply(constMotion.MOTOR_CONFIG);

More Resources


This guide is for beginners. You don’t need to know all the math—just follow the steps and experiment!