Hello. We are working with Spark Flex, and all our coders are rookies. Is Spark Flex capable of something like “run to position” and able to hold position? Would anyone have any sample code, or point us to some sample code for spark flex running an arm. Say Button A – position 1, Button B – position 2?
Everything here is for SparkMAX, but if you just change that then it should work.
This is the rev example for position control.
This is our Arm subsystem that works quite well.
The section that runs to a position works perfectly fine right now. This is a simple P controlled arm. It should really have a gravity feed forward here, but it works fine without so I am not messing with it.
public void runToPosition(double setpoint) {
//these are included safety measures. not necessary, but useful
if(getPos() >= ArmConstants.kUpperLimit) {
left.set(0);;
System.out.println("¡TOO HIGH! ¡UPPER LIMIT!");
}
else if(getPos() <= ArmConstants.kLowerLimit) {
left.set(0);;
System.out.println("¡TOO LOW! ¡LOWER LIMIT! " + getPos());
}
else{
armPID.setReference(setpoint, ControlType.kPosition);
}
}
The hold()
method does use ArmFeedforward
.
public void hold(TrapezoidProfile.State setpoint) {
double feedforward = ff.calculate(setpoint.position*2*Math.PI, setpoint.velocity);
armPID.setReference(setpoint.position, ControlType.kPosition,0, feedforward);
}
Really appreciate it. Definitely next level. We will try to see if we can make it work. Took a look at your code… if I am reading it, is the pov the D-pad? and is it set up for the operator to use the start and d pad at the same time? Thanks.
That would be correct. Those are not really intended to be used normally, however. This is a case of start
in combination with other things being used as an override button to allow certain things to happen that should not happen normally. In this case it runs the arm under open loop control and allows it to bypass safety limits. I strongly encourage that any normal control you do should be closed loop, using a PID like in any implementation of RunArmClosedLoop
.
Whatever you do do not use “SmartMotion”. It does not close the loop on position so it cannot effectively correct for position errors.
Instead of doing that, you can generate a motion profile using WPILib’s TrapezoidProfile, and send a series of positions to the Spark Max in regular position PID mode.
It doesn’t? The documentation seems to imply it does
Edit: You are right! I was referring to the bottom of teleopPeriodic() where it has a position as the PID set point. I thought smartmotion was a MotionMagic alternative
It appears it is not
I mean technically it is intended as REV’s equivalent to MotionMagic, but as you see in your linked posts, it’s implementation is flawed.
Also we’ve implemented a fixed version of this functionality, that we’ve dubbed “smooth motion” in our library, PurpleLib.
It does all the work of generating a trapezoid profile for you, running it, and providing a function to tell when the motion is complete.
Among other features like AdvantageKit logging etc.
Hello 4. Looking at your code. Do you use through the bore encoders for this? If so is it possible to do it without?
It is entirely possible to use the through bore sensor for PID feedback. You just have to configure that as the sensor that the PID controller is going to use.
Yes, I am using a througbore encoder, but you can change that to use any encoder you like. The code here is using an absolute encoder, so if you want to use a relative one you will need to include a method to reset its position.
If your arm is chain driven make sure that there is an encoder on the arm itself and not just the NEO encoder as the chain can slip → reading is wrong → stuff breaks under immense torque.