Motion Magic® Controls#

In addition to basic PID control, the Talon FX also supports onboard motion profiling using Motion Magic® controls.

Motion Magic®#

Motion Magic® is a control mode that provides the benefit of Motion Profiling without needing to generate motion profile trajectory points. When using Motion Magic®, the motor will move to a target position using a motion profile, while honoring the user specified acceleration, maximum velocity (cruise velocity), and optional jerk.

The benefits of this control mode over “simple” PID position closed-looping are:

  • Control of the mechanism throughout the entire motion (as opposed to racing to the end target position)

  • Control of the mechanism’s inertia to ensure smooth transitions between setpoints

  • Improved repeatability despite changes in battery load

  • Improved repeatability despite changes in motor load

After gain/settings are determined, the robot controller only needs to periodically set the target position.

There is no general requirement to “wait for the profile to finish”. However, the robot application can poll the sensor position and determine when the motion is finished if need be.

Motion Magic® functions by generating a trapezoidal/S-Curve velocity profile that does not exceed the specified cruise velocity, acceleration, or jerk. This is done automatically by the motor controller.

Note

If the remaining sensor distance to travel is small, the velocity may not reach cruise velocity as this would overshoot the target position. This is often referred to as a “triangle profile”.

Trapezoidal graph that showcases target cruise velocity and current velocity

If the Motion Magic® jerk is set to a nonzero value, the generated velocity profile is no longer trapezoidal, but instead is a continuous S-Curve (corner points are smoothed).

An S-Curve profile has the following advantaged over a trapezoidal profile:

  • Reducing oscillation of the mechanism.

  • Maneuver is more deliberate and reproducible.

Note

The jerk control feature, by its nature, will increase the amount of time a movement requires. This can be compensated for by increasing the configured acceleration value.

Graph showing velocity and position using s-curve profile

The following parameters must be set when controlling using Motion Magic®

  • Cruise Velocity - peak/cruising velocity of the motion

  • Acceleration - controls acceleration and deceleration rates during the beginning and end of motion

  • Jerk (optional) - controls jerk, which is the derivative of acceleration

Using Motion Magic® in API#

Motion Magic® is currently supported for all base control output types. The units of the output are determined by the control output type.

The Motion Magic® jerk, acceleration, and cruise velocity can be configured in code using a MotionMagicConfigs (Java, C++, Python) object.

In Motion Magic®, the gains should be configured as follows:

  • \(K_s\) - output to overcome static friction (output)

  • \(K_v\) - output per unit of target velocity (output/rps)

  • \(K_a\) - output per unit of target acceleration (output/(rps/s))

  • \(K_p\) - output per unit of error in position (output/rotation)

  • \(K_i\) - output per unit of integrated error in position (output/(rotation*s))

  • \(K_d\) - output per unit of error in velocity (output/rps)

// in init function
var talonFXConfigs = new TalonFXConfiguration();

// set slot 0 gains
var slot0Configs = talonFXConfigs.Slot0;
slot0Configs.kS = 0.25; // Add 0.25 V output to overcome static friction
slot0Configs.kV = 0.12; // A velocity target of 1 rps results in 0.12 V output
slot0Configs.kA = 0.01; // An acceleration of 1 rps/s requires 0.01 V output
slot0Configs.kP = 4.8; // A position error of 2.5 rotations results in 12 V output
slot0Configs.kI = 0; // no output for integrated error
slot0Configs.kD = 0.1; // A velocity error of 1 rps results in 0.1 V output

// set Motion Magic settings
var motionMagicConfigs = talonFXConfigs.MotionMagic;
motionMagicConfigs.MotionMagicCruiseVelocity = 80; // Target cruise velocity of 80 rps
motionMagicConfigs.MotionMagicAcceleration = 160; // Target acceleration of 160 rps/s (0.5 seconds)
motionMagicConfigs.MotionMagicJerk = 1600; // Target jerk of 1600 rps/s/s (0.1 seconds)

m_talonFX.getConfigurator().apply(talonFXConfigs);
// in init function
configs::TalonFXConfiguration talonFXConfigs{};

