NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.
Project Help and Ideas » Nerdkit learns to drive
June 24, 2012 by esoderberg |
Link below has video of couple test runs of my drive by wire 3 wheeler. Consists of Nerdkit mcu reading from an mpu-6050 gyro/accel combo and a hall switch pickup for velocity measurement. Driver input comes from a joystick. I started to design my own H-bridge, but I kept burning them out, so in order to get on the road, for now I'm using a Pololu motor controller to take my steering inputs from nerdkit to drive a linear actuator for steering control. I could go much faster but I'm still at the point where I go no faster than I'm comfortable crashing at(made lots of mistakes along the way so far, so more are expected). I'm still tuning the handling qualities but it's pretty tame so far. Most of my runs are with driver input controlling tilt rate, but also a few with driver input taken as desired tilt angle. Probably higher performance with former but easier to drive with latter. http://youtu.be/q8inBsAz1ng |
---|---|
June 25, 2012 by Ralphxyz |
Oh wow, I want one :-) Ralph |
June 26, 2012 by HansRoaming |
Very impressive! |
June 27, 2012 by esoderberg |
If anyone is familiar with the MPU-6050 gyro/accel and knows how to init the DMP portion, it would be great to see this in the forums. The data sheets from Invensense are really weak on this topic; there's some info on the web for using the DMP function, but from what I've found it's almost all in Arduino wiring code which I'm not familiar with (although it looks not too far from C code). It would let me simplify my code for the three wheeler and off load some of the processing being done on the nerdkit MCU if I could crack the code on this feature. Eric |
July 08, 2012 by esoderberg |
I hooked up a wireless link (via 2 XBee Pro, which worked great with minimal setup/learning curve) to record some of the data for the three wheeler. It should make refining the handling a little more rigorous than making adjustments based just on feel (although thanks to USNTPS I've made it work so far with this method). I'd like to be able to push more parameters on each run but as it is, I've gone from running at 400 Hz with no data link to about 200 Hz when sending 3 parameters, so for now I'm limiting what I send. Attached pic shows data for a series of S turns - green is tilt angle, blue is tilt rate, and red is steering input from joystick. My first impression is that the tilt rate signal is noisy as hell; I guess I shouldn't be surprised as the little 150cc engine gives the bike a pretty good rattle. I'm going to be doing a little more filtering to clean it up, but every time I adjust the filter I need to rework my PID parameters. At least now I'll be able to better see just what each adjustment is doing. Eric |
July 17, 2012 by esoderberg |
I'm doing a little clean up on my 3 wheel code and have been stumped: The function as written below works just fine - it reads multiple high and low bytes from a gyro FIFO buffer (in two's complement form) and returns a signed 16 bit value with the average of data from the FIFO buffer. Here's the part that I'm stuck on: if the MSB of the high byte is 1 than the converted 2's complement data should be negative and requires conversion to standard form; by my understanding this is equivalent to saying the shifted high and low bytes are > 32767. Yet when I use "if (((fifo_buffer_in[i2]<<8)+fifo_buffer_in[1+(i2)])>32767)" I get good data, but when I use the "if (fifo_buffer_in[i*2]>>7)", ie the statement that is commented out instead, dtilt_long always returns as a negative (around -65,000 when at rest). I could be content that it works as coded, but as I'm relying on this to keep myself from crashing I'd like to actually understand why what looks to be a simpler yet equivalent "if" statement is resulting in different results. Any thoughts welcome. Eric
|
July 17, 2012 by esoderberg |
One last item to note for anyone looking at the question above: when I just read the gyro register directly for one pair of bytes, without using the FIFO buffer, just looking at the MSB of the high byte in the "if" statement seems to work just fine using the code below.
|
July 17, 2012 by pcbolt |
Eric - That is strange. I'd be curious to see if...
would work. BTW, hope you didn't leave that semicolon there in line 24 above. The one thing that puzzles me is that you're returning a signed integer from the function, yet you're using a float number in the return statement calculation. That would worry me if I was handing over controls to the obedient little MCU brain. |
July 17, 2012 by esoderberg |
PCBolt, Tried your suggestion. That does not work either, gives same result as
As for returning a signed integer from a float, I have plenty of precision rounding to the nearest integer (the noise level is well above the lsb, which is down to milliradians/per second). Are there potential "bad" things that could happen, or does assigning a float to an integer reliably round down to the next integer? I could avoid it easy enough if there is a reason beyond the level of precision. Eric |
July 17, 2012 by esoderberg |
Drat!! Meant to say your suggestion gives same result as
|
July 17, 2012 by pcbolt |
Eric - I tested the float variables and you're right...it will simply round the result down with correct precision. I also tested the "if" statements and both worked for me. There was one problem though and it would make sense as to what you are seeing. When I computed the answer to this:
I got a negative number. Since "result" was declared an "int16_t", it did all the sign conversions correctly. In other words I did not need to add the "-65536" term. If this is the way your program is working, maybe the
is correct after all and since it is subtracting 65536 for each summing step, the average would be close to -65536. Still brings up the question as to why this works...
Two things might be happening. First, if the MCU doesn't know to extend the shift from an 8-bit variable to a 16-bit, the "fifo_buffer_in[i*2]<<8" would just get shifted away to 0. Second, if it did know to extend to 16-bits, but used signed integer logic, the test would never pass since it would be either less than 0 or less than 32767. If it jumps to the "else" statement..it never subtracts 65536. Just a theory. |
July 17, 2012 by pcbolt |
Eric - Almost forgot...if the MCU is computing the sign correctly, you would not need any "if" statements at all, you just need:
If the compiler warns about "signedness" you could try:
Good luck. |
July 18, 2012 by esoderberg |
PCBolt, Holy Cow! Your suggestion works, no if statements are necessary. It's amazing to me that my understanding of what was going on was so wrong, yet still managed to have it work. I definitely have a weakness when it comes to variable types; seems a majority of the time that I really get stuck on a piece of code, it's the consequence of variable types that I fail to fully account for in my logic. Thanks for helping me out. Eric |
July 18, 2012 by pcbolt |
Eric - Glad to help. I still don't have a complete grasp of the subject. I just know that I don't know and code defensively. Looking forward to seeing a video of the finished project. |
Please log in to post a reply.
Did you know that our USB NerdKit works on Windows, Linux, and Mac OS X? Learn more...
|