Images, Movies, and Code! Oh My!
Wednesday, May 6th, 2009Well, here you go, folks! I’m posting everything here. Code, schematics, the paper, pictures, and a clip of the cars moving! Enjoy! (more…)
Well, here you go, folks! I’m posting everything here. Code, schematics, the paper, pictures, and a clip of the cars moving! Enjoy! (more…)
First, apologies for those people who don’t like the movie “Short Circuit”, the past few weeks have felt like that.
I’ll cut right to the chase: the robots work. Not as cool as we had hoped, yet, but still very cool.
After the last post, we where working on getting the optical mouse to tell us how far we’d gone. Initial tests where positive. The mouse was reporting change and such. But after mounting the mouse to the underbelly of the car, the mouse wouldn’t report data reliably. We suspect that it was something to do with the car going too fast. It might be that we where traveling out of it’s field of vision within it’s 200Hz sample rate. But even making the car drive slowly (which wasn’t easy) on carpet barely improved the situation.
So, with the accelerometer down, and the optical mouse down, what do we do? Well, with time running short, we turn the mouse upside down and use the wheel! This setup finally got us measuring distance reliably. very hacky, and not as cool looking, but functional.
I then worked up some TCP code that would have the cars talking to each other. The idea here was that there would be a lead car that would calculate how to drive, then share it with the other cars. To test, we set the one car we had built as a following car, and a router as a lead car, then adjusted the code so that the lead car wouldn’t try and go and wouldn’t hold up the other car. This setup showed that the one could tell the other how to drive. The following car seemed to drive accurately, too.
So we go on and try and do a full test of this. And then the car stops being controllable. The router still works. The microcontroller still works, but the car keeps trying to go forward. Apparently we are now down to two cars. So we build up car number 3. But my partner tells me he blew out the final car a while back. Dont’ ask me how, but he did. One car isn’t a swarm. We could do the router-car swarm, but that isn’t much either.
So with one working car, we continue to test accurate driving. My partner works out a replacement board for a broken car. We think the car’s board is a simple H-bridge, as it seems to work like one, but we couldn’t find the parts to fix it. He built a new h-bridge finally, but it drives weakly. But it will do. On my end, I find out that the turning code is off. It isn’t always registering turns accurately. I add in code and find a whole bunch of math errors. Most of them involved the fact that our angle is always between PI and -PI radians (-180 to 180 degrees). This causes issues when the angle jumps from -3*PI/4 to +3*PI/4 (a turn of 90 degrees over that jump). I finally figure out an equation that compensates for that.
Now we finally have two cars to drive. I set it up so that one car still just sits there and the other car get’s it’s instructions, then goes. But it just sits there…. Turns out that my TCP code for that part shouldn’t have ever worked. It assumed that my TCP stack would tell me there was data even if I had already read it, so that if I got 3 instructions in one burst, I’d only read one of them and ignore the rest until I got another packet, where I’d read one more, and so forth. So how the code was working before was a mystery.
I fixed that bug, and it seemed to work again. I adjusted the code so that the lead car would drive and then tell the other car to go. The lead car (however slowly due to the H-bridge) would go, then say it was passing control. The other car would then crash. I added debugging and saw it crashing between two lines of code that it wasn’t crashing on before. I added more debugging to see if maybe I had a Null pointer in there. And it stopped crashing. I do more tests and it starts crashing again at random locations. This is a pain. I suspect what happened was that the lead car would send the go command repeatedly, and the follower would fill up it’s TCP buffer and segfault. So I made the go signal send once and it fixed the problem. Rather, I made the go code send once, and it fixed it, so I think that was what the problem was.
At this point we where suppose to demo it to the professor. We have it working in tests, but when he showed up, it stopped working. it would drive off into walls and not go and such. Not going and driving randomly seems to be noise in the serial line. So we filter that, and we send commands multiple times. Running away in a turn seems to indicate more turning math problems. Multiple passes through finds most of the math errors, but seems to cause more harm than good. Now it doesn’t turn correctly at all. I measured the compass data over a complete revolution and put it in excel and saw that the angle was always within a small range pointing mostly to the drive motor. Moving the compass to the front fixed it somewhat, so I measured the bias and just fixed it the rest of the way in software. Add in some noise filtering and it’s good to go.
More testing and a lot more time finally gets one car to do about the same thing as the other. It’s about a week latter than the demo date, but the professor said he’d still like to see it, even if it is late. I made a video of it on my camera, just in case, then show it to him. It finally worked right and it’s done.
Yes, that’s a long summary of about 3 weeks worth of work, but it’s done. When I get a chance, I’ll upload the video and some pictures to this post, so check back. I’ll also upload all schematics, code, and the final paper at a later date. The whole project will be under some open license so that people can make use of it. I don’t know about support or updates, as I don’t know the interest, but at least people can make free use of it.
I’m sure you where all excited with that makefile from last time. Reading between the lines (well, actually it had it’s own whole line, but that’s beside the point) about the progress on the robot project. Well, I’ll tease you a little more.
To start with, I found I had to add some more lines to the linker flags. I found that dd-wrt mini, which we are using, does not have libstdc++ installed. The toolchains have a copy of the library for mipsel, but the read-only filesystem of the router prevents it from being loaded even if copied there to the writable part. So there are two ways of dealing with that. First, we could build our own version of the firmware and include the library there. Every possible and easy to do. The other option would be to statically link the library in at compile time. Normally, such a thing is frowned upon, as it makes bigger binaries and the point of the libraries is so that many programs can use them without having their own copies. But, this is a one off program, and statically linked programs are a little faster, and library itself would be larger when dynamically linked than the whole program with it statically linked. It also means that the program will run on standard firmware without issues.
You might notice from that and the makefile that the program is all in C++ now. I reworked a lot of code and added in a bunch of new functionality. The new code is the main reason for the make file. Three files is ok to deal with manually, but I knew that it wasn’t going to stay as three files. It has grown to 6 .cpp files, and I’ll probably end up with at least 2 more.
Well, what does it do? First, we have some sensor classes. These serve as objects that can handle the different types of sensors. As of now, we have the magnetometer, the accelerometer, and the mouse. I can’t say that the accelerometer functions will accurately calculate distance yet, as I haven’t been able to get good data to test with, but in theory it should work. These objects will be shared between the sensor reader functions and the position update functions. Secondly, there is the serial functions. This is just a set of functions that open, read, write, and close the serial port. These where all mostly written before, but now it’s packaged up nicely. Thirdly, there is the position update file. This provides a position class that has functions to keep track of where the car is and where the goal location is.
We can pause here to look at the main file, which drives this system. It opens the serial port, and attempts reads, at which point, it will feed that data into the position system. The position system will calculate an X and Y and angle relative to the starting point. I tested this code with a small test that spit out a few angles and distances (not accelerations). I then had the positioning system spit out an X, Y and angle in comma-separated-value format, which can be imported into a spreadsheet. Plotting this, I saw the angles and the movement that I roughly expected. This was rather exciting.
I have since added a class for a “movement” or a simple step (a long the lines of “move forward 2 feet” or “Turn right 40 degrees”), some functions that read that in a queue and execute them, testing for when it’s done, and as part of that, code that will send the one byte commands to the microcontroller to drive the car. This portion has not been tested yet, but will be soon. We are working on getting the microcontroller powered by the car battery and working on getting good distance data from something.
The next piece that I haven’t quite cracked is point to point drive. I have some equations and some code, but that will have to be re-written for C++. I also need to work out the inter-router communication. But if I can’t get one car to go, I can’t get 4.
It’s spring break, and you know what that means: school projects!
Just kidding, somewhat… I had a presentation about the RC car project this past week. I covered lots of details of the design so that the professors could try and find weak points, and boy, did they ever.
One of the major weak points they found was with the accelerometer. Many projects use them to determine location on a small scale. Add in a gyro and a compass, and maybe a GPS, and you know everything about your location. But what they dont’ tell you is that it involves a lot of math. To determine distance from acceleration, you have to have the complete acceleration curve over time, and do a double integral over it. The integral can be done using just sums, but without enough readings from it, you can’t get good information.
So they suggested using rotary encoders on the axles. Not a bad idea, but that would involve finding good ones and ording them. Then they would have to be mounted, and we would probably want at least two per car, and the list goes on. We could put some Hal effect sensors by the wheels and put little magnets on the wheels and thus count revolutions. This could also work, and is slightly better than the rotary encoders, but not by much. Jokingly, one professor suggested dragging a mouse behind it, thing about ball mice.
Well, that got me thinking. Mice are essentially linear encoders. Ball mice do so by converting the linear movement into rotational movement in the encoders. Optical mice do so with small scale image processing, essentially. They take this data and send it serially via RS232, PS/2, or USB. So, if you take the guts of an optical mouse, attach it to the bottom of the car, and you run the cord up the the microcontroller, couldn’t you fake it and thus get distance measurement directly?
So I took apart a mouse that is a USB mouse that also supports PS/2 adapters. PS/2 is a much easier protocol than USB, both in terms of electrical signals and in the protocol itself. I also found out how PS/2 is suppose to work, and hooked up an oscilloscope to test it out. I didn’t have much luck, but I have since found some code that I want to try. I just need to get to the school and try stuff out. I really wish I had an oscilloscope at home….
On that note, I saw on eBay a pre-made dev board for AVR microcontrollers that can be used as a low end oscilloscope! I thought it was amazing, but still over my budget. The guy that made that is also working on one that can measure inductors and capacitors, and be a function generator, not to mention a logic analyser. That would be amazing. Like an electronics lab in a box.
Finally, as I was on my way home from school on Friday, a girl sideswiped my car. Both of us are ok, but my car is in bad shape. Luckily she’s insured, but I still might be out of a car for a while, and it might have been totalled, so…. I might have difficulty getting to school to work on these mice anytime this week.
By popular demand, mostly by me, I have uploaded some pictures of my RC car robot project. First, we see a nice picture of the car we are using. Yes, it is a Mustang. It some cheepo car from Target. Nothing special about it other than the size. It is a fair bit bigger than normal RC cars. It’s about 16″ or so long. Enough room for all our gadgets.
Inside is a small circuit board that houses all the goodies that let the car drive, besides the motors. On board there is a voltage regulator, 2 H-bridge circuits (one set for Right/left using small transistors, one set for drive using the large ones on the right), and an IC that translates the RC signals to control the H-Bridges. That IC just has 4 outputs: right, left, foward, and reverse. It just puts a little power out on up to 2 of those pins at a time and the thing goes. It doesn’t have variable speed or turning, but whatever.
This is after we soldered up some wires. It was also taken after we fried the small transistors, but you can’t tell.
And the Underside
I have some more pictures of motors and such, but who cares? Let me know and I’ll post links to them.
Second, we have the brains of the outfit. Not not me. The router.
This is the replacement router, the WRT54GL v1.0. Inside we see all the goodies it has to offer, such as Serial, JTAG, the broadcom mipsel processor, and the normal wireless stuff.
We can zoom in on the serial port, which has the pins added in this picture. There are 10 pins. From what I can tell, 9 and 10 are ground, 4 and 6, and 5 and 7 are the data pins for the 2 serial ports provided. In DD-WRT they show up as /dev/tts/0 and /dev/tts/1, unlike the normal /dev/ttyS0.
Finally, I leave you with very zoomed up picture of our digital compass. Those 6 pins on the top are the same size as the ones on the serial header. The board is slightly smaller than your thumbnail. It can find 64 different angles from north. Not very detailed, but enough for our work. Considering how much anything better would be, this was a steal.