Lately, I’ve been getting into PID loops to increase my autonomous accuracy, but after seeing multiple tutorials and forum conversations, I’ve noticed that some people used functions to put the PID loop while some made PID task and ran the task in task main. What would be a better choice and why?
While either can work well to your preference, I personally think that the best way to implement PID controls is using tasks, that way you can regulate multiple mechanisms at the same time, instead of just one at a time. This allows you to do some pretty nifty stuff in autonomous involving multiple mechanisms doing stuff simultaneously, which could shave off some time from the 15 second limit.
I would note that using too many tasks can cause unexpected behavior with the PID loop as the scheduler becomes overwhelmed. Source: First hand experience in NBN.
I prefer the more functional approach, where you have a pure
pid_calculate()
function that accepts a struct with PID config and returns the output of the motor. This has the added benefit of easily chaining with slew functions, true speed functions, etc. But whatever floats your boat, it didn’t really matter
For sure, plus the PID needs a time base and this is a good way to give the task a tick.
I wouldn’t necessarily do this, the reason being, as discussed above, PID is almost never pure PID. The PID and integrator reset, etc… that you use for a base to get from one location to the other is not the same as what you would use for a lift and the lift would not be the same as a claw. Now, if you mean just the actual calculation of the P+I+D + C equation passing in present value and a pointer to the PID strict, then yes. But there would be a lot of control code around that.
It, probably, doesn’t matter that much if you execute PID loops in multiple tasks or in a separate function calls from a single task. I personally would prefer a single task, because then there could be a single shared time synchronization section to minimize delay for issuing motor commands.
If you feel comfortable starting and stopping multiple tasks - do the tasks, otherwise using multiple function calls will work just as well.
It will be more important to make sure, as @Team80_Giraffes pointed earlier, that you insert sleep delays and do not issue motor updates more frequently than about ~20ms, because motor controllers update their power levels only at that rate (but not all motor ports are created equal).
Also, if you plan to use “D” component, you may want to take steps to do more precise timing and/or smooth your measurements, otherwise there could be a lot of noise (this was discussed back in NbN season in this PID theory thread).
Would you mind elaborating on this? I’m not sure how this sleep command thing is performed and I would like to know why it helps with PID. Does this somehow force a task manager to do things in a certain time window? or a certain order? or what? Thanks.
Basically, the Cortex can’t actually run multiple pieces of code at once. It just switches between different ones so fast that it looks like they’re all executing in parallel. However, if you have a while loop constantly spinning in your task, like you often will, there’s no “down time” left for the Cortex to switch to another task. If you add a sleep command, it gives the Cortex time to switch over to a different task and do something else.
Like @Genghis.Khan said, the Cortex has only one processor (IIRC), which means that it can only execute one instruction at a time. To allow asynchronicity, in the RobotC Kernel (and also in a PROS build), there is what’s known as a scheduler. It quickly switches between tasks when the CPU is idle, for example, when a task is sleeping. So, if you have multiple parallel tasks, you want to avoid starving the CPU, by which I mean not giving any of the other processes any idle time.
Since motor controllers update every ~20ms, in any task where you are doing anything related to motors, including calculating PID outputs, you’re gonna wanna wait anyway, since otherwise, you’re just wasting computation cycles.