How to SetSafetyEnabled(false) on SparkMax

Hello folks,
We are tryiing to disable safety mode on the SparkMax Controllers.
The command to do this should be SparkMaxLeft -> SetSafetyEnabled(false) but when we compile this we get…

sparkMaxLeft->frc::MotorSafety::SetSafetyEnabled(false);

// sparkMaxLeft->MotorSafety::SetSafetyEnabled(false);

error: ‘frc::MotorSafety’ is not a base of ‘rev::CANSparkMax’
sparkMaxLeft->frc::MotorSafety::SetSafetyEnabled(false);
^~~~~~~~~~~~~~~~

WE really need to have a solution to this.
Any options?

md

1 Like

Does sparkMaxLeft->SetSafetyEnabled(false); work? Calling base class functions in C++ doesn’t require specifying the base class.

We tried, just
sparkMaxLeft->SetSafetyEnabled(false);

as well, (actually this is what we tried first), and while Intelisence suggests that it is valid via autocomplete, when we try to compile it, it fails.

We get the same message that SetSafetyEnabled is not a
is not a base of ‘rev::CANSparkMax’

Relevent Code segment.

sparkMaxLeft.reset(new rev::CANSparkMax(7,rev::CANSparkMaxLowLevel::MotorType::kBrushless));

sparkMaxLeft->SetSafetyEnabled(false);

and the error…

…Subsystems\DriveSubsystem.cpp:54:19: error: ‘class rev::CANSparkMax’ has no member named ‘SetSafetyEnabled’
sparkMaxLeft->SetSafetyEnabled(false);
^~~~~~~~~~~~~~~~

Oh. That’s because it doesn’t inherit from MotorSafety and doesn’t implement that function itself. In that case, I don’t know how to disable it. Are you sure you need to?

Yes, unfortunately we absolutely have to disable it. We are using the PID functions of this controller, and so we are setting a reference position, and letting the motor hunt to that postion. During which time, the motor will not get updated in 100ms so the watchdog is kicking in and killing the operation of the action.

Anyway to get this function implemented?

md

Can’t you continuously set the same position, so it will go to that position and also feed the safety watchdog?

We can certainly give this a try, Less elegant but it may work.

The general rule is that all outputs should be set to some value every calculation cycle. If their state has not changed, then the same output is sent to the motor. If you do not update the output value, then the motor safety watchdog assumes you forgot or your code crashed, and correctly disables the motor.

There’s no motor safety timeout to actually disable with the CANSparkMax. There’s a heartbeat that tells the controller the robot code is still alive, but there’s only one of those and it runs in a separate thread. Furthermore, the set calls have no effect on whether that heartbeat is sent. If the output is disabled, it must be from logic in the controller firmware rather than the roboRIO software.

Did you make an instance of SparkMax somewhere on accident? The PWM version of the class has a Watchdog timeout after 100ms, but not CANSparkMax.

As it relates Motors, we only have CANSparkMax, not PWM variants connected. I will double check to make sure we did not incorrectly invent a pwm constructor. (I just checked, only CANSparkMax exist).

Assuming that we have not errored, and we have only CANSparkMax motor objects defined, are you suggesting that simply, in a command based Execute() block that repeating the SetReference call with the desired position will NOT actually reset this "non existent " timer.

I will try Peter’s suggestion and report back on my progress.

Repeating the SetReference() call should be a successful workaround. What I’m saying is that CANSparkMax doesn’t have any timeouts built in, so any timeouts would have to occur in the spark firmware. That means the roboRIO would never print a message about it. If you saw a timeout message specifically referencing 100ms, that would be from a PWM motor controller instance rather than CANSparkMax.

Thanks, we will take another look at the timeout message and If I can capture it before I deploy the next version of the code I will share.

I should have something to report tomorrow. Thanks everyone for your assistance.

md

ok folks, see below. and our symptoms.

We have a command that prints out the encoder values, and a command that will set the position 80 rotations forward from where we are at.

