- wind direction sensor driver (should be easy)
- GPS driver
- navigation
- rudder control algorithm
- sail position control algorithm
- over-arching control loop
Robot Sailboat
Sunday, November 13, 2011
Programming Progress
Wednesday, June 22, 2011
It works!!!!
In order to do the tilt compensation for the compass, I need to do a series of coordinate transformations. Unfortunately, I find coordinate transformations to be one of the most confusing things I’ve learned about in my engineering education. I’ve run across a couple instances where I’ve had to use them at work and now one instance where I have to use them for the robot. Every time I do, I get confused.
The basic idea of a coordinate transformation is reasonably easy to understand. Lets say you have a point sitting somewhere in space relative to an X and Y axes. Then imagine you have another pair of axes that are in the same plane and have the same origin, but are rotated at some angle relative to the original axes. You could figure out the coordinates of that point in the new axes by using trigonometry and a few Sin and Cos terms. The problem comes in when you want to deal with stuff in 3-axes and you want to do multiple rotations. The number of terms quickly get out of control and its hard to maintain an understanding of what each term intuitively means. That’s when you start using matrix math. That takes care of keeping all the terms in the equations straight, but you still have to make sure you know what you are doing. The order of which axes you rotate first matters, as does whether your second rotation is about the already rotated coordinate frame, or whether you do it about the original, fixed coordinate system. Lastly, you also need to decide whether you are rotating the data to a coordinate system or you are rotating a coordinate system to the data. Ugh.
So when it comes to the robot and the compass, I need to do a pair of rotations. There will be a rotation for the pitch of the boat (is the bow tilted up or down?) as well as for the roll (is it tilted over on its side?). The compass sensor will take readings while the boat is pitched and rolled, and I want to know what the compass readings would be if it were not pitched and rolled(sitting flat in the water but still pointing in the same direction). Its probably useful to note that I am assuming the sensor (both accelerometer and compass) X-axis will be aligned pointing towards the bow (front) of the boat, with the Y-axis pointing to the port (left) side, and the Z-axis will be pointing upwards along the mast.
The pitch rotation will be first. If the boat is pitched downwards, that is a positive rotation about the fixed y-axis (right-hand-rule). But we want to rotate that coordinate system the opposite direction to align it with the fixed coordinate system, so its really a negative rotation about the Y-axis. After the pitch compensation, the same is done for the roll compensation. The boat tipping to the starboard (right side) would be a positive rotation about the X-axis, so we have to do a negative rotation to compensate for it.
Each of these rotations creates a rotation matrix and since there are two of these rotations, there are two matrices that need to multiplied. Doing the requisite matrix multiplication produces the following two equations. Note that there would be a Z equation as well, but I have dropped that result after the compensation since you only need the X and Y components of the horizontal magnetic field to get the heading. Also note that in the equations below p = pitch and r = roll. The -1 in each of the trig functions signifies that the angle is the opposite of what the boat is actually tilted.
X = x*cos(-1*p) + y*sin(-1*p)*sin(-1*r) – z*cos(-1*r)* sin(-1*p)
Y = y*cos(-1*r) + z*sin(-1*r)
A summary of the assumptions I’ve used are below:
- The accelerometer Z-axis reads +1.0 when the red light is facing the ceiling
- The accelerometer X-axis reads a negative value when it is tilted in a positive rotation about the y-axis (the +x-axis tilts down towards the floor)
- The accelerometer Y-axis reads a positive value when the sensor is tilted in a positive rotation about the x-axis (the +y-axis points up in the air)
- Positive rotation of the sensor about the x-axis gives a positive roll angle (roll to starboard)
- Positive rotation of the sensor about the y-axis gives a positive pitch angle (pitch downwards")
- Pitch and roll angles should be multiplied by -1.0 to make the angles that for the coordinate transforms (coordinate axes rotated the opposite way of the pitch and roll angles)
- Rotation matrix is created using the following transformations:
- Rotate the pitch angle in the fixed coordinate frame first
- Rotate the roll angle in the fixed coordinate frame second
After all that, it does actually work! It took me a lot of thinking and testing to get it to work, but it does work and it seems to work pretty well. It is a bit sensative to accelerations and nearby electronics (computer, phone, etc), but there isn't much I can do about that. Hopefully the accelerations will even out with time-averaging and hopefully we can keep the sensor far enough away from the other electronics.
I should say that I calculated the angles by an over-simplified way to get the tilt compensation working, but for large tilt angles its not accurate. I have the more accurate method figured out (I think), but I haven't tried it to confirm. I'll leave that for another time.
Tuesday, June 14, 2011
Trying To Tilt Compensate
Several weeks ago I had spent quite a bit of time trying to figure out the math for doing the tilt compensation. I believe its just a couple coordinate transformations, but it gets tricky when you start figuring out which axis to rotate about first and whether you use fixed axes or the transformed axes for the second rotation. I thought I figured all that out, reduced it to a couple simple equations, and verified it with a spreadsheet. Something isn't right, though.
It may be because I had mistakenly thought that when an axis is tilted downwards in the direction that gravity is pulling, it would read a positive value. It actually reads a negative value. I guess this makes sense if you think about accelerating the sensor along the postive x-direction. It would feel a force pulling it towards negative x, but it reads a positive value since it is accelerating in the positive x-direction. Just to try, I multiplied the inputs by -1 to see if that fixed it, but that didn't work. I don't think its a simple change like that. I might have to multiply the matrices in a different order or something. Unfortunately, I didn't really write out how I figured out the math last time, so I'll have to go through it again. When I have it figured out, I'll be sure to write a blog post on it.
Saturday, June 4, 2011
Averaging
Wednesday, May 25, 2011
Processing Speed
With that thought in mind, I decided this would be a good time to test out how quickly the microcontroller can run through programming, particularly math intensive programming. How quickly it would be able to run some of the geometry functions (like arctan) will go a long way towards determining how frequently the controller will be able to cycle through its programming, as well as how tolerant it will be of the ineficient programming I will be feeding it. Doing a check on this would also give me the chance to learn the syntax of some useful functions like a for loop and commands for measuring time.
To do this I simply put a loop around a big chunk of my compass code forced the controller to do that loop 10,000 times, and checked the time immediately before and after. The loop consisted of:
- offsetting and scaling the three raw magnetometer readings (these were already stored in memory)
- going through 4 conditional checks to determine the proper way to calculate heading
- calculating the heading using and arctangent function
- converting from radians to degrees and then offsetting for declination
Doing all that 10,000 times takes approximately 2.3 seconds, which means it runs through that loop in less than 1/4300th of a second. Not bad for a cheap 16MHz processor. Kinda makes you wonder why your laptop is so slow, doesn't it? A modern laptop processor should be able to run instructions a couple thousand times faster than this microcontroller.
Monday, May 23, 2011
Slow Work on the Compass
The big problem was that the outputs weren't working and didn't make much sense to me. It turns out that the problem was related to not being able to output floating point numbers (numbers like 3.14 that are not simple integers) to the computer screen. I thought that when I output float numbers as integers, it just lopped off the numbers after the decimal point. It does do that, but doing so somehow screws up the other outputs. This is becoming a significant problem for debugging, so I think that I might have to use an alternate method for outputting these values. I think I saw online that other people had created custom functions to output float numbers, so hopefully I can just copy their code into mine. That might be my next task.
After I figured out that this was the problem, I was able to change a couple things and output just the numbers I really needed. The code did work reasonably well. I put the sensor flat on a table next to an actual compass, and they read pretty similar. It seemed like the sensor was reading maybe 3 or 4 degrees off from the compass. Not terrible, but not great. I'm wondering if magnetometer readings might need to be recalibrated. There is definately some noise in the readings. It would wander by about +/- 3 degrees as it sat there. That should be ok since I plan on averaging the readings. It was also very sensitive to being tilted. Just 10 degrees or so of tilt would cause the reading to vary by maybe 30 degrees or so. Hopefully the tilt compensation I have planned for it will work well.
There is one more problem I thought of. The heading is calculated simply as arctan(ycomponent/xcomponent), but the arctan function only works from -90 degrees to +90 degrees, so you need to use a couple conditional "if" statements to get from 90 to 270 degrees. That worked, but I realized that there is a discontinuity that will cause a problem for averaging. Right now, it will read 269 degrees, but if you rotate a couple degrees further, it will read -89 degrees. While that is fine in most cases, if the boat is heading towards 270 degrees and is trying to average several compass readings, the average of 269 and -89 is 180 degrees, not 270 degrees! The same problem happens if you shift that discontinuity to zero degrees (or anywhere else). It also happens when using degrees or radians. I'll have to figure out a way to deal with that.
Wednesday, May 18, 2011
Tilt Sensor
There was already some code written to get the accelerometer talking to the microcontroller (debugging output goes from there to a computer). Much like the compass, the outputs need to be adjusted and normalized. Again, I'm modifying them to read -1000 to +1000 (+1000 is equal to 1-g) on each axis. The raw outputs for each axis are approximately:
X-axis: -256 to 270
Y-axis: -262 to 264
Z-axis: -267 to 242
After completing the output modification, I decided to calculate the angle that the sensor is tilted. On one axis that can be done as pitch=asin(x-reading/gravity). Since I scaled the readings to be 1000 for 1-g, gravity can be replaced by 1000 in the equation above. The same can be done for roll angle using the y-axis.
I was a bit worried about noise in the readings, but it turns out to not really be an issue. When I'm looking at the scaled results and holding it as steady as possible on a table, it does have some variability. For instance, it might range from 482 to 490. Due to the the Sine function, when you are close to zero, the sensor reading needs to change a relatively large amount to change even one degree. As the angle gets closer to 90 degrees, small changes in the reading produce large changes in angle. Realistically, we don't care too much about the compass reading if the boat is pitched 90 degrees downwards. We'd have bigger problems in that case.
Waves and other things might affect the acceleration somewhat and therefore the calculated angle and compass heading, but I'm hoping that we can take readings frequently and average them over time to smooth out those errors.
It works pretty nicely now. The readings for moderate tilt angles (up to 60 degrees at least) are pretty smooth and steady. Tilted at 45 degrees and held on a table or something solid, it will vary less than one degree, which seems good enough to me. When you get close to 90 degrees, it gets a bit wierd, but that is expected. Again, I'm not too worried about being able to precisely measure 86 or 89 degrees of roll.
It seems like I should have gotten more done tonight, but I was having problems with the microcontroller to computer interface, so that slowed me down a bit. For some reason, there does not appear to be any good way to output floating point numbers (decimals) to the computer. I looked it up online and other people had the same problem. It will, however, output the integer portion of a floating point number, so I ended up just multiplying the angles by 10 so I could see the first decimal place. Not a problem when this is actually in operation on the sailboat, but its annoying for testing and debugging the software.
Writing the blog posts also takes up a bit of time, but since I have a poor memory, I suspect some of these posts will be useful to look back on in the future.