Wednesday, May 25, 2011

Processing Speed

It turns out I was wrong about not being able to output floating numbers from the microcontroller to the computer. Its just that there was a simple command that I was familar with that would conveniently string together outputs and put them together on one line for you. That function couldn't handle floating point numbers. I've figured out a simple way to do it so that it is in a format I like. I guess this just shows how little I know about programming.

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

Last night I tried to do something that I thought would be pretty easy. I was going to take just the horizontal components of the magnetometer (ignoring the large vertical component like a compass does) and output the heading. Unfortunately, I ran into a couple problems.

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

We have a 3-axis accelerometer to go along with the 3-axis compass. Its actually all on the same circuit-board that is smaller than a stamp. The idea is to comebine the accelerometer and compass readings to give us a tilt-compensated compass. As mentioned in my last post, the magnetic field isn't a 2-dimensional thing, it has components in all 3 directions, so when you tilt a compass, it will give you incorrect readings (that is why the needle on any hand compass you buy has some room to level itself to gravity). Using the accelerometer tells us how much the boat is tilting and we can therefore compensate for that tilt when looking at the compass readings. That is going to require a bit of math before we get to that point, though.

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.

Sunday, May 15, 2011

Modification of Compass Readings

I spent a little while today reaquinting myself with some of the programming for the accelerometer and compass sensors. The programming for getting readings from these sensors was partially completed, but never finished.

The compass sensor is a digital 3-axis magnetometer. Unfortunately, its not as simple as asking which direction the sensor is pointing. I have the sensor communicating with the microcontroller, but the ouputs are just 3 numbers. The first step is to calibrate and normallize those values to a standard maximum/minimum scale. I'm doing this initially by moving the sensor around till I get two of the three axes to be as close to zero as possible and then the third axis will be at either its maximum or minium. Once I have the min and max for each axis, I can add or subract values to get the midpoint at zero and scale to get the max and min at some value. I'll aim for -1000 to +1000 for each axis. The raw min and max values I am getting for each of the axes are:
Axis 1: -675 to 660
Axis 2: -580 to 745
Axis 3: -640 to 645

Even after normalizing these values, we still need to do more work to figure out what direction the sensor is pointing. The magnetic field is not strongest when pointing north, as you might expect. Instead, the strength and direction of the magnetic field depend on your location. In two dimensions, this is called the magnetic declination. In three dimensions it is called annoying. I found a website that gives you the direction of the magnetic field for any location. After putting in my zip code, it tells me that the direction of the field is 11 deg and 38 minutes West and 69 deg and 35 min downwards. In terms of components, when you are pointing true north, the magnetic field components should be:
North: 18,486nT
West: 3804nT
Down: 50,698nT

This will all have to be accounted for in the next step, but that won't happen today.

Introduction

Almost a year and a half ago (October of 2009) I decided that I wanted to try to build a robot in my limited spare time. Having several technically minded friends, I decided to get some people to try to make a group project out of it. Several of my friends had varying levels of interest in the project, and we worked together to brainstorm robot ideas. We narrowed the options down and ended up deciding on a robotic sailboat that could go long distances on its own using GPS for navigation.

Over the late fall we came up with a rough design and gameplan that allowed us to purchase some electronic components and a radio-controlled sailboat kit. During the early months of 2010, the sailboat kit was put together and completed as a radio-controlled version. The maiden voyage was in May of 2010. Here is a picture of it that day.

Unfortunately, interest in the project slowly waned, and very little work was done on it after it sailed. The current status is that the majority of the mechanical work is completed (it does sail after all), but the majority of the electronics and programming still needs to be completed.
I've decided that I'm going to try to start working on it again. I'm hoping to put in 4 hours a week on the project. That doesn't seem like a lot, but I suspect I'll have difficulty setting aside even that little time for the project. Its not that I don't want to work on it, its just that I have a lot of other things I should be doing, and when I'm not doing them, I'd like to have some time to relax and do nothing. I'm going to try to work on it each Sunday and Wednesday evening.

So I started to write down a few things in a journal for the robot, and I realized that I could just write it down online and make a blog about it. I figure that this will motivate me to keep doing work, and will let people see what progress is or isn't being made.