Users Examples

Forums:

Please post any examples you would like to share with other XLoBorg owners here :)

MikeRR's picture

Example software only gives the raw magnetometer x y z values:

mX = +00371, mY = -00053, mZ = +02539

This can be converted into a nicer 0-360 degree heading value by the following python code:

# get the heading in radians
heading = math.atan2 (my,mx)

# Correct negative values
if (heading < 0):
heading = heading + (2 * math.pi)

# convert to degrees
heading = heading * 180/math.pi;

Ready to run python program attached

Attachments: 

Does anyone know if there will be drift from the magnetometer over time? For instance, having taken a basereading today, do I need to adjust it tomorrow, next year etc?

piborg's picture

As far as we are aware there should be little or no drift in the magnetometer readings.
The main cause of a change will be:

  1. Change of environment
    e.g. placing inside a metal case
  2. Temperature
    the magnetometer should correct itself for this
  3. Local magnetic fields
    e.g. close proximity to a power sub-station, these are not correctable

If there are any other drift effects we would like to hear about them :)

Thanks for the info. Mine is indeed inside a metal case, a Proto Armour aluminium one in this instance. I'll let you know if it causes a problem.

piborg's picture

Hopefully it will work fine, the main thing is if you perform any calibration it should probably be done mounted in the case the same way it will be during operation.

clivej's picture

Like others posting here and in the other XLoBorg threads, I'm interested in getting orientation information from the device. I've got some with a visualiser written in Python and Tkinter. As Tkinter is available with Python 2.7.3 on the Pi, no additional software should be required.

At present, the app shows my naiveté in thinking the raw values from the magnetometer would be anything like heading, pitch, roll or yaw. Despite that, the accelerometer instruments look like they work and if the code helps, it is attached. EcoDriver.py defines classes for the app, xlosim7.py runs it and defines a callback to read from the board.

I'll keep following the discussions on this forum and if anyone has perfected the correction algorithms, I'd love to have a look.

Images: 

Are there any examples of using XLoBorg in something like a DiddyBorg to drive in a perfectly straight line based on a specified heading? I'm curious how accurately a wheeled robot can be controlled to travel in a fixed direction.

piborg's picture

We do not have any examples, but there are two basic ways of measuring course with an XLoBorg:

  1. Get a compass heading and compare with an intended heading
  2. Use the accelerometers to work out how much the robot is turning away from straight

Both methods have their own problems:

  1. When moving past a large metal surface (such as a radiator) the compass heading may become incorrect
  2. When the rotation is very gradual (e.g. small acceleration) the accelerometers may not be sensitive enough to detect it

With either method the correction applied to the robot is to steer him the opposite direction by slowing the motors down.
For example if he starts moving to the left you reduce the speed of the right motors slightly and he should straighten up.
We do this with the ball following example, but based on where the ball is relative to the center of the camera.

The datasheet indicates that it may be necessary to apply offsets to the compass readings, and that's what I've found, and until I did so I couldn't get the heading to go all the way through 360 degrees in turning the Pi through 360 degrees.

I got the offsets by taking the mX and mY readings then turning it through 180 degrees and taking further readings. The average of the mX readings and the average of the mY readings should ideally be zero, but if not, it represents an offset due to the chip itself and/or iron and DC current fields from the module and the Pi. You can get the mZ offset in a similar fashion by turning the Pi upside down.

I've modified XLoBorg.py to read the offsets from a file and to subtract them from the values returned by ReadCompassRaw, but the values for mZ are still all over the place with far more random fluctuation than mX or mY. Having modified xlosim7.py to display just 2 dials giving heading and magnetic dip, the heading dial works quite nicely but the dip is much less reliable. I'm not totally convinced that the offsets are stable from day to day.

I notice also that the temperature also seems to need an offset. Short of dunking the whole kaboosh in a bucket of ice and water, I don't see an easy way of determining it.

I also have the MPU-9150 9DoF sensor, so my next task is to see whether the magnetometer in that is any more usable.

Regards - Philip

piborg's picture

I am not sure why the temperature sensor is not calibrated in the factory, but it is fairly straight forward to calibrate.

What you want to do is get another temperature sensor which is already calibrated and mesure the temperature where the small black chip is and from the XLoBorg itself at the same time.

An easy way to do this is to place the Raspberry Pi with XLoBorg in a room with a nice stable temperature.
Place a normall thermometer next to the Raspberry Pi and give them both a while (say half an hour) to match the room temperature.

The difference between the two temperatures should be used as the offset.