// set slot 0 gains
auto& slot0Configs = talonFXConfigs.Slot0;
slot0Configs.kS = 0.25; // Add 0.25 V output to overcome static friction
slot0Configs.kV = 0.12; // A velocity target of 1 rps results in 0.12 V output
slot0Configs.kA = 0.01; // An acceleration of 1 rps/s requires 0.01 V output
slot0Configs.kP = 4.8; // A position error of 2.5 rotations results in 12 V output
slot0Configs.kI = 0; // no output for integrated error
slot0Configs.kD = 0.1; // A velocity error of 1 rps results in 0.1 V output

// set Motion Magic settings
auto& motionMagicConfigs = talonFXConfigs.MotionMagic;
motionMagicConfigs.MotionMagicCruiseVelocity = 80; // Target cruise velocity of 80 rps
motionMagicConfigs.MotionMagicAcceleration = 160; // Target acceleration of 160 rps/s (0.5 seconds)
motionMagicConfigs.MotionMagicJerk = 1600; // Target jerk of 1600 rps/s/s (0.1 seconds)

m_talonFX.GetConfigurator().Apply(talonFXConfigs);
# in init function
talonfx_configs = configs.TalonFXConfiguration()

# set slot 0 gains
slot0_configs = talonfx_configs.slot0
slot0_configs.k_s = 0.25 # Add 0.25 V output to overcome static friction
slot0_configs.k_v = 0.12 # A velocity target of 1 rps results in 0.12 V output
slot0_configs.k_a = 0.01 # An acceleration of 1 rps/s requires 0.01 V output
slot0_configs.k_p = 4.8 # A position error of 2.5 rotations results in 12 V output
slot0_configs.k_i = 0 # no output for integrated error
slot0_configs.k_d = 0.1 # A velocity error of 1 rps results in 0.1 V output

# set Motion Magic settings
motion_magic_configs = talonfx_configs.motion_magic
motion_magic_configs.motion_magic_cruise_velocity = 80 # Target cruise velocity of 80 rps
motion_magic_configs.motion_magic_acceleration = 160 # Target acceleration of 160 rps/s (0.5 seconds)
motion_magic_configs.motion_magic_jerk = 1600 # Target jerk of 1600 rps/s/s (0.1 seconds)

self.talonfx.configurator.apply(talonfx_configs)

Tip

Motion Magic® supports modifying cruise velocity, acceleration, and jerk on the fly (requires firmware version 24.0.6.0 or newer).

Once the gains are configured, the Motion Magic® request can be sent to the TalonFX. The control request object has an optional feedforward term that can be used to add an arbitrary value to the output, which can be useful to account for the effects of gravity.

// create a Motion Magic request, voltage output
final MotionMagicVoltage m_request = new MotionMagicVoltage(0);

// set target position to 100 rotations
m_talonFX.setControl(m_request.withPosition(100));
// create a Motion Magic request, voltage output
controls::MotionMagicVoltage m_request{0_tr};

// set target position to 100 rotations
m_talonFX.SetControl(m_request.WithPosition(100_tr));
# create a Motion Magic request, voltage output
self.request = controls.MotionMagicVoltage(0)

# set target position to 100 rotations
self.talonfx.set_control(self.request.with_position(100))

Dynamic Motion Magic®#

Important

This feature requires the device to be Pro licensed and on a CANivore. When unlicensed, the TalonFX will disable control output and trip the UnlicensedFeatureInUse fault.

When using a Pro-licensed Talon FX connected to a CANivore, Dynamic Motion Magic® can be used, allowing for the cruise velocity, acceleration, and jerk to be modified directly in the control request during motion. This can be used to set up different values for acceleration vs deceleration or to speed up and slow down the profile on the fly.

The gain slots are configured in the same way as a regular Motion Magic® request. However, the cruise velocity, acceleration, and jerk parameters are set up in the control request, not the Motion Magic® config group.

Once the gains are configured, the Dynamic Motion Magic® request can be sent to the TalonFX. The control request object has an optional feedforward term that can be used to add an arbitrary value to the output, which can be useful to account for the effects of gravity.