By setting the reference postion repeatly in execute, the command DOES work as expected, however during the run, we recieve a timeout related to the differental drive.

What we suspect is happening is that we have a side effect of having a differental drive that is running, but when we “take over” the motors, the differential drive class feels starved for attention.

when it times out, it has the effect of reseting the sparkmax encoders back to zero. The same effect if we reboot the rio.

We have just commented out our differential drive constructor and will report if this settles things down. If it does, we have to figure out why this is happening.

md

FRC: Robot radio detection times. NT: server: client CONNECTED: 10.7.72.223 port 54586
encoderL:0
encoderR:0
ERROR -6 A timeout has been exceeded: DifferentialDrive… Output not updated often enough. Check [MotorSafety.cpp:101]
Error at Check [MotorSafety.cpp:101]: A timeout has been exceeded: DifferentialDrive… Output not updated often enough.
at frc::MotorSafety::Check()
at frc::MotorSafety::CheckMotors()
at frc::DriverStation::Run()
at std::thread::_State_impl<std::_Bind_simple<std::_Mem_fn<void (frc::DriverStation::)()> (frc::DriverStation)> >::_M_run()
at /usr/lib/libstdc++.so.6(+0x9c188) [0xb5d08188]

encoderL:-0.047619
encoderR:0.0238095
encoderL:25.7617
encoderR:-27.6427

ERROR -6 A timeout has been exceeded: DifferentialDrive… Output not updated often enough. Check [MotorSafety.cpp:101]
Error at Check [MotorSafety.cpp:101]: A timeout has been exceeded: DifferentialDrive… Output not updated often enough.
at frc::MotorSafety::Check()
at frc::MotorSafety::CheckMotors()
at frc::DriverStation::Run()
at std::thread::_State_impl<std::_Bind_simple<std::_Mem_fn<void (frc::DriverStation::)()> (frc::DriverStation)> >::_M_run()
at /usr/lib/libstdc++.so.6(+0x9c188) [0xb5d08188]

encoderL:0.190476
encoderR:-78.1217

removing the differntial drive solves this problem. All works, EXCEPT we cant drive the robot now.

Any ideas on how to toggle differential drive on / off?

md

We have made some progress.
Before we run the command that sets the reference position, we

differentialDrive.reset();

and then, after the command is completed, we rebuild the differential drive using the original command that we created the drive in the first place.

differentialDrive.reset(new frc::DifferentialDrive(*sparkMaxLeft, *sparkMaxRight));

This can’t be the way that we should be doing this.

I think we have established that in this case this issue is not specifically a SparkMax issue, and if we were using Talons, or virtually any other motor controller we would likely have the same issue where the drive would want to be fed.

As a matter of review, the code has a drive subsystem, with a default command which is the command that reads a joystick and feeds these values to an arcade drive method.
Separately in the drivesubsystem, we have essentially move motor commands via a setreference that move the motors to the desired position.

When we don’t have a differential drive defined, we do not receive any timeouts. But if we have an active differential drive AND our other command that wants to move the motors, the drive gets starved and it complains with the errors shown above, and has the effect of also resetting the SparkMax integrated encoder back to zero.

It appears the issue I am experiencing may be noted here in the post below.

Peter, is this the same issue? If it is resolved as noted, should I simply update wpilib on the programming pc?

It looks like the safety object is in the based class of DifferentialDrive. Have you tried doing
differentialDrive.SetSafetyEnabled(false)

Admittedly this is how it all started, but based on the docs, I got focused on SeteSafetyEnabled as a motor controller , and not related to the “top level” DifferentialDrive class.

https://wpilib.screenstepslive.com/s/currentCS/m/java/l/599705-using-the-motor-safety-feature

So, I spinned my wheels a bit on this, but I have to thank each of you for assisting. We did solve the issues.

In short, yes, I just was able to set the SetSafetyEnabled(false) on the DifferentialDrive object and, providing some testing I am confident that this will work.

md