Obviously, you can calibrate it within a degree or so like that, but for accurate calibration you'd need somehow to obtain tight thermal coupling between the chip and your reference thermometer. Anyway, I'm not interested in the thermometer beyond a simple demo, but I am interested in any other users' experience with calibration of the magnetometer, and whether other people have seen much greater random fluctuations in mZ than in mX or mY, as I have.

piborg's picture

We have not had much feedback from people on the subject, but based on my own observations the gains do vary a bit between the axes, but not as much as the offsets.

At least one other user has seen the same based on their calibration method:
Tilt Compensated Compass - working much better now!

Maybe their method is worth a go to see if it generates a better set of offsets?

The results should be fairly stable day to day, they should mostly be affected by proximity to metal objects or magnets.

Do the Z readings appear to be really erratic or just noiser then the X and Y ?

OK, so I modified ReadCompassRaw to take periodic measurements and write them to a .csv file. This is what Excel made of them!

This plot was taken from a run of 1000 samples with a 5mS delay in the loop, however, the 1000 samples took 10 seconds, so the loop was taking a total of 10mS per iteration.

As you can see, mX and mY are fairly stable but mZ has a nasty jitter at around 10Hz. Plotting all 1000 data points, no obvious periodicity is apparent.

I'm also attaching my version of ReadCompassRaw, so you can easily replicate my tests.

I looked at the other user's method for determining the offset, and it's over-complicated. So long as you rotate the module through 180 degrees, parasitic effects and stray fields will remain the same but the true field will be reversed and will be cancelled by taking the average, leaving the offset. This will be true whatever the initial alignment, so there is no need to align the module with magnetic North and magnetic dip. Much easier and more reliable to simply align it with the edge of your desk.

Regards - Philip

PS hoping the image and attachment work - previewing this gave the following error:
Notice: Undefined index: uri in image_field_formatter_view() (line 551 of C:\HostingSpaces\ntvomefu\piborg.org\wwwroot\modules\image\image.field.inc).

Images: 
Attachments: 
piborg's picture

Well that plot of Z values does not look normal at all...

I have attached an old image from when we were testing the XLoBorgs for movement response, you can see at the start that all three axes are fairly stable before being moved.

Unfortunately these readings were taken at an approximate 10 Hz, so they are not as detailed as yours are.

At this point it would seem that there is either a bug in the code, or the XLoBorg is faulty.

Have you tried this code with an unmodified copy of XLoBorg.py?

I will try and test your example here with the same values you used and see if I get the same results.

Images: 

I don't think it can be a bug in the code - it's hard to see how a bug would produce such random fluctuations, and anyway, a difference in the processing of mZ to the other two would hopefully stand out. Also, I've now produced a version of XLoBorg.py to interface to the MPU9150 9DoF sensor, and that gives stable mX, mY and mZ readings as well as credible temperature readings. (I got it incredibly cheaply from a Far Eastern eBay seller so wouldn't have been surprised if it had turned out to be a reclaimed factory reject, but in fact it seems to work rather well.)

It would be very interesting to see the results if you were able to test a few samples from stock. The attached new version of ReadCompassRaw.py calculates the mean and std dev of a number of samples, making the anomalous mZ variability stand out instantly. (Discount results from any run which included an i2c read failure - the exception is caught in the driver, so ReadCompassRaw just sees zero values which throw the std dev.)

The Absolute Maximum Ratings from the MAG3110 datasheet includes an applied magnetic field of 100,000uT, so a theoretical possibility is that that has been exceeded, though it seems unlikely. In any case, a Hall effect device (unlike a MEMS transducer) has no moving parts, so it's hard to see how a magnetic overload would have a serious effect other than taking the zero-field offsets out of spec. I've tested it with one or two small magnets salvaged from a magnetic catch on a mobile phone holder, but I took care not to bring them closer than a couple of cm.

Attachments: 
piborg's picture

Sometimes code bugs can manifest in strange ways.

For example swapping the high and low byte around in the code would produce something that looks similar to what you are seeing, it would also be a subtle enough bug to be easily missed.

To be clear I was suggesting the possibility of a bug in the XLoBorg.py code might be to blame, either by us or by the modifications you made for the offsets.

As far as I can see there is nothing that would cause this problem in your test script, however unless you have modified the InitCompass function in XLoBorg.py the compass will only refresh readings at 10 Hz.

It might help to see your modified copy of XLoBorg.py to eliminate that being the problem.

piborg's picture

I have managed to test a range of boards, and I do not see the problem you are experiencing.

Both of your scripts generate graphs which look very similar apart from offsets with the boards using the standard XLoBorg.py script (see attached image).

