We added a little monitor to our control thread (java), and was a bit surprised to find that it was usually taking over 5ms to execute fully, over the allotted amount of time that we allowed it (200hz execution rate, notifier triggered). I recently removed all the CANTalon gets and sets from it (we have a sim layer that allows all the function calls to go to a dead end if no talon is attached), and suddenly our control thread is taking a mere .15ms to execute, a 97% reduction in thread usage, even though all the rest of our logic is running, but without any legitimate numbers or outputs.
My anecdote-tier observation may be flawed (might’ve accidentally gotten rid of something else along the way, I have to investigate more scientifically to say for sure), but it makes me wonder, has anyone bench marked how much time the various CANTalon functions take to execute? Am I using them improperly for my application? Any advice to help address this sort of thing?
With the source code now closed, it’s much harder to tell, but for the last 2 years, any function except for Get() and Set() cause a 1ms sleep and a context switch. In addition, even Get() and Set() have an ~150us RPC delay, which adds up much quicker then you think.
I had a few teams this year calling SetControlMode() every loop, and this would cause horrible lag. Switching this to only be called when the mode changed fixed their lag issues. So when using CAN Talons, be careful calling anything except Get() and Set() in a fast loop, and don’t call Get() or Set() too many times even in that loop.
For this reason, 254 is now using a “LazyCANTalon” class we wrote that caches more state and prevents hammering the API with RPC calls.
I also suspect that the driver has improved here somewhat, since we are still making O(~a dozen) non Get()/Set() calls per 5ms control iteration and hitting our deadlines pretty consistently.
Yeah that’s very possible. I don’t know exactly what changes were made this off season for that. They might have removed the Thread.sleep() calls, which were the cause in the past of the issues. We also had some decent improvements in the RPC calls at the NI level, which definitely help.
Everything is a bit dispersed and abstracted about so it’s hard to post the important parts of code without just uploading a sizable chunk of the project, but outside of generic .set() (like 8 of those per control cycle) function calls, I’m only using one other function,
this.turretTal.getEncPosition()
(two calls per loop). I’m not doing any repeated calls outside of the control loop, only the very occasional .set() and calls for generic things like turning on a harvester motor.
We are also doing a
pdp.getTotalCurrent()
and a
pdp.getVoltage()
200 times per second in the control thread for logging and for vbus compensation, though I don’t think they are a problem as I ran the test earlier where I saw the 97% reduction in loop time with those calls.
The majority of our telemetry comes through the roborio, our drivetrain and flywheel encoders are read by the WPIlib encoder and counter class on the RIO, which seems to be working nicely.
Is it just a layer ontop of the CTRE libs, or a replacement? How and how much does it improve performance? Is it something you’d recommend looking into?