# MAXMotion Position Control

MAXMotion Position Control is a second-degree closed loop controller, allowing for smooth and consistent motions from one position to another by limiting both the velocity and acceleration of the motor. These can be configured via the [MAXMotion Parameters](https://docs.revrobotics.com/revlib/spark/closed-loop-control-getting-started#maxmotion-parameters), setting a target acceleration and a "cruise" velocity. The motor will spin up, honoring the acceleration target, hold speed at the cruise velocity, and then slow down honoring the acceleration target to arrive at the setpoint. MAXMotion updates its motion profile every 10ms and the underlying PID controller every 1ms, which makes it extremely fast and responsive.

## How it Works

MAXMotion generates a profile containing all the key transition points between the current position and the setpoint and uses that to calculate intermediate positions for the PID controller to follow.

<figure><img src="https://4253857238-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0OKYENVWAIgVP2TmkWl3%2Fuploads%2FE52E7RexaJL9AegYsMBI%2Fimage.png?alt=media&#x26;token=483d3fac-4393-4222-94be-1688b4ed4e3d" alt=""><figcaption></figcaption></figure>

Each point along the profile is a target for the PID controller at the point in time it corresponds to. If, at some point in time, the actual measured position is more than the configured Allowed Profile Error away from the profile, the profile will be regenerated from the current position and velocity. While the mechanism is within that margin, it will continue to track the same profile. This makes tuning easy and makes motions consistent and accurate.

## Configuring MAXMotion

### Feedforwards

The SPARK Feedforward system was designed with MAXMotion in mind, and MAXMotion can take advantage of all of its features.

The first step of setting up MAXMotion is to configure the PID feedforwards, as explained on [the feedforward page](https://docs.revrobotics.com/revlib/spark/closed-loop/feed-forward-control). The kV and kA values from a calculator, converted to appropriate units, or from a tool like SysID are perfect starting points for tuning.

### MAXMotion Constants

There are 3 primary constants to configure for MAXMotion:

* Cruise Velocity: this is the speed you want the motion to hold through the middle of its path
* Maximum Acceleration: this is the acceleration you want to use to speed up and slow down the motion
* Allowed Profile Error: this is the amount of position deviation from the profile that is allowed before the profile is regenerated

{% hint style="warning" %}
If changes to quantities aren't showing the expected results, the Current Limits may be engaging. This will limit the acceleration of the system and can be remedied by increasing the Current Limit (within reason) or increasing the Gear Ratio.
{% endhint %}

### What do the constants do?

<table><thead><tr><th width="184">Constant</th><th>Associated behavior</th></tr></thead><tbody><tr><td>Cruise Velocity</td><td>This is the top of the trapezoid, the velocity that is sustained through the center stage of the motion. Increasing it beyond what is achievable will result in a triangular "trapezoid" on you Velocity graph.</td></tr><tr><td>Maximum Acceleration</td><td>This is how quickly the mechanism accelerates. Increasing it too much will draw a lot of current, and may hit the current limits or stall the motors.</td></tr><tr><td>Allowed Profile Error</td><td>This is how "loose" the profile is, and how far your mechanism can get from the profile before the profile is regenerated. For tuning, it's helpful to set this to a large value so you can see the behavior without the profile resetting, but the end goal for your motion should be to minimize this margin.</td></tr><tr><td>kP</td><td>This is the position-tracking gain. This represents how much voltage is applied proportionally to the position error. Increasing it will make the mechanism move toward the position target more quickly, but increasing it too much will cause overshooting and stuttering.</td></tr><tr><td>kI</td><td>This is the integral gain, which is not often recommended for FRC use.</td></tr><tr><td>kD</td><td>This is the derivative gain, which helps track velocity within the position controller. For better velocity tracking, kV is a better choice.</td></tr><tr><td>kS</td><td>This is the static gain, which helps overcome a constant resistance like friction in a gearbox. It should be set to the maximum voltage in either direction that doesn't make the mechanism move at all, where any more causes motion. Increasing it will improve precision and make motions in different directions more consistent, but increasing it too much will cause jitter.</td></tr><tr><td>kV</td><td>This is the velocity-tracking gain. Increasing it will increase the voltage output proportionally to the velocity target, and will help track velocity more closely. Increasing it too much will cause overshooting on velocity or general instability.</td></tr><tr><td>kA</td><td>This is the acceleration-tracking gain. Increasing it will help track acceleration more closely, but increasing it too much will cause instability. It will make a noticeable difference in velocity tracking during acceleration and deceleration.</td></tr><tr><td>kG and kCos</td><td>These are gravity feedforwards, that help hold position against gravity and remove the gravity factor from the position and velocity tracking of the other constants. For more information on these gains, see <a href="feed-forward-control">Feed Forward Control</a></td></tr></tbody></table>

### Tuning for MAXMotion Position Control

1. Ensure the mechanism is free to move and note any mechanical limits
2. Set up the [Feedforwards](#feedforwards) for the mechanism. **Note that these may not provide expected results until other values are setup**
3. Set P to a very small number, relative to your position units. For the default units, kP = 0.01 is a good starting point. Keep in mind that kP will be *multiplied* by your position error and then become duty cycle percent output, so pick a "small" value relative to what your position error is expected to be
4. Set the Cruise Velocity and Max Acceleration to small numbers, relative to your velocity units and gear ratio. For a directly-driven mechanism with default units, 30 RPM and 10 RPM/s respectively are good starting points to see the effects of MAXMotion and clearly see the impacts of each parameter, but these are very slow and will need increased
5. Set the Allowed Profile Error to a high number relative to your units and the distance to your setpoint. For most motions at the default units, an Allowed Profile Error of 1 Rotation is enough to get started. If the results are confusing, especially if the acceleration targets appear to be too low, increase this. Increasing this value will let the motion continue for a longer period before regenerating the profile, which may uncover the root of a tuning issue
6. Set up a method to retrieve relevant info
   1. If running a robot program, use NetworkTables to post this information
      1. Several of these values can be fetched from the SparkClosedLoopController object
      2. A dashboard like Glass or AdvantageScope can help graph and record these values
   2. In the REV Hardware Client, use the Telemetry tab to enable this information
   3. Good information to watch while tuning:
      1. Position
      2. Velocity
      3. Applied Output
      4. MAXMotion Position Setpoint
      5. MAXMotion Velocity Setpoint
      6. Setpoint
      7. Current Draw
   4. Note that fetching all these values may require modifying the Status Frame Periods for certain parameters as the CAN bus or the SPARK device reaches its limit. If the device stops responding and many Status Frames are timing out, power cycle all devices on the bus to clear the errors and try reducing traffic by increasing status frame periods
   5. Graphing all the positions and all the velocities on 2 graphs will help this process
7. Tuning for your mechanism using [Simulation](https://docs.revrobotics.com/revlib/spark/sim) is a safe, good way to start, but will probably still need further tweaking to make the actual mechanism's motion perfect
8. Be very careful, as this tuning process could cause your mechanism to move in unpredictable or unexpected ways if the constants are off, particularly if your units don't match up
9. Repeat the following process until the results are satisfactory
   1. Run and record a motion to a known setpoint
   2. If the motion is jittery or shaky, reduce kP. If your Allowed Profile Error is small, increase it to a large number while diagnosing issues
   3. If the motion shoots to a high, uncontrollable velocity immediately, increase P to a larger number. With too small of a P value, the feedforwards are sensitive to tiny inaccuracies, but by increasing P it will increase this tolerance. If this persists, reduce your feedforward values, specifically kV
   4. If the MAXMotion Position Setpoint jumps or spikes and resets more than a few times, increase the Allowed Profile Error. This won't contribute to fixing the issue, but will let you better observe the behavior and identify other factors.
   5. If the motion is asymmetrical up vs down, recalculate kG and kS or try determining them experimentally
   6. If the velocity lags behind the target velocity, increase kV
   7. If the velocity overshoots the target velocity, decrease kV
   8. If the position lags behind the target, increase kP slightly
   9. If the mechanism overshoots the setpoint, reduce kV (or, if that doesn't fix it, kS)
   10. If the motion is stable, smooth, and consistent, the the position and velocity targets are reached consistently, the mechanism doesn't overshoot the setpoint, and the MAXMotion Position Setpoint doesn't seem to "jump", reduce the Allowed Profile Error, increase the Cruise Velocity, or increase the Max Acceleration slightly
   11. Repeat this process until you have the speed, smoothness, and accuracy that you want

### What does "good tuning" look like?

A well-tuned MAXMotion controller will:

* Track position, velocity, and acceleration closely and accurately
* Respond quickly to a change in setpoint
* Not stutter or reset
* Move smoothly and in a controllable way
* Move quickly
* Not overshoot the setpoint
* The acceleration will be set as high as is smooth without hitting the current limit
* The velocity will be set as high as is achievable and smooth
* The allowed profile error will be as small as possible

## Using MAXMotion

After tuning your constants, calling MAXMotion is as simple as passing in the setpoint to the controller.

{% tabs %}
{% tab title="Java" %}

```java
m_controller.setSetpoint(setPoint, SparkBase.ControlType.kMAXMotionPositionControl);
```

API Docs: [setSetpoint](https://codedocs.revrobotics.com/java/com/revrobotics/spark/sparkclosedloopcontroller#setSetpoint\(double,com.revrobotics.spark.SparkBase.ControlType\))
{% endtab %}

{% tab title="C++" %}

```cpp
using namespace rev::spark;

m_controller.SetSetpoint(setPoint, SparkBase::ControlType::kMAXMotionPositionControl);
```

API Reference: [SetSetpoint](https://codedocs.revrobotics.com/cpp/classrev_1_1spark_1_1_spark_closed_loop_controller#aefb8aa2d8ea8533a8e726f58c58facc9)
{% endtab %}
{% endtabs %}

### Migrating from Smart Motion <a href="#migrating-from-smart-motion" id="migrating-from-smart-motion"></a>

{% hint style="warning" %}
As Smart Motion and MAXMotion Position Control use different underlying control methods, all PID constants will need to be re-tuned from scratch.&#x20;
{% endhint %}

Smart Motion used a different method for smooth second-degree motion control, but MAXMotion can be applied anywhere Smart Motion was previously. Maximum velocity and acceleration constants may be transferable, but should be tested with caution. All other constants will need re-tuned from scratch, including all PIDs.

MAXMotion has several improvements over Smart Motion, and should offer better consistency, a better tuning experience, better position retention, and an all-around better user experience. It is highly recommended to migrate all systems using Smart Motion to MAXMotion.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.revrobotics.com/revlib/spark/closed-loop/maxmotion-position-control.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
