CSCE 436/836: Embedded Systems
Lab 4: PID, Serial Console, Scheduler


Instructor: Carrick Detweiler
carrick _at_ cse.unl.edu
University of Nebraska-Lincoln
Spring 2011

Started: March 29, 2011
Due: Friday, April 8, 2011 at 5pm

1  Overview

This lab will consist of three main parts. As always, they are somewhat interrelated, so you should read through the complete lab before starting and plan how to approach the lab. In the first part of the lab, you will interface with a serial console library that gives you an easy way to include commands that you can execute over the serial port or radio. Next, you will learn to use a task scheduler library, which will allow you to execute tasks at specific intervals (milliseconds or seconds). Both of these libraries are from SEAMos, http://code.google.com/p/seamos/, which is a light-weight, configurable embedded operating system I have developed. Finally, you will implement proportional, integral, derivative (PID) control for the rotation of the hovercraft.

2  Safety

Remember and review the safety instructions from the previous labs.

3  Serial Console [30pts.]

The serial console provides a console/terminal-like interface for embedded systems. It lets you type in different commands (with arguments) to execute, similar to the setup you created in previous labs to allow rebooting the board and also commanding individual thrusters. You have also seen me use it in class and in some sample compiled code I sent you.
The console system consists of 4 files, console.h, console.c, console_custom.h, and console_custom.c. You should only need to modify the latter two files, although feel free to explore the other two files, which have the core code, to see how the console system functions. You will find examples of how to use the console system in console_custom.c. Note that console_custom.c assumes that you have a file uart.h that includes the standard-named uart functions we have been using and defaults to sending on both ports 0 and 1. This can be changed by editing console_custom.c.
The idea behind the console system is that you add or register functions that you want to be able to execute from the console. When you add them, you give a long name and short name that, when typed, will cause execution of a particular function. You also give a short description of any parameters and general help info. These are used when you type h or help from the console to output a set of available commands.
It will be up to you to read through the source files (mainly console_custom.c) to determine how to complete the following tasks. These should be completed on the 5V Atmel; you can optionally add the console system to the 3.3V processor if you find it useful. The first step will be to add the source files to your existing SCons build scrips.
Question: Create a console command to test each of the thrusters by briefly turning each one. Call it testthrust and have a short command of tt. This function should briefly turn on each thruster (one at a time) so that you can see that they all are working. How did you initialize the console system? How did you tell it to process commands? How did you add a command?
Question: Create a console command to set the lift thruster to a specific thrust level from 0-100% (as an argument). Call this lift and have the short command be l. You may want to remap 0 thrust to the minimum thrust level that turns on the thruster and 100 to the maximum allowed thrust level. Describe how you were able to obtain the argument on the command line.
Question: Modify the lift command so that if no lift value is given, it will report the current lift level. How did you do this?
Implement similar functions to control each of the other thrusters. This is useful for testing, but not so much for direct hovercraft control. To control the hovercraft, create console command that switches from the console interface to a direct keyboard command interface (which you have already implemented). You should be able to switch back and forth between the two modes.
Question: How did you enable switching between the console control and direct control modes?
Question: Finally, implement console commands to read the sensors on the hoverboard (gyro, current, voltage, etc). Describe these functions.

4  Scheduler [30pts.]