// create a Dynamic Motion Magic request, voltage output
// default velocity of 80 rps, acceleration of 400 rot/s^2, and jerk of 4000 rot/s^3
final DynamicMotionMagicVoltage m_request =
   new DynamicMotionMagicVoltage(0, 80, 400, 4000);

if (m_joy.getAButton()) {
   // while the joystick A button is held, use a slower profile
   m_request.Velocity = 40; // rps
   m_request.Acceleration = 80; // rot/s^2
   m_request.Jerk = 400; // rot/s^3
} else {
   // otherwise use a faster profile
   m_request.Velocity = 80; // rps
   m_request.Acceleration = 400; // rot/s^2
   m_request.Jerk = 4000; // rot/s^3
}

// set target position to 100 rotations
m_talonFX.setControl(m_request.withPosition(100));
// create a Dynamic Motion Magic request, voltage output
// default velocity of 80 rps, acceleration of 400 rot/s^2, and jerk of 4000 rot/s^3
controls::DynamicMotionMagicVoltage m_request{
   0_tr, 80_tps, 400_tr_per_s_sq, 4000_tr_per_s_cu};

if (m_joy.GetAButton()) {
   // while the joystick A button is held, use a slower profile
   m_request.Velocity = 40_tps;
   m_request.Acceleration = 80_tr_per_s_sq;
   m_request.Jerk = 400_tr_per_s_cu;
} else {
   // otherwise use a faster profile
   m_request.Velocity = 80_tps;
   m_request.Acceleration = 400_tr_per_s_sq;
   m_request.Jerk = 4000_tr_per_s_cu;
}

// set target position to 100 rotations
m_talonFX.SetControl(m_request.WithPosition(100_tr));
# create a Dynamic Motion Magic request, voltage output
# default velocity of 80 rps, acceleration of 400 rot/s^2, and jerk of 4000 rot/s^3
self.request = controls.DynamicMotionMagicVoltage(0, 80, 400, 4000)

if self.joy.getAButton():
   # while the joystick A button is held, use a slower profile
   self.request.velocity = 40 # rps
   self.request.acceleration = 80 # rot/s^2
   self.request.jerk = 400 # rot/s^3
else:
   # otherwise use a faster profile
   self.request.velocity = 80 # rps
   self.request.acceleration = 400 # rot/s^2
   self.request.jerk = 4000 # rot/s^3

# set target position to 100 rotations
self.talonfx.set_control(self.request.with_position(100))

Motion Magic® Velocity#

The Talon FX also supports onboard velocity motion profiling using Motion Magic® Velocity. When using Motion Magic® Velocity, the motor will ramp to a target velocity using a trapezoidal acceleration profile that honors the specified acceleration and optional jerk.

The benefits of this control mode over “simple” PID velocity closed-looping are:

  • Control of the mechanism throughout the entire motion (as opposed to racing to the end target velocity)

  • Control of the mechanism’s inertia to ensure smooth transitions between setpoints

  • Improved repeatability despite changes in battery load

  • Improved repeatability despite changes in motor load

After gain/settings are determined, the robot controller only needs to periodically set the target velocity.

Graph that showcases the trapezoidal profile velocity and acceleration setpoints.

The following parameters must be set when controlling using Motion Magic® Velocity

  • Acceleration - controls acceleration and deceleration rates during the beginning and end of motion

  • Jerk (optional) - controls jerk, which is the derivative of acceleration

Using Motion Magic® Velocity in API#

Motion Magic® Velocity is currently supported for all base control output types. The units of the output are determined by the control output type.

The Motion Magic® Velocity jerk and acceleration can be configured in code using a MotionMagicConfigs (Java, C++, Python) object.

In Motion Magic® Velocity, the gains should be configured as follows:

  • \(K_s\) - output to overcome static friction (output)

  • \(K_v\) - output per unit of target velocity (output/rps)

  • \(K_a\) - output per unit of target acceleration (output/(rps/s))

  • \(K_p\) - output per unit of error in velocity (output/rps)

  • \(K_i\) - output per unit of integrated error in velocity (output/rotation)

  • \(K_d\) - output per unit of error derivative in velocity (output/(rps/s))

