HM55B compass module and Javelin
Don French
Posts: 126
Has anyone written the Java equivalents of the Basic code that comes with the HM55B compass module?·· So far I only looked at the TestDigitalCompass.bs2 program that comes with the package, and it doesn't look that hard except you need an ATN method and some code to simulate the·*/ (multiply middle) Basic·operator.· It appears that there is an ATN method on the yahoo javelinCode site, so I guess that solves the hardest part.· But if anyone already did the whole thing, I won't need to reinvent the wheel.
Comments
··· private static void readDirection(){
····· int angle;· // Store angle measurement
····· int prevAngle = 0;
····· while(true){
······· getCompassAxes();
······· angle = IntegerMath.atan2(-y, x); // Convert x and y to brads
······· angle = angle * 1406 / 1000;·· // mult by 1.406 (360/256) to convert to degrees
······· if(prevAngle != angle)
········· System.out.println(angle);·· // Display axes and degrees
······ prevAngle = angle;
····· }
··· }
··· private static void getCompassAxes(){
····· int dinDout = CPU.pin9;····· // transceives to/from Din/Dout
····· int clkHM55B = CPU.pin11;···· // sends pulses to HM55B's Clk
····· int enableHM55B = CPU.pin10;···· // enables HM55B
····· int statusHM55B = 0;
····· int resetHM55B = 0x0000;········ // Reset command for HM55B
····· int measureHM55B = 0x4000;······ // Start measurement (before shifting L)
····· int reportHM55B = 0x6000;········ // Get status/axis values (before shifting L)
····· int readyHM55B = 0x000C;········ // 1100 -> Done, 00 -> no errors
····· int mask = 0x7c00;···················// before shifting left one bit
····· mask = mask << 1;················ // to make it 0xF800
····· measureHM55B = measureHM55B << 1;· // to make it 0x8000
····· reportHM55B = reportHM55B << 1;· // To make it 0xC000
····· CPU.writePin(enableHM55B, ON);·· // ON is defined as true, OFF as false. (The enable pin is inverted)
····· CPU.writePin(enableHM55B, OFF);· // Prepare the HM55B for a command
····· CPU.shiftOut(dinDout, clkHM55B, 4, CPU.SHIFT_MSB, resetHM55B);· // Give it the reset command
····· CPU.writePin(enableHM55B, ON);
····· CPU.writePin(enableHM55B, OFF);
····· CPU.shiftOut(dinDout, clkHM55B, 4, CPU.SHIFT_MSB, measureHM55B);· //·Send the measure command
····· statusHM55B = 0x00;······················· // Clear previous status flags
····· while( statusHM55B != readyHM55B){··· // Status flag checking loop
······· CPU.writePin(enableHM55B, ON);
······· CPU.writePin(enableHM55B, OFF);
······· CPU.shiftOut(dinDout, clkHM55B, 4, CPU.SHIFT_MSB, reportHM55B);
······· statusHM55B = CPU.shiftIn(dinDout, clkHM55B, 4, CPU.POST_CLOCK_MSB );
····· }
···········
······// Cool!· the chip is ready to give up its data
···· // The BASIC routine gets all 22 bits with one SHIFTIN, but we have to do two.
···· //·· Could this be the problem?
····· x = CPU.shiftIn(dinDout, clkHM55B, 11, CPU.POST_CLOCK_MSB);
····· y = CPU.shiftIn(dinDout, clkHM55B, 11, CPU.POST_CLOCK_MSB);
····· CPU.writePin(enableHM55B, ON);··· //· Disable·chip
····· if( (y & 0x400) > 0) y = y | mask;· // if 11-bit is on, propagate the mask bit
····· if( (x & 0x400) > 0) x = x | mask;· // ditto
··· }
}
The Basic·source that I converted to Java·is available here:
····· ·http://www.parallax.com/detail.asp?product_id=29123
So, what happens when I run this program?· I get output but it isn't reasonable.· The angle values range from about -30 to 30.·· Rotating the compass does affect the output, so something is working.· When it just sits still, I get a fair amount of fluctuation.· Here are 100 angles reported without moving the compass (why are they negative?)
-4
-8
-4
-8
-4
-8
-6
-8
-4
-8
-3
-1
-8
-14
-10
-7
-1
-4
-8
-1
-8
-1
-14
-4
-8
-1
-6
-8
-1
-10
-8
-10
-8
-6
-10
-8
0
-6
-4
-8
-4
-8
-10
-6
-8
-10
-15
-4
-10
-4
-6
-10
-4
-8
-4
-6
-10
-8
-4
-7
-8
-1
-6
-4
-15
-8
-10
0
-10
-6
-4
-1
-6
-1
-8
-7
-4
-8
-6
-4
-14
-8
-4
-6
-4
-6
-10
-6
-8
-4
-10
-8
-10
-1
0
-8
-4
-7
-1
-10
Unfortunately, the device does not seem very useful. Without it moving at all, I get the the following range of results in a few seconds time:
43
50
45
50
45
47
45
50
47
50
45
47
50
45
47
51
This is with the sensor installed on the Javelin prototyping board. Maybe it will improve with it moved away. Anyone get any better results than this?
·· I'm glad you got that little problem worked out!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Chris Savage
Parallax Tech Support
csavage@parallax.com
· /**
·· * Calculate arctan value of y/x
·· *
·· * @param y y-value
·· * @param x x-value (should not be 0 !!!)
·· * @result arctan(y/x)
·· */
· /* absolute value of parameters should */
· /* be less than 1000 to prevent overflow */
so you must scale x and y before applying atan2(y,x)
Your x and y are 11 bits so their range is 0 to 2047 (or -1024 to +1023)
I suggest to rightshift x and y by 1 bit
x >>= 1;
y >>= 1;
if (x & 0x200 != 0) x |= 0xFC00;· //range -512 to +511
if (y & 0x200 != 0) y |= 0xFC00; //ditto
Also note that atan2 is an approxiamation.
regards peter
·
I have compensated for the fluctions in the angles by averaging over 20 samples.· The average holds to within a degree.
I found a much more serious problem though.· I quite frequently get an undefined status value·of 8 returned from the module.· Sometimes when I run the program, I get nothing but 8's.· Other times I get 0 (not ready)·for a few iterations and then a 12 (ready to read), which is as expected.· When it works correctly, I can run the program·seemingly forever without having·a problem.··When it works incorrectly, it also does so forever.· Usually, resetting the Javelin does not correct the problem.· Unplugging it and waiting for a while seems to help. ·Any idea what is going on?
For example: if 2 angles +1 and +359 are averaged you get +180
which is 180 degrees in error because you want 0 degrees.
The x for +1 degree equals the x for +359 degree.
The y for +1 degree is minus the y for +359 degree so the average y is 0,
which yields 0 degrees.
regards peter
·
Any idea of why the status value the device returns is an 8 for a valid status some of the time and a 12 other times? I haven't tried using the device with a BS yet, but if it works the same way it does with a Javelin, people are going to have problems using the example code Parallax provides.
http://www.parallax.com/dl/docs/prod/compshop/HM55BDatasheet.pdf
section 5.2 , 5.3 and 5.4 show
end··error
A A· B B
When AABB = 1100 (eg. 12) measurement is completed without error
AABB = 1000 (eg. 8) is not defined but also indicates normal completion of measurement
I think you should test for
1100 = ok
1111 = AD overflow
00XX = not ready
regards peter
Don't you mean I should check for 1100 and 1000 as OK conditions?
I guess in case of overflow you just reset and try again.· Any idea what causes the overflow condition?
In any case, Parallax should change the sample code they provide for this device if 1100 and 1000 are both valid OK statuses and either one can and does occur.·
-- Don
Discard the values read when status is 1111 (AD overflow) or 00XX (not ready).
Any other value than the above should be treated as invalid, just start
a new sample sequence.
regards peter
but maybe it is wise to study the timing diagrams on the datasheet more closely.
On the other hand, if status=8 appears to return valid x and y values, use them.
(but then maybe status=4 is also valid)
regards peter
Feel free to complete it with the mathematics.
http://forums.parallax.com/showthread.php?p=544194
CPU.writePin(Clk, false); // Initialize Clk for delivering positive pulses.
Was there an equivalent line in the BASIC code? If so, I must have missed it. I will try this when I get home just to see if that was the problem. But as i have already posted, checking for either an 8 or a 12 status seems to also fix the problem.
I just checked the approximation method of computing atan2 that I think you pointed me to, and it is pretty good.· The most it ever is off is 1.315 degrees, based on running 10,000 combinations of x and y through it.
I needed to do this check·because my compass is not giving me good results and I wasn't sure if it was the atan2 approximation.··· I did a test where I rotated my device at a constant speed and took a reading every second.· The difference between readings repeatably varied from 2 degrees per second·to 22 degrees per second, depending on which direction·the compass·was pointing.· I have the motors doing the rotating completely enclosed in the film equivalent of mumetal, so I don't think it is that.· But something is causing this inaccuracy.· I wonder if it could be the presence of a reed relay on a chip·that is near by and which is turned on at the time of rotation.· I will have to do more experiments.· I have the compass mounted on the Javelin Demo board prototype area and there are a few other wires near it.· But they all rotate along with the compass, so I would think that their presence would have a constant effect rather than one that depends on the direction the device is pointing.· My next experiment is to take the compass off the prototype board and put it a foot up in the air away from the Demo board.·
-- Don
The url mentioned in the class
http://www.acroname.com/brainstem/examples/math/math.html
also has plotted curves of the approxiamation (excel spreadsheet)
regards peter