A scheduler allows scheduling events to occur at a particular time or to repeat at a particular interval. You have been given a non-preemptive, multi-tasking scheduler. This means that you can schedule multiple tasks, but only one will run at a time. In addition, it will run until it completes, potentially blocking other tasks that would like to run. Because of this, you should make sure that no task runs for an extended period of time as this will starve any other tasks that are trying to execute.
The scheduler consists of the main schedule.h and schedule.c, as well as scheduleConsoleCmds.h and scheduleConsoleCmds.c which provide some console commands to add or delete events from the scheduler queue. Add these to your build system and make sure to initialize them.
The scheduler requires that scheduleProcessMS(ms) is called approximately every millisecond and is passed an argument which is the current time, since startup, in milliseconds. Use one of the timers to generate an interrupt every millisecond. In this interrupt, increment a variable that will serve as the global time in milliseconds. You should then call scheduleProcessMS(ms) from your main while loop (not in the interrupt). Pay close attention to the fact that you need to make sure that the global millisecond counter continues to increment, even when scheduleProcessMS(ms) is running. In addition, the ms variable needs to be carefully handled to prevent it from being updated at the same time that scheduleProcessMS(ms) is using it.
Question: Describe how you made sure your ms counter continually updated while scheduleProcessMS(ms) was running and how you made sure that the ms value was always valid when passed to scheduleProcessMS(ms). Why would it be a bad idea to call this function directly from the interrupt code?
Similarly, there is a function scheduleProcessSec(sec) that handles events that are scheduled with second granularity. You can use the millisecond counter (divided by 1000) as input to this function. Setup your main loop so that both the millisecond and second schedule processing functions run.
Question: You can schedule an event to run at a particular number of milliseconds or seconds from now or periodically. What are the functions to do this? Describe their arguments.
To be able to add events from the console, you need to add a "possible event." You can do this by using the function scheduleAddPossibleEvent(...). You can also add events or delete events from other events (an event can even delete itself).
Question: There are multiple ways to delete events. What are the methods?
Question: Create an event that blinks one of your LEDs briefly at 2Hz. How does this work?
Question: Implement a console command that uses the scheduler to drive straight for a specified amount of time. How did you achieve this?
Question: In the previous section, you created a console command that tests the thrusters by turning each one on for a short time. While it is doing this, however, nothing else can run (including scheduled events). Create a new set of events that sequentially tests each thruster. You might turn on each thruster for a short period, perhaps 250ms, and then leaves all thrusters off for 1 second before moving to the next thruster to test. Describe how you implemented these sequences of thruster tests in the scheduler without blocking other events that may be running (such as the LED blinking event). You may also want to turn on your other LED when a thruster is supposed to be on so that you will know if a thruster is not working.

5  PID Control [30pts.]

