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)SparkFlexm_motor=
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: position, velocity, or current) and a control mode as shown below:
API Docs: ,
API Docs: ,
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.
To run a PID loop, several constants are required. More advanced controllers require additional parameters to be set and tuned.
A PID controller has 3 core parameters or gains. For more information on these gains and how to tune them, see .
These gains can be configured on the with the closedLoop member of a SparkFlexConfigor SparkMaxConfig object as seen below:
API Docs:
API Docs:
There are several Feedforward parameters that can be used to model your system and help support the PID controller, resulting in more precise and consistent motions. These are explained on the .
API Docs:
API Docs:
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.
API Docs:
API Docs:
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.
API Docs:
API Docs:
When applying the setpoint, pass the slot number and the motor controller will switch to the appropriate config.
The MAXMotion Cruise Velocity parameter only applies to MAXMotion Position Control Mode, while MAXMotion Velocity Control Mode does not honor it in order to ensure any setpoint is reachable. This means any top-speed clamping you want to do must be done before you send the setpoint to the Motor Controller.
Cruise Velocity is in units of Revolutions per Minute (RPM) by default
Maximum Acceleration is in units of RPM per Second (RPM/s) by default
// Set the setpoint of the PID controller in raw position modem_controller.setSetpoint(setPoint,ControlType.kPosition);
// Set the setpoint of the PID controller in raw position modem_controller.SetSetpoint(setPoint,SparkBase::ControlType::kPosition);
SparkFlexConfig config = new SparkFlexConfig();
// Set PID gains
config.closedLoop
.p(kP)
.i(kI)
.d(kD)
.outputRange(kMinOutput, kMaxOutput);
using namespace rev::spark;
SparkFlexConfig config;
// Set PID gains
config.closedLoop
.P(kP)
.I(kI)
.D(kD)
.OutputRange(kMinOutput, kMaxOutput);
SparkFlexConfig config = new SparkFlexConfig();
// Set PID gains
config.closedLoop.feedForward
.kS(s)
.kV(v)
.kA(a)
.kG(g) // kG is a linear gravity feedforward, for an elevator
.kCos(g) // kCos is a cosine gravity feedforward, for an arm
.kCosRatio(cosRatio); // kCosRatio relates the encoder position to absolute position
using namespace rev::spark;
SparkFlexConfig config;
// Set PID gains
config.closedLoop.feedForward
.kS(s)
.kV(v)
.kA(a)
.kG(g) // kG is a linear gravity feedforward, for an elevator
.kCos(g) // kCos is a cosine gravity feedforward, for an arm
.kCosRatio(cosRatio); // kCosRatio relates the encoder position to absolute position
SparkMaxConfig config = new SparkMaxConfig();
// Set MAXMotion parameters
config.closedloop.maxMotion
.cruiseVelocity(cruiseVel)
.maxAcceleration(maxAccel)
.allowedProfileError(allowedErr);
using namespace rev::spark;
SparkMaxConfig config;
// Set MAXMotion parameters
config.closedloop.maxMotion
.CruiseVelocity(cruiseVel)
.MaxAcceleration(maxAccel)
.AllowedProfileError(allowedErr);
SparkFlexConfig config = new SparkFlexConfig();
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);
using namespace 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);
// Use the PID gains in slot 0 for position control
m_controller.setSetpoint(setPoint, ControlType.kPosition, ClosedLoopSlot.kSlot0);
// Use the PID gains in slot 1 for velocity control
m_controller.setSetpoint(setPoint, ControlType.kVelocity, ClosedLoopSlot.kSlot1);
using namespace rev::spark;
// Use the PID gains in slot 0 for position control
m_controller.SetSetpoint(setPoint, SparkBase::ControlType::kPosition, ClosedLoopSlot::kSlot0);
// Use the PID gains in slot 1 for velocity control
m_controller.SetSetpoint(setPoint, SparkBase::ControlType::kVelocity, ClosedLoopSlot::kSlot1);