How to make graphs to help tune PID

Hello vex forum. I would like to ask about how to make a graph of sensor values with respect to time to help tune PID.

Recently I have been working on learning PID and the tuning of the loop, and find the method very helpful regulating autonomous routines. So I plan to use it to hold lift and intake while driving. I have seen posts about PID tuning, including many of jpearman’s, that use graphs of sensor value with respect to time to compare among different constants. I would like to ask how to do this. Can this be done in robotc? I am using robotc currently. Do you need to use other software to work with exported data?

I think using graphs to tune PID will greatly help VEX competitors, as we commonly lack tools to measure values required for zi method.

Thank you!

You could write to the terminal window and copy it to excel. I like to export in the CSV format to make it really easy to import into excel.

Actually tuning the ZN method does not require ANY external tools. All you need to do is tune the P value, and substitute it in for the kU value, and then you just have to listen to the oscillation of the motors (which is pretty audible once you’ve got kP done.) Then time the interval between oscillations and you get your tU Value!:slight_smile:

So it won’t be very helpful in the short term, but this is what I use.

I stream variables (error, target, position etc. ) from the cortex and display real time in a scrolling graph. Here is the output from my triple lift, I’m still developing the trapezoidal motion profile code that will be released one day, it makes for much more accurate PID control.

You can of course do this non-real time by capturing the same data and using in Excel as Elliot suggested.

1 Like

The easiest / no hardware way to do this would be to utilize the text TTY that comes through the programming cable.

SO basically, when the programming cable isn’t uploading code, on Windows it shows up as a COMM port (assuming you have the proper driver installed), or on unix-based systems, it’ll show up as a /dev/ttyXXX file thingy.

You can send bytes of data at a time, which just so happens to cover the ASCII set as char is a byte. So, in simple terms, you can send text down the pipe, and on the other end you can interpret that text however you want.

A really simple format could look like so…

[value][newline]
[value][newline]
[value][newline]

Or you could figure out something more complicated, which is basically what I’m doing with C4.

Either way, there is no easy / standard way to get arbitrary data out of the Cortex, nor is there a easy out of the box way to graph said data.

It’s something I want to change, there’s just this whole having to actually go to college thing in my way.

-Cody

Thanks everyone. I think using excel to graph is a good way for me to do this. That was helpful.

And Cody, I am just a guy who started programming a month ago… I feel that it was even a miracle to pull parts off jpearman’s PID controller and construct my own crappy one… I’ll spend some time to try to understand your post.

And just an additional question, how well does the cortex handle two PID loops, a main control loop and a few simple background loops all together? I don’t wanna over stress my cortex.

TASKS

Look up robotc task api
I’m on my phone

Edit: realized you asked how well.
Pretty well is the answer. I haven’t hit any issues with 4 or 5 tasks running at once.

Don’t worry about it, not a problem as long as you have a few mS of delay in each task.

1 Like

Thanks for the response. I am doing 25 ms for all the loops.

I would agree, printing the data in a csv format would be rather easy to plug into excel. It’s short sweet and simple.

Don’t worry about my post. I link things for completeness. I’ve found that learning to program is one of those one foot in front of the other type things at first (even for me).

You have a simple problem and you now have a simple solution to that problem. I’d go grab the data and throw it into excel, and I’d be happy that in the end I/you are going to get the PID loop tuned like you need (sorry for the tense change there).

The Cortex is 90 MIPS, or 90 million instructions per second. To put this into perspective, the MSL rover known as Curiosity has only about 400 MIPS of computational power. That is to say, it has about the computing power of four VEX Cortex’s.

So in one way the Cortex is weak, I mean that phone in your pocket can dance circles around it, but in another way, that Cortex could probably run the critical systems on a billion dollar robot currently functioning on Mars (and arguably the best robot ever built by mankind).

I’ve never managed to properly stress a Cortex. You’d have to run some pretty nasty algorithms in order to really max one. Something like a sort operation on a large list or image processing, etc.

In terms of ops, there are plenty. It’s more time that’s a concern. You have to understand that time stuck waiting for something to finish is basically wasted CPU time. It’s known as blocking, which I don’t want to get into right now because I’m tired.

Anywho, the wait() / delay() / sleep() functions are kind of a neat way of telling the OS that whatever code you have running can safely be suspended for X ms. The OS can then run other “tasks” or pseudo “threads” while the code is effectively snoozing.

So a good way of writing, say multiple PID loops might be to run each of them in their own task, and to make sure that they all sleep for at least 1ms every iteration.

1ms is actually a lot of time for a processor. In fact in 1ms (or 1/1000 of a second), the Cortex can do 90,000,000 (90 million) / 1,000 things. That’s 90,000 operations. While one line of code may end up being possibly MANY ops, it’s still a lot of things.

Generally speaking, code that updates motors ONLY can safely be run every 20ms, because motors can only be updated once every 20ms anyway, so there’s no point in updating them more often but for your PID code, it’s worth checking those sensor values as finely as possible so I would go ahead and run those at 1ms, just keep the code simple that’s all.

We’ve had four and five PID loops running in autonomous typically in two tasks.

Pulling some PID control loops into one task is also advisable for items that set the same motor values. For instance X Y and turn angle were in one task where X & Y were set for distance and rotation was adjusted to keep it straight. Each could be in its own task, but there is not necessarily a need when they are all controlling the same motors.

In sack attack, the arm and scoop moved together so they were in one task.

Sack attack (holonomic drive):
X
Y
Turn angle/Heading
Arm angle/height
Scoop angle

Toss Up PID loops:
Drive distance
Turn Angle/Heading
Arm angle/height

Skyrise PID loops:
Drive distance
Turn Angle/Heading
Arm angle/height

You may want to have toggles to turn on/off each PID controller within the task as well. The task still runs but the error calc and motor setting is skipped as the driver’s joysticks are controlling things.

The trick in autonomous is knowing when to stop the current activity and start on the next activity because the arm and driving are independent tasks. If there’s any type of overshoot, you may have to wait for steady state at the target value versus arriving (and immediately leaving) the target value. That wastes precious time.

Thanks Cody. That was helpful.

In fact, all my PID loops do is calculation. All the motor outputs are executed in the main loop, when buttons are not pressed.

That being said, is it fine for me to run PID loops at 1 ms and the main loop at 20 ms? Also, how do you calculate the frequency of a loop? If I run a loop at 1 ms, can we assume that it is 1000 hz? I kind of need to know this for PI.

That’s a really good question… What are the exact characteristics involved with sleeping a task?

What happens when code that is running isn’t finished in time for a task to run?

Does a delay(1) sleep for exactly 1ms? At least 1ms? At most?

etc.

** Summons a James **

See the links I posted earlier in another thread that explain multi-tasking.

sleeping for 1mS will usually sleep until the next 1mS timer tick boundary, however, if a higher priority task is running you may have to wait longer. Occasionally ROBOTC will want to run some system stuff and you may again be sleeping longer, this happens about once every 15mS. If many tasks all want to sleep for the same amount of time and are of the same priority then behavior depends on the amount of code that needs to be run, preemption of tasks at the same priority happens about once every 20mS I think.

Running a PID loop at 1mS intervals is not necessary in VEX, a good time would be perhaps 10mS. PID works best with the motors on ports 1 and 10, they can be updated far quicker than the port 2-9 motors, about 500 times per second in theory. Make the PID task a higher priority task than others.

1 Like

Thanks Jpearman. I’ll run the loops at 10mS and set the task priority.