In the previous lab you had to rotate to a particular angle. Some groups did this "open loop," by just creating a mapping for how long it takes to rotate a particular angle and just rotating for that time. Other groups use the gyro to obtain some feedback. This is what we are going to do in this section. We will do this by implementing a proportional, integral, derivative (PID) controller for rotation. This will enable your hovercraft to hold a particular angle even when it is disturbed (e.g. if you try to turn it, or to compensate for rotational moments caused by translational thrusters). You can read about PID control on the wikipedia page: http://en.wikipedia.org/wiki/PID_controller.
Here is a brief summary. You should make sure to read this whole section before starting as some of the work for the later questions will be helpful in answering the earlier ones. If you have a target angle at and a current angle (as read by your integrated gyro data) of ai, then you can control the rotational thrust, r, of your hovercraft according to: r = P(a_t-a_i) P is the proportional scaling term of the controller (and can be positive or negative). With a P controller, if you are far off from your target angle, it will have high thrust and when it gets closer the thrust will decrease. This can work well, but if P is too low it will never reach the target and if it is too high, it will overshoot and oscillate.
By introducing a derivative, D, term oscillations can be damped: r = P(a_t-a_i) + D(a_i-1-a_i) where ai−1 is the angle from the previous time step and D is the derivative scaling term of the controller. The value (ai−1−ai) is basically a numeric derivative of the error and it tends to slow how fast the output term r will change (damps oscillations).
A purely PD controller often works well and I recommend that you first try a PD controller before trying to introduce an integral, I, term. The problem is that a PD controller will not always achieve the set point 1. Adding an integral term can ensure that you reach your target, but at the cost of potentially adding oscillations and having to deal with issues such as windup. Adding the I component will yield: r = P(a_t-a_i) +I(integral_i) + D(a_i-1-a_i) where, integrali = integrali−1 + (at−ai), and integral0 = 0. The windup problem is that if there is an offset (e.g. you hold your hovercraft in one position and don't let it rotate for a while), then the integral term will continue to grow unbounded. So typically, you need to bound the integral term by a maximum value to mitigate this problem.
In essence, a PID controller is not too difficult, however, there are a number of practical issues that you must address when using one. The first, is tuning the PID values. Wikipedia has a number of suggestions as to how to tune the controller. My preferred method is to first try a PD controller (almost always works better than a purely P controller). The idea is that you first set D=I=0 and then tune P until it oscillates slightly, then add D until the oscillations are damped. On the hovercraft, the I term probably isn't needed, but if you find that there is an offset from the final position, then you can add a little bit of I to make sure it achieves the target.
Question: Did you need to use an I term? What were your final values for the PID parameters?
There are a number of other practical issues when controlling rotational systems by degrees. The first, is that there is a discontinuity between 0 and 360 degrees. The second, is if your target is 180 degrees off from your current position, should you go clockwise or counter clockwise? The problem is exacerbated if there is sensor noise (you could end up oscillating 180 degrees off of your target angle). To solve the second problem, one approach is to have a fixed thruster output whenever you are further than 90 degrees off of the target and then to switch to your PID control when you are closer to your target.
Question: Describe how you addressed rotations of near 180 degrees from your current angle.
To address the discontinuity between 0 and 360, you can always work in terms of relative angles when doing control instead of absolute angles. One way to think about this is to always have your target be 180 degrees. To rotate, you then just set your current angle to be offset from 180 degrees. For instance, if you are currently at 350 degrees and you want to go to 30 degrees, you can set your target angle to 180 degrees and set your current angle to 140 degrees. In essence, you are then working in relative angles far away from the discontinuity. There are other approaches to this as well.
Question: Describe how you addressed rotating around an absolute angle of 0 degrees.
Another problem to address is deadbands. If you leave your PID controller on all the time, then the hovercraft will maintain its angle. However, very small offsets may cause current to go to the thrusters without them actually moving. This is a waste of energy. Thus, it is good if you have deadbands so that the thrusters will never just be on a very small amount (and not turning). You can implement this in the PID controller or in the functions that control your thrusters.
Question: Create a new group of console commands (sub-commands) to set the P, I, and D values individually (call them setp, seti, and setd). If no value is given, then report the currently set value.
Question: Create a new function and console command that takes an offset angle and rotates that particular number of degrees, call the console command rotate or rot for short. It should take at least plus-minus 180 degrees. Describe how you implemented this function.
Question: Have your PID controller run as a scheduled event. It can run at up to 1KHz if run every millisecond. Do you need it to run this fast? What is the minimum frequency you can run it at and get good results?
Question: What happens if the PID controller does not run at the scheduled time? This could occur if some other event runs too long. How can you compensate for this?
Question: Plot outputs of your current angle, target, and rotation thrust levels for different PID values when changing the target angle. Make sure to include an output from your final PID controller. Also include plots from a purely P controller when it has a value that causes oscillation and when it does not cause oscillation. Include any other plots that you find useful.
Question: Implement a console command to drive an equilateral triangle. Do this by enabling the angle PID controller and then scheduling a series of events that enables the forward thruster, followed by a 120 turn, etc. Since the PID controller is always running, it will compensate for any angular drift that your forward thruster may cause.

6  To Hand In

You should designate one person from your group as the point person for this lab (each person needs to do this at least once over the semester). This person is responsible for organizing and handing in the report, but everyone must contribute to writing the text. You should list all group members and indicate who was the point person on this lab. Your lab should be submitted by email before the start of class on the due date. A pdf formatted document is preferred.
Your lab report should have an introduction and conclusion and address the various questions (highlighted as Question: ) throughout the lab in detail. It should be well written and have a logical flow. Including pictures, charts, and graphs may be useful in explaining the results. There is no set page limit, but you should make sure to answer questions in detail and explain how you arrived at your decisions. You are also welcome to add additional insights and material to the lab beyond answering the required questions. The clarity, organization, grammar, and completeness of the report is worth 10 points of your lab report grade.
Question: Please include your code with the lab report. Note that you will receive deductions if your code is not reasonably well commented. You should comment the code as you write it, do not leave writing comments until the end. I recommend structuring your code such that for every section of this lab, a different function is called from the main loop. Then you will be able to comment out just one function to change between sections in the lab and you won't have to delete working code from previous parts of the lab.
Question: For everyone in your group how many hours did each person spend on this part and the lab in total? Did you divide the work, if so how? Work on everything together?
Question: Please discuss and highlight any areas of this lab that you found unclear or difficult.

Footnotes:

1Think of a PD controller as pulling a car up a hill with a spring, no matter how stiff the spring, if you put one end where you want the car to end up, it will never get there.


File translated from TEX by TTH, version 3.89.
On 29 Mar 2011, 10:30.