Building commands to avoid `DifferentialDrive... Output not updated often enough` errors

Over the past few years there have been a few discussions here about DifferentialDrive... Output not updated often enough errors. Sometimes they are the result of programming mistakes; sometimes they seem more fundamental.

For example consider the following situation. I want to run a driving command that drives until a specific condition is achieved (for example, reaching the end of a trajectory). Simultaneously I want to aim a turret. The time taken for both of these commands is unknown. I have a default command for the DifferentialDrive subsystem that causes it to stop in the absence of operator joystick input; and MotorSafety is enabled on the DifferentialDrive subsystem.

Let’s name a few things:
NormalDriving – the default drivebase Command; never finishes; feeds 0 to motors in absence of driver input.
DriveTrajectory – a Command that drives the trajectory; finishes when the end of the trajectory is reached; requires drivebase
AimTurret – the Command that aims the turret; finishes when the turret is aimed; requires turret
PCG - ParallelCommandGroup, SCG - SequentialCommandGroup, PRG - ParallelRaceGroup

How do I do DriveTrajectory and AimTurret simultaneously? I put them in a parallel command group, right?

doBothCommand1  = new PCG(DriveTrajectory, AimTurret).

doBothCommand1 is a command that requires the turret and the drivebase and ends when both commands’ finish conditions have been met. Unfortunately, it is also a command that leaves the drivebase watchdog unfed if the DriveTrajectory command ends before the AimTurret command does: because doBothCommand1 is the scheduled command for the drivebase until AimTurret finishes, DriveNormal (the drivebase’s default command) does not get scheduled on the Drivebase. And so, a DifferentialDrive... Output not updated often enough error occurs. If I were to enable MotorSafety for the turret subsystem, it would pretty much be guaranteed that I would get Output not updated often enough for one subsystem or the other whenever I ran doBothCommand1.

So how can this be avoided (assuming I’m not willing to disable MotorSafety for the drivebase)? I apparently need to put a NormalDriving command after the DriveTrajectory. So let’s consider

doBothCommand2 = new PCG(new SCG(DriveTrajectory, DriveNormal), AimTurret)

doBothCommand2 doesn’t cause an Output not updated often enough error; but it also doesn’t work – since DriveNormal never finishes, the parallel command group never finishes.

How about

doBothCommand3 = new SCG(new PRG(DriveTrajectory, AimTurret), new PRG(DriveNormal, AimTurret))

That works if AimTurret takes longer than DriveTrajectory, but does not work if DriveTrajectory takes longer (driving is interrupted before reaching the destination).

So, am I missing something obvious from the (new) Command framework that would let me solve this problem? And if not, what additional/different functionality could be made part of the Command framework to provide a solution for this, I believe fairly common, use case? And what if MotorSafety is enabled on the turret as well. (And as I said above, I don’t consider turning off MotorSafety a solution).

For now, tolerating the errors seems to be the best approach. When the MotorSafety reports the error it also turns off the motors which is exactly what is required. It’s just that it shouldn’t be a reported error in this case.

1 Like

Either send a 0 output to the motors or call feed.

The real solution is to turn the feature off.

2 Likes

My point was, within the Command framework, is there a way to compose commands to repeatedly send a 0 output to the drivebase in this scenario of needing to drive and do something else simultaneously? That’s what all my examples were trying to accomplish and none of them was a satisfactory solution. And I emphatically disagree with the statement that turning off MotorSafety is “the real solution”.

You can inline a RunCommand that calls feed. The command framework itself does not interact with the motor safety API.

I assume you already know that you can simply disable motor safety: m_robotDrive.setSafetyEnabled(false); ?

While it’s useful to prevent rookies from having runaway robots, pretty much no other mechanism or motor on a robot has this. We personally just disable it right away.

I understand what feed does and I understand that the command framework does not interact with MotorSafety. But I’m not seeing that a RunCommand calling feed is in any way fundamentally different from my attempts to use the NormalDriving command. Could you show how to compose commands, using Parallel, Sequential and Race composition (or something else) to accomplish the task? That is what I have not been able to do.

Do an outermost command group (I think race?) that combines the rest of what you are doing with a RunCommand that just feeds the drivetrain. The RunCommand won’t depend on any subsystem and thus will happily run in parallel with the rest of the sequence and keep the drivetrain fed whenever no other command is calling set() on it. It doesn’t hurt to call both set() and feed().

1 Like

Thank you Peter. That makes sense and was the key insight that I did not have. I’d worry about calling set though? Wouldn’t that interfere with sets being done from the actually driving command?

Don’t call set() from this “background” command (you’re right, it will interfere). Call feed().

1 Like

Thanks for this discussion and the solution.

Yes, I know about it, but we disagree about whether it is a good idea to turn it off.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.