Is There a PID Function in a Library That can be Called on ?
Hello I'm a new user with some PicAxe, PLC and Arduino knowledge and would like to move over to the P1/P2 ecosystem. I'm still looking at the example programs and studying the idea of "cogs".
I have many applications that depend on PID control but after doing a cursory search I have not found a function that can be called when needed. Have I missed that in my search of user projects and documents or are the PID controllers always written as needed by everyone?
I've done rung-by-rung PID code for PLCs and it was tedious. So I'm hoping that it might be possible to put in the set point variable, 3 constants for the PID values and a 4th output variable and call this function as many times as needed, roll, pitch, yaw, slant, skid, throttle, etc. (And include features like integral wind-up and saturation prevention.)
If this already exists then that would be infinitely less painful than writing it myself.
Thank you,
Patrick
Comments
There is a PID for the BS2 and I've seen one for the Prop P1.
What you're looking for is the old Object Exchange for the Prop1. It was a great contributor resource but was discontinued a number of years back. An archive of the files has been kept on Github of late - https://github.com/parallaxinc/propeller
I think the Prop2 edition there is mostly converted Prop1 code. Most Prop2 code proper is spread out here on the forums.
I can't recommend the PID authored by "cweber"(sp) because he uses a single coefficient for all 3 terms (can't work)
I just write my own, no rocket science. The P2 is perfect for PID I know of high-end ($$$$) motion controllers, boasting 16KHz sample rates but having to sacrifice certain features. This is a walk in the park for the P2, even with my 6 axes.
I have challenged ChatGPT to come-up with a PID, including acceleration and velocity feedforward. It gets pretty close but it's clueless when it comes to writing efficient code.
I have always used the LM629 ($30+ /axis makes the P2 a giveaway) datasheet. Note how they handle the integral...worked well for me
Craig
Boy, am I out of date
Craig
I just asked ChatGPT to write a PID based on the LM629 datasheet. It ignored the part about bit-shifting the integral. I only use FlexBasic and so I requested BASIC code:
Craig
Rochester electronics has the LM629M, but for $75
Crazy. I last used it in the early 90s. P2 can hugely out perform it and easily handle 12 axes (limited only by pin count). 16bit motor command, much faster quadrature counting, etc., etc. For what, $20?
Craig
Thanks Mickster and DigitalBob for the replies.
This certainly sounds like what I want especially if written wisely per system resources. Now how do I code it ?
At the very least it has to have wind-up prevention, I think I might have to start with PicAxe or Arduino till I'm caught up on the P1/2 thing. If I can figure out this "spin" type coding I'll post a version for all to use freely with an in depth description.
-Patrick
Anti-wind-up is simply:
My preference is to only apply integral at steady-state and so during motion, Ki=0. In the rare case where the axis following-error (during motion) is greater than ideal (usually a hydraulic servo), I close it up with AFF (acceleration feedforward) and VFF (velocity feedforward) as they are open-loop and therefore do not affect loop stability.
Another cool trick is to memorize a previously establish "safe" level of integral that can be applied instantly as the axis comes to rest and let it increment from there. I always run very tight loops and I only use Ki when Kp runs out of steam (very near to steady-state).
Also, don't forget:
In my applications, this is serious and I shut-down but others will do something like reducing the command.
Derivative:
The ChatGPT example, above, actually got the DTerm wrong (I since complained to it and it apologised and corrected it).
This is typically all we need but I maintain a history of the last 4 PrevErrors. I very rarely need this but for very low velocities or low-resolution feedback, one can achieve a smoother response.
Roll-your-own PID on the Prop is the only way to go. None of the interrupt clap-trap to be concerned with. The P2 is the dream motion-control device. It can out-perform the motion-control big-boys
Craig
Dedicate a cog to running the PID loop (pseudo code):
Craig
Your making me feel better about this.
I like the idea of cogs and have been studying them, the P1/2 silicon fabbed features are clearly superior to the STM32 and other uControllers for a lot of what we do. I loath and despise the existence of the Arduino and PicAxe but they are brain dead simple.
the "waitcnt" is the command I'm looking at now.
-Patrick
The ability to sync with the system counter in the Px series is fantastic -- no cycle counting required. The feature functions a bit differently in the two devices (achieving the same result).
I've only ever written one program that changed clock speed on-the-fly (DEF CON convention badge), so I usually create a constant based on the system frequency to set my loop time.
Spin1:
Spin2:
PASM1:
Note: PASM 1 does not allow constants larger that 511 (9 bits); you can create a timing value for low-speed loops like this:
I always have a constant in my programs called CLK_FREQ that is the system frequency
PASM2:
One of the many nice features of PASM2 is the ability to have large constants with ##.
Have fun with the P1 and the P2. They're different from what you're used to, but very nice chips and you have lots of choices how to program them Spin, C, BASIC, Forth. I do all my work in Spin with PASM mixed in where needed or advantageous.
A neat trick in the P2 is the ability to embed assembly into a Spin2 method. This is great for testing PASM2 fragments or bumping the speed of the method when required (assuming you're not running your code through the FlexSpin compiler).
Just to elaborate on Jon's example; the time period is unaffected by the loop-execution time. If 1ms is selected, the loop will run @ 1ms, 2ms, 3ms, etc.
Craig
Yep. The only rule is keeping the loop code timing shorter than the loop execution time. In many of my P1 projects I run a background loop at 1ms so that I can have a running milliseconds timer. I have found that I can get a lot of work done in 1ms, even on a P1 running interpreted Spin at 80MHz. The P2 is faster and more efficient than the P1, hence can get a lot more work done in that same millisecond.
Another great thing about the Propeller is the ability to time-test code.
Spin1:
Spin2:
At the end either segment the variable t holds the number of system ticks required to run the test code. I use this frequently to compare different approaches to a given problem.
Whoa! this is looking better and better!
So let me see if Im getting this. For time critical embedded applications (basically everything everybody wants to do) You can say : 'execute this code block which takes 456 uS, but run it in 1 mS' and without wasting the 544 uS clock ticks it will make the result available at the 1mS moment ? With those 544 unneeded uS being used else where ?
So this is superior to the "Pause and waste clock cycles", "delay" or "Wait" type barbaric commands. All this is done without traditional hardware and software ISR ?
No ISR required -- though the P2 does support interrupts.
In the synchronized loops I showed above, the loop timing will be exactly LOOP_TIX in length. If you have 450us of code, you'll sitting on the waticnt instruction for 550us for a 1ms loop. There are times when we want something to happen at a very specific rate; this is how we do it in the Propeller. If you can squeeze other useful work into that space, great, but you have to code that.
Here's a real-world example of a 1ms background loop (i.e., it runs in its own cog, separate from the main code loop) that I use in P1 projects that run on the EFX-TEX HC-8+ controller. This updates a timer variable (millis), controls a Red-Green LED with flashing and static color modes, and reads 16 digital inputs through a couple of shift-registers. It's looks like a lot of code but everything gets done in well under a millisecond on a P1 running 80MHz.
Here's another example from my servo driver for the P1. This divides the 20ms servo refresh window into 8 slots, refreshing each servo (up to 8) during the slot. The P1 counter (each cog has two) is used as a pulse generator which allows that 2.5ms window time to be used to calculate the position update for the next cycle. Simple code, but lets me control up to 8 servos with a cog, and control movement speed from one position to another.
Oh, it's mind-blowing.
In my case, I have 6 PIDs but dual-loop (12 encoders). In the PID loop, I also added a bunch of do-nothing multiplications (floating point) to allow for future bloat.
I need to double-check this when I next power-up but I'm pretty sure that I went sub microsecond (just for the heck of it) with no problem.
Not sure if you plan to use the index pulse for home referencing but this was really irritating with a megabuck big-name controller because it only ever read the encoder during the PID loop. Running at what appears to be the industry norm of 1ms, to be accurate to a single count, the recommended "homing" velocity was 250 cnts/sec. Well in my case this means < 1mm/sec on a linear axis Talk about painful. With the Prop, I can have a cog - independent of the PID cog - dedicated to rapidly scanning the encoder count and the index pulse allowing me to "home" at a more reasonable velocity...Nice! In the past, I would receive reports that my machines were "hanging-up" during the homing sequence...nope, they just take forever to find the index pulse
Once the machine is "homed", the scanning cog can be freed-up for other tasks.
Craig
Same here. I have several. It's nice to be able to reset a timer because my stuff rarely gets powered-down.
Craig
It's kinda like a timer interrupt but without the latency. The wasted clock-cycle anxiety is really a non-issue because it's one of eight processors. Like Jon, I use the remaining clock-cycles for incrementing timers and toggling an output to an external watchdog.
Craig
That's quite amusing - The limitations of being tied to the servo loop for bit-bashing. Certainly not a well thought out solution when it comes to such a tiny width as the index pulse. It also sounds like a tail of being forced to use the official libraries as well. With zero documentation on register level access.
But now you bring it up, CNCs do all seem to go extremely slow moving off the home sensor to the index mark. I hadn't really thought it was a necessity so much as just copy-catting.
>
This was the #1 priority for me and prior to going all-in with the P2, I was playing with the LS7366R which features a hardware latch.
T_Chap uses this with the P1 and with it being SPI, he has battery backup to this and also his incremental encoders so he rarely, if ever, needs to re-home. The 7366R also features a power-fail flag so he knows if the battery supply has faded.
Craig