// in init function
var talonFXConfigs = new TalonFXConfiguration();

// set slot 0 gains
var slot0Configs = talonFXConfigs.Slot0;
slot0Configs.kS = 0.25; // Add 0.25 V output to overcome static friction
slot0Configs.kV = 0.12; // A velocity target of 1 rps results in 0.12 V output
slot0Configs.kA = 0.01; // An acceleration of 1 rps/s requires 0.01 V output
slot0Configs.kP = 0.11; // An error of 1 rps results in 0.11 V output
slot0Configs.kI = 0; // no output for integrated error
slot0Configs.kD = 0; // no output for error derivative

// set Motion Magic Velocity settings
var motionMagicConfigs = talonFXConfigs.MotionMagic;
motionMagicConfigs.MotionMagicAcceleration = 400; // Target acceleration of 400 rps/s (0.25 seconds to max)
motionMagicConfigs.MotionMagicJerk = 4000; // Target jerk of 4000 rps/s/s (0.1 seconds)

m_talonFX.getConfigurator().apply(talonFXConfigs);
// in init function
configs::TalonFXConfiguration talonFXConfigs{};

// set slot 0 gains
auto& slot0Configs = talonFXConfigs.Slot0;
slot0Configs.kS = 0.25; // Add 0.25 V output to overcome static friction
slot0Configs.kV = 0.12; // A velocity target of 1 rps results in 0.12 V output
slot0Configs.kA = 0.01; // An acceleration of 1 rps/s requires 0.01 V output
slot0Configs.kP = 0.11; // An error of 1 rps results in 0.11 V output
slot0Configs.kI = 0; // no output for integrated error
slot0Configs.kD = 0; // no output for error derivative

// set Motion Magic Velocity settings
auto& motionMagicConfigs = talonFXConfigs.MotionMagic;
motionMagicConfigs.MotionMagicAcceleration = 400; // Target acceleration of 400 rps/s (0.25 seconds to max)
motionMagicConfigs.MotionMagicJerk = 4000; // Target jerk of 4000 rps/s/s (0.1 seconds)

m_talonFX.GetConfigurator().Apply(talonFXConfigs);
# in init function
talonfx_configs = configs.TalonFXConfiguration()

# set slot 0 gains
slot0_configs = talonfx_configs.slot0
slot0_configs.k_s = 0.25 # Add 0.25 V output to overcome static friction
slot0_configs.k_v = 0.12 # A velocity target of 1 rps results in 0.12 V output
slot0_configs.k_a = 0.01 # An acceleration of 1 rps/s requires 0.01 V output
slot0_configs.k_p = 0.11 # An error of 1 rps results in 0.11 V output
slot0_configs.k_i = 0 # no output for integrated error
slot0_configs.k_d = 0 # no output for error derivative

# set Motion Magic Velocity settings
motion_magic_configs = talonfx_configs.motion_magic
motion_magic_configs.motion_magic_acceleration = 400 # Target acceleration of 400 rps/s (0.25 seconds to max)
motion_magic_configs.motion_magic_jerk = 4000 # Target jerk of 4000 rps/s/s (0.1 seconds)

self.talonfx.configurator.apply(talonfx_configs)

Tip

Motion Magic® Velocity supports modifying acceleration and jerk on the fly (requires firmware version 24.0.6.0 or newer).

Once the gains are configured, the Motion Magic® Velocity request can be sent to the TalonFX.

The Motion Magic® Velocity request has an Acceleration parameter that can be used to override the profile acceleration during motion. If the Acceleration parameter is left 0, the acceleration config will be used instead.

The control request object also has an optional feedforward term that can be used to add an arbitrary value to the output, which can be useful to account for the effects of gravity.

// create a Motion Magic Velocity request, voltage output
final MotionMagicVelocityVoltage m_request = new MotionMagicVelocityVoltage(0);

if (m_joy.getAButton()) {
   // while the joystick A button is held, use a slower acceleration
   m_request.Acceleration = 100; // rot/s^2
} else {
   // otherwise, fall back to the config
   m_request.Acceleration = 0;
}