The standard deviation is slightly larger for Z, but not massively:
X → 2~3
Y → 2~3
Z → 3~5

I presume the difference is to do with the mounting on the PCB.
In any case this is without any gain or offset corrections applied.

I have attached the traces from both of your scripts from one of the boards so you can compare for yourself.

It would seem the culprit has been narrowed down to one of two things:

  1. The modifications to the XLoBorg.py script have caused an unwanted side-effect
  2. The XLoBorg you have has a fault with it which is only affecting Z for some reason
Images: 

Thank you, that's very interesting. I'll attach my XLoBorg.py for comparison but the changes seem to be insignificant in relation to this problem, mainly to do with reading offsets from a file and applying them, and calculating heading. In InitCompass I tried setting standby mode before setting CTRL_REG1as the datasheet seemed to imply that might be necessary, but it had no effect. I also fixed an insignificant bug in the line "# Disable reset cycle". Feel free to merge it into your git if you feel it's useful. It might then be appropriate to rename ReadCompassRaw as ReadCompass! I also have an xlosim7.py which you're welcome to which shows heading and dip instead of mX, mY and mZ, which are much better suited to a dial-type display.

It does seem as though our device has a dodgy Z sensor - much less of an impediment than had it been X or Y.

Regards - Philip

Attachments: 
piborg's picture

I have run the same tests again with your modified version of XLoBorg.py (with no offsets file), and I see no noticeable change in the output.

It would seem that we have managed to send you a board with a dodgy Z sensor, I have tried about ten different boards now and not seen the same problem.

Would you like us to send you out a replacement board?

Thank you for that kind offer. Let me contact you via the Sales Contact Form for shipping details.

Regards - Philip

Replacement XLoBorg arrived yesterday and seems fine. Thank you for a such an efficient resolution. Attached is a graph showing much more stable mZ readings in line with what you got. (Offset compensation has been applied.) Interesting though that the mZ standard deviation always seems to be slightly higher than mX and mY. If the mX and mY Hall effect sensors are fabricated in the plane of the chip, the mZ sensor would have to be perpendicular to it, which might then account for slightly different characteristics.

I've also attached a graph showing what happens during such a run if you rotate the device through 180 degrees and then turn it upside down.

Images: 

HI all,
in order to get magnetic filed measured, i would like to know the units in which this magnetomers trhows info. I mean: For instance:

mX = +00371, mY = -00053, mZ = +02539

What is the unit of these values? My objetive is to get nanoteslas in the end.

Regards and thank u!

According to the datasheet (which you can find at http://cache.freescale.com/files/sensors/doc/data_sheet/MAG3110.pdf) the sensitivity is 0.1μT per count, so divide the output by 10 to get it in μT, or multiply by 100 to get nT. The sensitivity and temperature coefficient of sensitivity are factory trimmed, the latter typically to 0.1%/degree C, however, it doesn't give a figure for the accuracy of the sensitivity itself.

Regards - Philip

Thanks pleriche!!

According to several websites, in order to get approximately a magnetic filed strengh, i have done this operation: sqrt(mX*mX + mY*mY + mZ*mZ).

Each time i move the sensor from place, 10 cm, the values change drastically.

May you please explain?

Thanks in advance.

piborg's picture

Before performing this field strength calculation you should first remove the offsets in mX, mY, and mZ.
You may also want to correct the scale of mX, mY, and mZ so that the units are equal.

This can be done using one of these calibration methods:
Compass offset
Tilt Compensated Compass - working much better now!

The offsets are the most important, they are likely to be the main source of the measurement error.

I want to create a vibration sensor and I am hoping this sensor can help me. Anybody have any code to detect vibration or when it stops?

Thanks!

Kurt

piborg's picture

I am not sure if this will do what you want, but bitreactive has an example of turning XLoBorg into an intruder detector:
http://www.bitreactive.com/intruder-detection-with-raspberry-pi/

What they have done to detect a vibration is add all of the acceleration values together (X + Y + Z) and compare them.
Gravity should be 1G, so if it is below or above 1G by too much you know it is being moved.
They use 0.95 - 1.05 as the "normal" range.

Their example also has a neat feature of being able to take a photo from the camera and send you an email.

This does really help. I am just getting started with my Pi and my first project is a little stupid. My wife is forever getting up to check the washer and dryer. I was thinking I could make something that would text her when vibration stopped. The problem is that vibration stops at various times in the cycle. Then, I thought I could text or email a photo of the display when the vibration stopped. Now, I gotta get a camera.

Thanks for the help. The application itself looks fairly simple except for sending a picture.

Fun stuff.

Hi lads!
So I've been trying myself at getting a heading from the magnetometer and I must say it wasn't easy, but in the end it works alright.

As someone said here, the main thing is the ZERO OFFSET
I had to offset my mX by almost 2000 and my mY by 1300 to get an approximate angle.
So thank you for the hint. It seems indeed mandatory to offset the readings.
Accelerometer works fine out of the box, no calibration needed.

I only calculate my heading with atan2(mY,mX) so far, but I've read another method that takes the tilt into account so I'll just give it in case peeps here want to give it a try.
It's in cpp but it's fairly readable (I hope):

note: Angers is where I live and AngersDecl is the inclination of Earth's mag field where I live (google your own location, there's a canadian website that gives this info out)

