Closed-loop control in REVLib is accessed through the SPARK's closed loop controller object. This object is specific to each motor and contains all the methods needed to control your motor with closed-loop control. It can be accessed as shown below:
// Initialize the motor (Flex/MAX are setup the same way)SparkFlex m_motor =newSparkFlex(deviceID,MotorType.kBrushless);// Initialize the closed loop controllerSparkClosedLoopController m_controller =m_motor.getClosedLoopController();
usingnamespace rev::spark;// Initialize the motor (Flex/MAX are setup the same way)SparkMax m_motor{deviceID, SparkMax::MotorType::kBrushless};// Initialize the closed loop controllerSparkClosedLoopController m_controller =m_motor.GetClosedLoopController();
To drive your motor in a closed-loop control mode, address the closed loop controller object and give it a set point (a target in whatever units are required by your control mode: , , or ) and a control mode as shown below:
This will run your motor in the provided mode, but it won't move until you've configured the PID constants.
// Set the setpoint of the PID controller in raw position modem_controller.setReference(setPoint,ControlType.kPosition);
The provided example above runs the motor in position control mode, which is just a conventional PID loop reading the motor's current position from the configured encoder and taking a setpoint in rotations.
Use caution when running motors in closed-loop modes, as they may move very quickly and unexpectedly if improperly tuned.
PID Constants and Configuration
To run a PID loop, several constants are required. For a more advanced controller, even more parameters need to be set and tuned.
This section uses concepts about configuration which is discussed here. For more information about SPARK specific configuration, see this page.
PID Parameters
A PID controller has 3 core parameters or gains. For more information on these gains and how to tune them, see Getting Started with PID Tuning.
These gains can be configured on the with the closedLoop member of a SparkFlexConfigor SparkMaxConfig object as seen below:
SparkFlexConfig config =newSparkFlexConfig();// Set PID gainsconfig.closedLoop.p(kP).i(kI).d(kD).outputRange(kMinOutput, kMaxOutput);
The SPARK family of motor controllers also offer an F term, which is a velocity feed-forward. This is unique to each type of motor, and can be calculated by taking the reciprocal of the motor's velocity constant (Kv), in other words 1/Kv.
The Kv values for the NEO family of Brushless Motors are documented within each motor's specifications table: NEO Vortex, NEO V1.1, NEO 550
For a NEO Vortex, this value is 1/565. This is only needed when running a velocity-based control loop (velocity mode, Smart Motion, and Smart Velocity). The F parameter can be set as seen below:
SparkMaxConfig config =newSparkMaxConfig();// Set kFFconfig.closedLoop.velocityFF(1/Kv);
The F parameter should only be set when using a velocity-based PID controller, and should be set to zero otherwise to avoid unwanted behavior.
MAXMotion Parameters
MAXMotion has parameters that allow you to configure and tune the motion profiles generated by MAXMotion. The parameters can be set through the maxMotion member of the closedLoop config.
SparkMaxConfig config =newSparkMaxConfig();// Set MAXMotion parametersconfig.closedloop.maxMotion.maxVelocity(maxVel).maxAcceleration(maxAccel).allowedClosedLoopError(allowedErr);
Smart Motion is deprecated and marked for removal. It is recommended to use MAXMotion instead.
Smart Motion and Smart Velocity have parameters that allow you to configure and tune the motion profiles that they generate. The parameters can be set through the smartMotion member of the closedLoop config.
SparkMaxConfig config =newSparkMaxConfig();// Set Smart Motion and Smart Velocity parameters.config.closedloop.smartMotion.maxVelocity(maxVel).minOutputVelocity(minVel).maxAcceleration(maxAccel).allowedClosedLoopError(allowerErr);
usingnamespace rev::spark;SparkMaxConfig config;// Set Smart Motion and Smart Velocity parameters.config.closedloop.smartMotion .MaxVelocity(maxVel) .MinOutputVelocity(minVel) .MaxAcceleration(maxAccel) .AllowedClosedLoopError(allowerErr);
Maximum Velocity is in units of Revolutions per Minute (RPM)
Maximum Acceleration is in units of RPM per Second (RPM/s)
Slots
The SPARK MAX and SPARK Flex each have 4 closed-loop slots, each with their own set of constants. These slots are numbered 0-3. You can pass the desired as an argument to each of the applicable configurations.
SparkFlexConfig config =newSparkFlexConfig();config.closedLoop// Set PID gains for position control in slot 0.// We don't have to pass a slot number since the default is slot 0..p(kP).i(kI).d(kD).outputRange(kMinOutput, kMaxOutput)// Set PID gains for velocity control in slot 1.p(kP1,ClosedLoopSlot.kSlot1).i(kI1,ClosedLoopSlot.kSlot1).p(kD1,ClosedLoopSlot.kSlot1).velocityFF(kFF1,ClosedLoopSlot.kSlot1);
usingnamespace rev::spark;SparkFlexConfig config;config.closedLoop // Set PID gains for position control in slot 0. // We don't have to pass a slot number since the default is slot 0. .P(kP) .I(kI) .D(kD) .OutputRange(kMinOutput, kMaxOutput) // Set PID gains for velocity control in slot 1 .P(kP1, ClosedLoopSlot::kSlot1) .I(kI1, ClosedLoopSlot::kSlot1) .D(kD1, ClosedLoopSlot::kSlot1) .VelocityFF(kFF1, ClosedLoopSlot::kSlot1);
When applying the setpoint, pass the slot number and the motor controller will switch to the appropriate config.
// Use the PID gains in slot 0 for position controlm_controller.setReference(setPoint,ControlType.kPosition,0);// Use the PID gains in slot 1 for velocity controlm_controller.setReference(setPoint,ControlType.kVelocity,1);
usingnamespace rev::spark;// Use the PID gains in slot 0 for position controlm_controller.SetReference(setPoint, SparkBase::ControlType::kPosition,0);// Use the PID gains in slot 1 for velocity controlm_controller.SetReference(setPoint, SparkBase::ControlType::kVelocity,1);