// set target velocity to 80 rps
m_talonFX.setControl(m_request.withVelocity(80));
// create a Motion Magic Velocity request, voltage output
controls::MotionMagicVelocityVoltage m_request{0_tps};

if (m_joy.GetAButton()) {
   // while the joystick A button is held, use a slower acceleration
   m_request.Acceleration = 100_tr_per_s_sq;
} else {
   // otherwise, fall back to the config
   m_request.Acceleration = 0_tr_per_s_sq;
}

// set target velocity to 80 rps
m_talonFX.SetControl(m_request.WithVelocity(80_tps));
# create a Motion Magic Velocity request, voltage output
self.request = controls.MotionMagicVelocityVoltage(0)

if self.joy.getAButton():
   # while the joystick A button is held, use a slower acceleration
   self.request.acceleration = 100 # rot/s^2
else:
   # otherwise, fall back to the config
   self.request.acceleration = 0

# set target velocity to 80 rps
self.talonfx.set_control(self.request.with_velocity(80))

Motion Magic® Expo#

Whereas traditional Motion Magic® generates a trapezoidal or S-Curve profile, Motion Magic® Expo generates an exponential profile. This allows the profile to best match the system dynamics, reducing both overshoot and time to target compared to a trapezoidal profile.

Graph that showcases the exponential profile position and velocity setpoints.

Motion Magic® Expo uses the kV and kA characteristics of the system, as well as an optional cruise velocity. The Motion Magic® Expo kV and kA configs are separate from the slot gain configs, as they may use different units and have different behaviors.

The Motion Magic® Expo kV represents the voltage required to maintain a given velocity and is in units of Volts/rps. Dividing the supply voltage by kV results in the maximum velocity of the profile. As a result, when supply voltage is fixed, a higher profile kV results in a lower profile velocity. Unlike with gain slots, it is safer to start from a higher kV than what is ideal.

The Motion Magic® Expo kA represents the voltage required to apply a given acceleration and is in units of Volts/(rps/s). Dividing the supply voltage by kA results in the maximum acceleration of the profile from 0. As a result, when supply voltage is fixed, a higher profile kA results in a lower profile acceleration. Unlike with gain slots, it is safer to start from a higher kA than what is ideal.

If the Motion Magic® cruise velocity is set to a non-zero value, the profile will only accelerate up to the cruise velocity. Otherwise, the profile will accelerate towards the maximum possible velocity based on the profile kV.

The following parameters must be set when controlling using Motion Magic® Expo:

  • Expo kV - voltage required to maintain a given velocity, in V/rps

  • Expo kA - voltage required to apply a given acceleration, in V/(rps/s)

  • Cruise Velocity (optional) - peak velocity of the profile; set to 0 to target the system’s max velocity

Using Motion Magic® Expo in API#

Motion Magic® Expo is currently supported for all base control output types. The units of the output are determined by the control output type.

The Motion Magic® Expo kV, kA, and cruise velocity can be configured in code using a MotionMagicConfigs (Java, C++, Python) object.

Important

Unlike the gain slots, the MotionMagicExpo_kV and MotionMagicExpo_kA configs are always in output units of Volts.

In Motion Magic® Expo, the gains should be configured as follows:

  • \(K_s\) - output to overcome static friction (output)

  • \(K_v\) - output per unit of target velocity (output/rps)

  • \(K_a\) - output per unit of target acceleration (output/(rps/s))

  • \(K_p\) - output per unit of error in position (output/rotation)

  • \(K_i\) - output per unit of integrated error in position (output/(rotation*s))

  • \(K_d\) - output per unit of error in velocity (output/rps)

// in init function
var talonFXConfigs = new TalonFXConfiguration();

// set slot 0 gains
var slot0Configs = talonFXConfigs.Slot0;
slot0Configs.kS = 0.25; // Add 0.25 V output to overcome static friction
slot0Configs.kV = 0.12; // A velocity target of 1 rps results in 0.12 V output
slot0Configs.kA = 0.01; // An acceleration of 1 rps/s requires 0.01 V output
slot0Configs.kP = 4.8; // A position error of 2.5 rotations results in 12 V output
slot0Configs.kI = 0; // no output for integrated error
slot0Configs.kD = 0.1; // A velocity error of 1 rps results in 0.1 V output

