AME 30315 Pendulum Project
- 1 Administrative Things
- 2 Introduction
- 3 The System
- 4 Getting Started
- 5 Compiling and Downloading a Program
- 6 Notes on Editing the Program to Control the Pendulum
- 7 Initial Steps
- 8 System Identification
- 9 Designing a Controller
- 10 Implementing a Controller
- 11 Hints
- 12 Project and Report Content
- 13 Additional Steps
- Hopefully you already know your group assignment.
- The Pendulum platforms are stored in room 214 Stinson-Remick. You all should have swipe-card access to that room. It is not very big, so finding the pendulums is easy. Finding your assigned pendulum for the first time may take a bit of searching, but after that, as long as you put it back in the same spot, it will be easy to find. Keep using the same one. If it is damaged or broken, let me know ASAP. We have some backups.
- There are four TAs for the project, and they have agreed that one of them will be available in 212-213 S-R on Tuesday and Wednesday evenings from 8:00pm to midnight (Tuesdays 8:00-10:00: David, Tuesdays 10:00-12:00: Kevin, Wednesdays 8:00-10:00: Scott and Wednesdays 10:00-12:00: Madeline). They were in this class last year and spent the first part of this semester working out the bugs in the project, so they will be an excellent resource and I encourage you to consult with them.
- You may reserve the pendulum for up to two hours on the google calendar created for it and shared with you.
- Your group may only have one pending reservation at any given time. In other words, your group can only make one reservation and only after that reservation time is over may you make another reservation.
- The project is due at 5:00pm on the last day of classes. There will be no extensions. If all the pendulum platforms are reserved the evening before it is due, that will not be accepted as a valid excuse for not completing the project. You will HAVE to work ahead of time and in an organized manner because it will basically be impossible to start this a couple days before, even with unlimited access to one of the platforms, and finish.
- It is expected that greater than 80% of the time spent on this project will be spent working together with all the group members present in the same room at the same time on the same thing. If this is not happening, you must let me know. If you have a delinquent group member, you must let me know. Also you must let me know these things when it is happening, not when the project is due.
In this project you will design a feedback controller to stabilize an inverted pendulum. The basic steps are:
- system identification,
- controller design,
- implementation and verification.
The first and third steps require that you be able to program a microcontroller. All three steps, but particularly the second step, requires that you understand the course material.
This web page provides a description of the system and instructions to download a program. Read everything before the "Getting Started" section, but do not worry if you do not understand it all. You will probably have to re-read it several times.
One student in each group, probably the ME major, should read these sections. None of it is absolutely necessary to get the project to work. However, it describes the system, and that will make it easier to complete the project.
| The pendulum and controller are shown in the picture below. It is comprised of
The microcontroller is very inexpensive and has limited capability, as is realistic in industry where component costs are of significant importance.
The following elements are illustrated in the picture.
You will need to use one of the desktop computers in 212 or 213 Stinson-Remick. Those computers should have the following software installed:
There are 30 pendulum platforms and each group has been assigned to a specific one. They are stored in 214 S-R and must be returned to that room when you are finished.
All the software can be found in the start menu, except the compiler. To run that you need to open a command prompt (under Accessories) and type "c:\usr\bin\m6811-elf-gcc". If it responds with "no input files" then it's installed. If it responds with "no recognized as an internal or external command" then it's not installed or is not in your path.
|There are two interrupts in the program. One is an output compare interrupt and the other is a pulse accumulator interrupt.
This section outlines the steps to write, compile, download and execute a program on the microcontroller. Until you have a controller designed that is supposed to stabilize the pendulum, make sure the pendulum is pointing down.
The file format that can be downloaded to the hc11 is called an "S-record" and has a filename that has a ".s19" suffex. Here is an example of an S-record that commands a square-wave torque to the pendulum with a period of approximately four seconds. It is a text file, so it is something you can look at and open in an editor, but it is not really decipherable. Save this program on your computer.
The steps required to download the run this example square-wave program are as follows.
- The rest of these instructions assume you made a folder on the desktop of one of the computers in 212 or 213 Stinson-Remick.
- Save the S-record in the link above to that folder on the desktop. Your browser may try to save it as a text file. If that happens, just be sure to rename it to "StudentCode.s19". Also save the files msload9.bin and pms91.bat in the same directory as the S-record.
- You need to use a command prompt and be in the correct directory.
- Open a command prompt (type "cmd" in the search in the windows start menu.
- Type "N:" to switch to the network drive.
- Type "cd Private"
- Type "cd "Desktop"
- Type "cd #######" to get into the folder you made.
- Type "dir" to see the files: StudentCode.s19, msload9.bin and pms91.bat. If you have "StudentCode.s19.txt" type "move StudentCode.s19.txt StudentCode.s19" to rename it.
- It is usually best to have the pendulum on the floor near the computer. Ensure that the pendulum is hanging down.
- Connect the serial cable to the serial port on the computer and make sure it's connected to the serial port on the hc11 board. Be careful with both ends of the serial cable. The serial port is sort of low on is on the back of the computer, so you may have to slide it out of the enclosure that holds it a bit. Also, the attachment point for the serial cable on the pendulum is delicate. If you accidentally kick the cable or power cords, something will likely break.
- Plug in the power plug for the microcontroller board, but NOT the motor. Some LEDs light up on the board when you plug in the right one. On most of the pendulums, the smaller plug is the microcontroller one.
- Set the two switches on the hc11 board to be "together" that is the top one should be down and the bottom one should be up. Push the reset button. This puts the board in "bootstrap mode" to download the program to the EEPROM.
- The pms91.bat file is a batch file that copies stuff to the serial port. First it sends msload9.bin to the hc11, and with this program, the hc11 knows to copy the other stuff sent to it into the EEPROM.
- The program needs access to the COM port. If another program is using it, it will be blocked. The first time you do this, it probably won't be a problem, but you definitely will be debugging stuff via the serial port later. If you leave putty running, it will block it, in which case you will get a warning saying basically that.
- If it's working, you will see a message like:
TECHNOLOGICAL ARTS S-record File Downloader for 9MHz MicroStamp11 ============================================== For expanded-mode 68HC11Dx systems with external EEPROM/RAM . NOTE: For proper operation, do not apply or remove board power while it is Write-Enabled . USAGE: to download a file called myfile.s19 via COM1, type pms91 myfile . 1) Make sure Docking Module is connected to COM1 2) Make sure MicroStamp11 is properly inserted in Docking Module 3) Apply power to Docking Module (+5VDC to +12VDC is acceptable) 4) Place both switches in LOAD position 5) Press target board RESET button. . Press C to abort, or... Press any key to continue . . . Installing bootloader in RAM now... (to abort, disconnect serial cable) Status for device COM1: ----------------------- Baud: 9600 Parity: None Data Bits: 8 Stop Bits: 1 Timeout: OFF XON/XOFF: OFF CTS handshaking: OFF DSR handshaking: OFF DSR sensitivity: OFF DTR circuit: ON RTS circuit: ON 1 file(s) copied. Programming EEPROM now... (takes approximately 20 sec/Kbyte) Status for device COM1: ----------------------- Baud: 1200 Parity: None Data Bits: 8 Stop Bits: 1 Timeout: OFF XON/XOFF: OFF CTS handshaking: OFF DSR handshaking: OFF DSR sensitivity: OFF DTR circuit: ON RTS circuit: ON 1 file(s) copied. EEPROM programming complete. WRITE PROTECT MicroStamp11. Place MicroStamp11 in RUN mode. Press RESET button. Your program is now running...
Be patient. This can take a minute or two. It's not done until you see the "programming complete" line. Move the two switches into the opposite positions (top one up and bottom one down), or in other words, push them apart. When you push the reset button, your program will run!
Things may be a little underwhelming at this point because it may seem like nothing is happening. To make things happen you have to establish communication with the hc11.
To do this, start putty by finding it in the menu or typing "putty" in the start menu. In the opening window, click on "serial" for the connection type, and then click "Open". If you click the reset button again, you should see a welcome message and instructions to move the pendulum through the zero position. If you move it all the way left and right, you should see an indication that it found the zero position. If you plug in the motor, you should hear the PWM and also see the pendulum alternate between a left and right position with a period of a couple seconds.
For safety reasons, the code is written so that the motor just doesn't start doing its thing when you hit reset. It doesn't enter the main part of the program until you move the pendulum by hand through the index position on the encoder. Then it waits for two more seconds before starting.
The program StudentCode.s19 basically commands a square-wave torque to the pendulum with a period of about four seconds. So it should move one way and oscillate some, then after several second or so, move the other way and oscillate some, etc. Just unplug the motor when you have seen and heard enough.
When you are done, CLOSE putty! If you forget, it will block you the next time you try do download an S-record.
Compiling and Downloading a Program
Ultimately your job is to edit the program to implement a controller that you design. In this section you will compile the source code to make an S-record that does something similar to the above. You need to download and save the following files in the same directory
What each of these files do will be described later. In this section the point is to just successfully compile them. You must have them all in the same director or it won't work.
To compile the program and create the S-record type
c:\usr\bin\m6811-elf-gcc -Wall -N -mshort -Wl,-m,m68hc11elfb -msoft-reg-count=0 -o filename.elf filename.c
You need to replace "filename.c" with whatever program you are compiling, e.g., StudentCode.c. It will create a file called "filename.elf". You need to replace "filename.elf" with the same prefix as your C program, i.e., StudentCode.elf. An elf file is a file in Executable and Linkable Format. If you get a warning about the eeprom memory region, just ignore it.
To translate the elf into an S-record, type
c:\usr\bin\m6811-elf-objcopy --output-target=srec filename.elf filename.s19
Again, replace "filename" with whatever. The file "filename.s19" is the S-record that you can download to the hc11 as outlined above. You may want to use a different name for the S-record so you can be sure that when you use it, it doesn't happen to be the same one that you downloaded before.
Do these steps for StudentCode.c to make sure you can compile, make the S-record and download it to the hc11. Then open putty and run it.
If you to all of this correctly and haven't modified the code at all, it should move a small amount, corresponding to ulong = 10. Also, a lot more information will be printed to the putty terminal, as in useful stuff like the angle, the commanded input and the time. The first number is time in hundredths of seconds, the second is the angle in hundredths of degrees and the third is what the commanded input is.
If you didn't see it move, unplug the motor and you can see it fall back to vertical. Also, note that the screen output continues when you do this, so if you move it back and forth by hand, you can see the angle change in the output.
StudentCode2.c is the program that made the square-wave input s-record. The only difference between this and StudentCode.c is the variable "count" declared on line 73 and the switching logic on lines 108-111.
The TAs have made a batch file that does all three steps for you: 1) compile, 2) convert to s-record and 3) download. It is fine with me for everyone to copy that after they have done the above steps by hand a couple times.
Notes on Editing the Program to Control the Pendulum
To stabilize the pendulum in the upright position, you really only need to change two things in the code:
- "OFFSET" at around line 24
- "ulong" at around line 105. (Determining the right ulong is really the main point of the project). ulong is the commanded torque. "u" is a standard variable name for inputs to systems and the "long" part means that it is declared as a "long int" which is 4 bytes long. In retrospect, perhaps "torque" would have been a better name. Change it if you want.
If you want to stabilize about non-zero positions, then modify "pos_desired" at around line 70.
In the computation for ulong, wherever you put a number, you must end it with an "L" (lower-case works too). That tells the compiler to treat that literal as a long integer (4 bytes), so it multiplies the correct way with the errors, etc. If you don't have the "L" it might not work at all! This may seem pedantic, but microcontroller processors often have compilers that make almost no assumptions about how you want to combine things, which makes sense.
|More Programming details for the ME team member to read|
Do NOT edit either vectors.c or memory.x. The former defines the interrupt vector so that when an interrupt occurs, the processor knows where to go to handle it. The second is the memory map for the processor. You can certainly look at each one. I don't think it would hurt or corrupt you.
StudentCode.c set set to print out the time, angle and control input every 1/20 of a second using the "print_data()" function at the end of the if() statement that happens at that rate. If you want to modify what's printed, that's cool, and read the following.
The file serial.c provides functions to communicate stuff through the serial port. In particular, for your purposes, it provides ways to print out information that may be useful for you to debug your program. Note: serial communication is very slow. If you try to print too much stuff, it will slow down your program and affect its performance. As will be described later, the main control loop operates at about 20Hz. The code seems to be able to handle printing up to the order of 30 characters in that loop. If you try much more, it may take longer than 0.05 seconds.
You can figure out all the wonders of serial.c by reading the comments in it. The two main functions you will use are:
If you want to print positive or negative numbers, you have to go through the labor of checking whether it is positive or negative and printing the "-" sign manually!
The file StudentCode.c has most of the functionality you need to control the pendulum. You should be able to complete the project by only modifying the main() function in StudentCode.c. However, in order to be able to do that, you may have to figure out how many of the other functions in the file work.
There is not a function that gives you the pendulum position. The variable pos does this and is incremented by the pulse accumulator interrupt. The value of pos at any time is the position of the pendulum in encoder ticks. If you have a variable that is equal to pos*18, it will be the position of the pendulum in degrees times 100 relative to the index position.
Be very careful writing your code. The compiler option '-Wall' tells the compiler to give all possible warnings. In the development of this project it became VERY obvious that strict C code must be written. If it gives you a warning, fix it. Just because it compiles and even runs, doesn't mean it's doing what you expect. Things like 'a=b' where a is a long and b is an int generates a warning, as it should, and fixing all of this in your code is necessary.
I would suggest breaking it down in the following steps before you try to implement the real controller.
- First modify the StudentCode.c in some minor ways. Perhaps change the torque to be negative, or increase it somewhat. Recompile and re-download to run it. Or perhaps modify StudentCode2.c to make the period of the square wave smaller or larger.
- The controller looks for the index on the encoder and treats that as zero. However, because these were assembled by hand, and also because they can get banged around a bit, the index is almost never exactly at zero. Your first task will be to determine how far off the index is from zero, and put that into the program.
- You can do this by setting the torque (ulong) to zero and just watching the output to see the value when it hangs straight down. The negative of that will be the offset, which you need to change at the top of the program. Each platform will have a different offset and over time it may even change for individual platforms.
- This is not necessary at this point, but some of you may want to implement proportional control. This will not give satisfactory performance, but is a good first step. I don't know what a good gain is, so you will have to experiment some if you try that.
To design a good controller, you need a decent representation of the system dynamics. To determine the transfer function that relates the commanded input torque, ulong, to the angle, theta, that describes the response of the system we will command a step input to the pendulum when it is hanging down and see how it responds. This will give us all the information we need to determine the transfer function relating the input torque to the output angle.
- Enable logging in putty so that everything that gets printed to the screen gets saved to a file. To do this, click logging option on left-hand column, browse to own directory, save “printable output” under Session Logging. You need to specify where it is saved so you can find it later to edit and then to load it into Matlab.
- With the pendulum hanging down with no movement, command a step input for the torque, i.e, set torque to be a constant value. That's basically the default StudentCode.c behavior. Build up from ulong=10L to whatever your assigned "step mag" was. You want the steady-state angle to be between 15 and 45 degrees. If your assigned value doesn't do this, then just increase or decrease it so it's in the range. For most groups and most pendulums, the assigned values should be fine.
- If you haven't changed anything that's printed out, the terminal should show the time, angle and input. If you did happen to modify it, then make sure to print to the screen at least the time and the angle at 20 Hz.
- After it settles down, quit putty. Edit the log file to cut out any extra junk at the top and any incomplete lines at the bottom, and you should have three columns of numbers: time, angle and torque. If you let it sit there for a long time before you quit, then you may want to cut off some of the last lines.
- You should be able to plot the response in Matlab.
Theory and Practical Steps
- You want to find a transfer function like Theta(s)/U(s) = k_num/(s^2 + 2 z wn s + wn^2), i.e., three numbers, wn, z and k_num.
- You can get wn from the period of oscillation.
- You can get z from the logarithmic decrement.
- You can get k_num from the final value theorem.
- Once you have computed those, you can fine-tune the numbers by comparing the response with a plot in matlab using step().
- BE CONSISTENT with units. I would use time in seconds, angles in degrees and torque in whatever the heck ulong=1 is. This is easier said than done. Almost every group will have problems with the units in this project at some point. Just be as careful as possible, and when things don't work, checking units may often resolve the problem.
- You must do your system id with the "Step Mag" assigned to your group. Good engineering practice, obviously, requires you to verify stuff you determine by repeating the experiment several times and checking that what you determined to be the transfer function gives decent results for other inputs too, both other magnitudes and opposite signs.
- Note that if you use a step input of magnitude other than one, which is the case for everyone, the you should compare the step response with step(step_mag*k_num,[1 2*z*wn wn*wn]).
- Page 1 of your project report will be your system id results.
Designing a Controller
You must design a lead-lag controller to stabilize the pendulum in the inverted position with satisfactory transient response and satisfactory steady-state error. Each group has a lag gain assigned to handle the steady-state error. Each group also has an assigned damping ratio for the transient response. You must design your controller to have that zeta and that lag gain. After you do that, if you don't like the way it acts, you can improve it yourself, but what you submit should be the assigned values.
To validate your design, you must
- Show that it stabilizes to zero.
- The root locus should give a natural frequency, which should predict the rise time.
- The damping ratio should predict overshoot.
- To test the lag gain, implement the lead controller and measure the steady-state error. Add the lag, and see if the steady-state error is reduced by the expected amount.
- Predict how it will behave with a step input in the desired angle to 10 degrees. Do that, and compare the actual response to the predicted response.
- Predict what will happen if you increase or decrease the gain. Validate the expected change in response.
Implementing a Controller
In our class, we will only consider continuous-time systems. However, the microcontroller only works in discrete time steps. Hence, you must convert your controller from continuous-time to discrete-time. In the frequency domain, continuous-time systems are represented by the Laplace transform, with s as the independent variable. In the frequency domain, multiplication by s represents differentiation, i.e.,
In discrete-time, the analogous transformation to the Laplace transform is called the z-Transform, with, not surprisingly, the independent variable being z instead of s. In discrete time instead of a function depending continuously on time, a function is only defined for a sequence of times, i.e., instead of x(t) we have x(T), x(2T), x(3T), etc., where T is some time step. In discrete time, under the z-transform, the analog to multiplication by s being differentiation is that multiplication by z is a time shift. Specifically, z X(nT) = X((n+1)T), it shifts the function ahead by one time step. Dividing by z shifts it back. Multiplication by z twice shifts it ahead by two time steps, etc.
The approach we will take in this class, which is relatively common, is to do all of our work in the continuous frequency domain and at the very end convert our continuous controller to a discrete-time one. For very simple operations you would naturally do this, for example, replacing the derivative of a function, f'(t), by [f((n+1)t)-f(nT)]/T. However, for more complicated things, this could get confusing. It turns out that the usual trapezoidal rule for integration gives a nice relationship between s and z given by
This is called Tustin's method. Now, say you have some controller that you designed given by, for example
where F(s) is a control force and E(s) is the error signal. What you do is substitute the equation relating s and z into C(s) to get it in terms of z, e.g., for this problem (if I did the algebra correctly...)
for the right hand side. Because this is the z-transform for the error to the force, we have
Because multiplication by z is a shift forward in time, in discrete-time this corresponds to
which is our computation for f(t) at the new time step. It depends on both f and e at the previous time step as well as e at the current time step (t=(n+1)T). For a lead-lag compensator, the numerator and denominator will both be second-order in z, so the computation for the new control input will depend on the current error as well as the error and control at the previous two time steps.
You should definitely do the computation by hand. You should know too that Matlab has a function called c2d() which stands for "continuous-to-discrete" which does this conversion computation. You need to give it the time step as well as the method. For this example with a time step of 1/20 and using Tustin's method,
>> c2d(tf([1 2],[1 15]),1/20,'tustin') Transfer function: 0.7636 z - 0.6909 ----------------- z - 0.4545 Sampling time: 0.05 >>
Assuming this is correct, let's proceed to implement it on the hc11. That processor is CHEAP ($3.50), so it's not going to be able to do too much math. In fact, floating point arithmetic requires an additional library is is way too slow. It can, however, very quickly do fixed point (integer) arithmetic. Assuming the matlab controller for the pendulum (it won't work, by the way, this is just an example...) with u representing the pwm level and err the error, we would be tempted to write
- u = 0.4545*u_old + 0.7636*err - 0.6909*err_old;
where u_old and err_old were copied from u and err at the bottom of the 20 Hz loop. But it can't do the 0.4545*u_old computation. What it CAN do is
- ulong = (4545L*u_old + 7636L*err - 6909L*err_old)/10000;
If you look at the comment a line or two above the ulong line in the original StudentCode.c you will see a version of this (with changed numbers).
This will allow it to retain necessary precision but still do the computations in fixed-point.
- For the hc11 an integer is 16 bits, which has a maximum value approximately 64,000 (half that if it is signed). When I implemented the controller, the computation for u in the first line (before it was divided by 10000) exceeded 32k. Hence, the variable type for u in the code had to be a long integer. so we have a ulong. This made u 32 bits, which was large enough for the computations (but slower).
- You must be very careful with the variable types in the code. Embedded systems are very picky about them and passing an int to a function that wants an unsigned long, for example, may compile but exhibit flaky behavior because the function isn't getting the intended value from the variable. As long as you do ulong like shown above, it should be ok. Be sure to put an L after every number in the ulong line!
- Also, be careful printing stuff to the serial port because it can only put out so much in 1/20 of a second. One mistake I made was to compute some stuff, print it, use it in another computation, print that, and then set the torque to the computed value, which was too much. If the printing slows it down to less than 20Hz, it won't complain or otherwise indicate anything, but effectively the time step will be longer than what you used in your computations, and things won't work! Most groups can probably get away with just looking at what is printed by default.
- Be very careful with units. You will definitely save time if you are careful with all the units whenever you write something. Are you using encoder counts for the position, or degrees, or degreesx100? I would have saved a few hours if I were more disciplined about this.
Project and Report Content
You must write this report as if I were your boss and people trusted their lives to the product we were developing (medical device, airplane, etc.). Your boss has very little time, however. You are limited to 3 pages, with each page having this content:
- System id: what is your transfer function? Show me a plot that validates it. If other details fit, put them below the transfer function and the plot. I know how to compute a transfer function, you need to convince me that your's is correct.
- Controller design: what is your lead-lag controller? How did you design it? What are the controller specifications? What is the theoretical response of your system?
- Implementation: compare the actual controlled response to what is theoretically expected. Also change the gain and predict the change. Does the change in the physical response correspond to what is expected with the gain change?
If you get it working and want to learn more, I would suggest investigating the following. Unfortunately, there will not be any extra credit for the project because that was not part of the setup when people determined their grade allocations.
- In addition to the modifications to main() and specifically the while(1) loop therein, modify any other selected parts of the code to significantly improve the performance of the system. Check how fast you can make the PWM work with your baseline code and controller before it gets flaky or how much faster you can make the 20Hz control loop. Then find something in the code that you can modify to make it faster so that it can run at a faster PWM and/or control loop before it starts running into problems.
- Use simulink to model the real system. The plant will be continuous, but the sensing and control will be discrete.
- Use this model to predict the steady-state error when there is no lag compensation.
- Use this model to predict the effect of faster or slower control loops. What seems to be the slowest it can work and still be effective?
- Use this model to predict the effect of having less resolution on the PWM, i.e., instead of a resolution from -400 to +440, check the effect of -40 to +40, etc.
- Use simulink or other matlab tools to automatically generate the C code for the controller. Automatic code generation is becoming commonplace. Nothing is more dangerous than blindly trusting what comes out of a computer, so you have to know how the controller should work. Now that you have done that, check what simulink gives to you for code. Disclaimer: I have not done this myself and am not sure if the hc11 is a recognized target, how to do it, etc.
- You may propose an additional component to the project if you wish. Come talk to me with any ideas you may have.