note2: zero offset and gain modification not included in this code.
m_accel[] is an array of 3 floats that collects the output of the accelerometer readings,
m_magnet[] is an array of 3 floats that collects the output of the magnetometer readings,
m_orient[] is the resulting yaw, pitch & roll (probably not in that order though, those words always confuse me)
and heading is the resulting horizontal angle that includes tilt compensation.
Also you'll need to include cmath obviously for the trigo functions as well as M_PI.

float AngersDecl = 0.4822222;
float accelmagnitude= sqrt(pow(m_accel[0], 2.0) + pow(m_accel[1], 2.0) + pow(m_accel[2], 2.0));
m_orient[1] = asin(-(m_accel[1]) / accelmagnitude);
m_orient[2] = asin(m_accel[0] / accelmagnitude);
float x = ((-(m_magnet[0])) * cos(m_orient[2])) + (m_magnet[2] * sin(m_orient[2]));
float y = (m_magnet[0] * sin(m_orient[1]) * sin(m_orient[2])) + (m_magnet[1] * cos(m_orient[1])) + (m_magnet[2] * sin(m_orient[1]) * cos(m_orient[2]));
float heading = atan2(y,x) + AngersDecl;
if(heading < 0){
heading += (2* M_PI);
}else if(heading > 2*M_PI){
heading -= (2* M_PI);
}
heading = heading * 180/M_PI;
heading = floor(heading);

Now note that I don't hope to get precision under one degree, but this calculation might be useful for flying drones because you get the other two axis in m_orient[1] and [2]. By the logic of this code I should put the result in m_orient[0], but I didn't, so there's that.
I'm making a rover myself but it's intended to work on slopes as well so I thought I'd make it tilt-compliant.

Thank you folks at piborg for this nice & affordable part.

You might be interested in two Instructables I published just a few months ago:
http://www.instructables.com/id/Simple-Manual-Magnetometer-Calibration/
and
http://www.instructables.com/id/Automatic-Magnetometer-Calibration/

I was particularly proud of the second Automatic calibration method, which was inspired by the iPhone magnetometer calibration procedure. This uses Arduino and the MPU-9150 magnetometer, but the same principles could equally be applied using a Pi and XLoBorg. On completion of the calibration procedure it simulates a compass with spirit level. I would think this is preferable for hand held use but if you're putting it on a drone or wheeled vehicle then obviously it's got to work whatever crazy angle it finds itself to be tilting at.

Regarding the cpp code you quote, I can understand in general terms what it's trying to achieve, but there should surely be a kind of symmetry between the expressions for x and y. I could believe the one for x but don't understand the one for y. Also, your value for declination is presumably in degrees, but you add it to a value delivered by the atan2() function, which will be in radians.

Regards - Philip

Thank you for your reply!
My declination is in radians, not in degrees, I just double checked.
As for the calculation itself however, I do not know what I'm doing, so I can't really say whether you're right or wrong. And I can't for the life of me find where I dug up the equations that I translated into cpp code. I wrote this, but definitely not the equations that originated it. I'll try to find them this weekend, as I will have some time to work on my thing. By the way this code, with a reading + a heading calculation every 100ms, only takes a couple of percents of a single pi CPU core, so it's fairly lightweight.
I was pretty happy with my solution until I shut it down for a week and then booted it back up, only to find out it gave me bad results, so there's that. Will get back on it tomorrow probably.
Your automatic procedure does look cool, I won't use it as-is because I don't have the hardware but I have plans -once I'm done with this wheeled robot- which could make good use of it. I'm waist-deep (and sinking) in image processing right now however, so I think I will settle for whatever I manage to do within a few hours of work!
Once I'm satisfied with my code I'll just post both my .h and .cpp here (at the risk of being torched down into nothingness by better coders than I am hehe).

Subscribe to Comments for &quot;Users Examples&quot;