// set Motion Magic Expo settings
var motionMagicConfigs = talonFXConfigs.MotionMagic;
motionMagicConfigs.MotionMagicCruiseVelocity = 0; // Unlimited cruise velocity
motionMagicConfigs.MotionMagicExpo_kV = 0.12; // kV is around 0.12 V/rps
motionMagicConfigs.MotionMagicExpo_kA = 0.1; // Use a slower kA of 0.1 V/(rps/s)

m_talonFX.getConfigurator().apply(talonFXConfigs);
// in init function
configs::TalonFXConfiguration talonFXConfigs{};

// set slot 0 gains
auto& slot0Configs = talonFXConfigs.Slot0;
slot0Configs.kS = 0.25; // Add 0.25 V output to overcome static friction
slot0Configs.kV = 0.12; // A velocity target of 1 rps results in 0.12 V output
slot0Configs.kA = 0.01; // An acceleration of 1 rps/s requires 0.01 V output
slot0Configs.kP = 4.8; // A position error of 2.5 rotations results in 12 V output
slot0Configs.kI = 0; // no output for integrated error
slot0Configs.kD = 0.1; // A velocity error of 1 rps results in 0.1 V output

// set Motion Magic Expo settings
auto& motionMagicConfigs = talonFXConfigs.MotionMagic;
motionMagicConfigs.MotionMagicCruiseVelocity = 0; // Unlimited cruise velocity
motionMagicConfigs.MotionMagicExpo_kV = 0.12; // kV is around 0.12 V/rps
motionMagicConfigs.MotionMagicExpo_kA = 0.1; // Use a slower kA of 0.1 V/(rps/s)

m_talonFX.GetConfigurator().Apply(talonFXConfigs);
# in init function
talonfx_configs = configs.TalonFXConfiguration()

# set slot 0 gains
slot0_configs = talonfx_configs.slot0
slot0_configs.k_s = 0.25 # Add 0.25 V output to overcome static friction
slot0_configs.k_v = 0.12 # A velocity target of 1 rps results in 0.12 V output
slot0_configs.k_a = 0.01 # An acceleration of 1 rps/s requires 0.01 V output
slot0_configs.k_p = 4.8 # A position error of 2.5 rotations results in 12 V output
slot0_configs.k_i = 0 # no output for integrated error
slot0_configs.k_d = 0.1 # A velocity error of 1 rps results in 0.1 V output

# set Motion Magic Expo settings
motion_magic_configs = talonfx_configs.motion_magic
motion_magic_configs.motion_magic_cruise_velocity = 0 # Unlimited cruise velocity
motion_magic_configs.motion_magic_expo_k_v = 0.12 # kV is around 0.12 V/rps
motion_magic_configs.motion_magic_expo_k_a = 0.1 # Use a slower kA of 0.1 V/(rps/s)

self.talonfx.configurator.apply(talonfx_configs)

Tip

Motion Magic® Expo supports modifying cruise velocity, kV, and kA on the fly.

Once the gains are configured, the Motion Magic® Expo request can be sent to the TalonFX. The control request object has an optional feedforward term that can be used to add an arbitrary value to the output, which can be useful to account for the effects of gravity.

// create a Motion Magic Expo request, voltage output
final MotionMagicExpoVoltage m_request = new MotionMagicExpoVoltage(0)

// set target position to 100 rotations
m_talonFX.setControl(m_request.withPosition(100));
// create a Motion Magic Expo request, voltage output
controls::MotionMagicExpoVoltage m_request{0_tr}

// set target position to 100 rotations
m_talonFX.SetControl(m_request.WithPosition(100_tr));
# create a Motion Magic Expo request, voltage output
self.request = controls.MotionMagicExpoVoltage(0)

# set target position to 100 rotations
self.talonfx.set_control(self.request.with_position(100))