Page 1 of 4

Experimental Gyro Compass (LeJOS)

Posted: 08 Jan 2011, 13:01
by kvols
Hi all

I've been experimenting with a gyro sensor based compass. There has been a few surprises in the process, and I'd like to share the program and some experiences with you.

I'm using the HiTechnic Gyro Sensor and LeJOS.

First surprise is how amazing precise this sensor actualy is. It can actually work as a pretty precise compass that doesn't get affected by magnetic fields or weather it's level.

The sensor does however drift a bit, and I've used some simple tricks to avoid it in the sample below (Does anyone know how to attach a Java program?)

I have heard that a "Kalman filter" could help improve the accuracy of the sensor readings. Does anyone here have experiences with such a filter? Some usable source code perhaps...? (NO this is NOT for a school project! ;-))

Regarding the enclosed code: Use and experiment as you find fit, and please post your experiences here... Please note that it's experimental, and comes with absolutely no warranty, so please do not use it for missile guidance or something...

Kind regards
Povl

Code: Select all

import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.SensorPort;
import lejos.nxt.addon.GyroSensor;


/**
 * This is an experimental test class to study the HiTechnic Gyro Sensor for use as a gyro compass..
 * 
 * The class is not in a finished state, and is only meant for experiments.
 * 
 * @author kvols
 *
 */
public class GyroCompassTest implements Runnable {

	public static final int SAMPLE_RATE= 5;
	
	private final GyroSensor gs;
	// Heading in 1/1000 degrees
	private int heading = 0;
	// Sensor offset in 1/1000 degrees/s
	int sensorOffset;

	public GyroCompassTest(GyroSensor gs) throws InterruptedException {
		this.gs = gs;
		// Find a reasonable offset
		for (int i = 0; i < 20; i++) {
			sensorOffset += gs.readValue();
			Thread.sleep(3);
		}
		sensorOffset *= 50;
		// Start the sensor sampler
		Thread t = new Thread(this);
		t.setDaemon(true);
		t.start();
	}

	/**
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws InterruptedException {
		GyroSensor gs = new GyroSensor(SensorPort.S1);
		GyroCompassTest gt = new GyroCompassTest(gs);

		while (!Button.ESCAPE.isPressed()) {
				if (Button.ENTER.isPressed()) // Set to zero
					gt.heading = 0;
			Thread.sleep(25);
			LCD.clear();
			// Display the heading rounded to nearest degree:
			LCD.drawInt(gt.sensorOffset, 5, 5);
			// Display the current estimated sensor offset (1000nds):
			LCD.drawInt((gt.heading+500)/1000, 5, 3);
		}
	}

	@Override
	public void run() {
		int av = 0;
		int oldAv;
		int err = 0;
		int errCount = 0;
		long time = System.currentTimeMillis();
		try {
			Thread.sleep(SAMPLE_RATE);
			for (;;) {
				oldAv = av;
				av = gs.readValue() * 1000 - sensorOffset;
				// Detect no movement and fine tune the offset
				if (av >= -1000 && av <= 1000) {
					err += av;
					errCount++;
					// Tune the offset if still for some time
					if (errCount == 30) {
						// Let the offset converge to prevent over-compensation:
						sensorOffset += err / (errCount*2);
						// Adjust the current heading, to prevent idle drifting:
						av = -err;
						errCount = 0;
						err = 0;
					}
				} else {
					errCount = 0;
					err = 0;
				}
				// Calculate the absolute rotation
				int dt = (int) (System.currentTimeMillis() - time);
				time += dt;
				heading += ((oldAv + av) * dt) / 2000;
				// Sleep or some time
				Thread.sleep(SAMPLE_RATE);
			}
		} catch (InterruptedException e) { // Just stop if interrupted!
		}
	}
}

Re: Experimental Gyro Compass (LeJOS)

Posted: 08 Jan 2011, 13:21
by mightor
Regarding the enclosed code: Use and experiment as you find fit, and please post your experiences here... Please note that it's experimental, and comes with absolutely no warranty, so please do not use it for missile guidance or something...
Great, thanks for dashing my hopes for world domination!

Here are some posts by Aswin, one of the forum regulars, who was dealing with the same gyro issues:
http://nxttime.wordpress.com/2010/11/03 ... and-drift/
http://nxttime.wordpress.com/2010/10/06 ... an-filter/
http://nxttime.wordpress.com/2010/10/05 ... blem-less/

There are loads more like it on there, so be sure to read all the stuff on that blog. It's in ROBOTC but that shoudn't stop you.

- Xander

Re: Experimental Gyro Compass (LeJOS)

Posted: 08 Jan 2011, 13:36
by kvols
Cool - thanks, Xander!

I'll do some more (re)searching. :)

Re: Experimental Gyro Compass (LeJOS)

Posted: 08 Jan 2011, 13:51
by HaWe
by theory the Kalman filter erases noise which is Normally (Gaussian) distributed.
If the Gyro sensor values tend to drift, they are not supposed to be Gaussian distributed.
The same issue it's to Compass and Odometry (compass error by ferromagnetic disturbance, drift, slip).

For non-Gaussian noise a different (non-linear) filter model is needed, e.g. a stochastic filter like Monte Carlo Filters, also called Particle Filters.

I just purchased a Gyro from HT, and I'm curious how to implement a Monte Carlo Filter (NXC) for Gyro, compass, and odometry, and maybe an additional accelerometer sensor.

I assume it's the easiest approach not to use the raw sensor data as filter inputs but the calculated positioning and heading based on the single sensor readings. By this approach you have the same mathematic dimensions which therefore can be compared and filtered by similar 3D matrices (x_pos, y_pos, heading) (sorry for my poor English, and sorry for my fragmentary maths knowledge ).

Re: Experimental Gyro Compass (LeJOS)

Posted: 08 Jan 2011, 14:20
by kvols
That is a very good point, Doc!

My initial guess was that inaccuracies would even themselves out in the integration of the sample values, and that appears to be correct!

The drifting of the sensor is a bit of a problem though. The sensor value seems to be decreasing slowly with the battery voltage and increasing temperature. My simple method of adjusting the sensor offset seems to almost work, but it appears to set the sensor offset a bit too low, and I cannot find the bug. When the sensor is moving I haven't found a way to adjust for drifting....

The algorithm is not very sensitive to the sampling time. If I sample every 10 ms instead of 3 ms, the heading readings are still pretty accurate, though I cannot change rotations quite as fast. Using a nanosecond timer instead doesn't appear to improve accuracy, and it does give other issues in the calculations.

Please post your findings NXC, LeJOS, ...

Kindly,
Povl

Re: Experimental Gyro Compass (LeJOS)

Posted: 08 Jan 2011, 16:53
by HaWe
as far as I can see you are using Euler integration which often calculates with big inaccuracies:

Code: Select all

 time += dt;
heading += ((oldAv + av) * dt) / 2000;
AFAIR I once read a code for a Segway using a gyro which integrates by a Runge Kutta algorithm which indeed is a far better alternative.
IIRC it was muntoo who once posted an assay about this integration algorithm issue: http://gafferongames.com/game-physics/i ... on-basics/

HTH!

Re: Experimental Gyro Compass (LeJOS)

Posted: 08 Jan 2011, 17:25
by HaWe
BTW, as I'm just about to find a RK4 method for my own gyro in NXC:

how is the rotation speed (degree per second) calculated out of the gyro value?
is this already the correct unit of measurement [degree/sec] by this formula:
gyroSpeed [degree/sec] = gyroRaw - gOffset
?

Re: Experimental Gyro Compass (LeJOS)

Posted: 08 Jan 2011, 18:23
by kvols
The sensor is an analog sensor, returning values from 0..1023 (10 bit AD). A motionless sensor usually returns a value around 600 (its offset value), but that can change depending on battery voltage and temperature, and it varies from sensor to sensor. Clockwise rotation returns a larger value and vise versa. If the sensor offset is 610, and the value returned is 600, the sensor is currently rotating at a rate of 10 degrees/s counter clock-wise.

Several issues are involved for reading accurate values: The sensor is a bit noisy, and the offset is constantly moving a bit up and down. Except for the noise, the sensor appears to be quite accurate.

Euler integration... I actually thought I did midpoint integration... I'll have to dig into this! ;-)

Thanks again for your comments!

Povl

Re: Experimental Gyro Compass (LeJOS)

Posted: 08 Jan 2011, 18:47
by HaWe
so in this case the formula above is actually correct?
gyroSpeed [degree/sec] = gyroRaw - gOffset
gyroSpeed = 600 - 610 = 10 [degree/sec]

ps
Euler? Midpoint? maybe I have to dig into this ;)

Re: Experimental Gyro Compass (LeJOS)

Posted: 08 Jan 2011, 18:51
by gloomyandy
Looks to me like you are doing midpoint integration. You may want to try using a sample rate of 4ms rather than 5ms. Because of the way that the A/D sample rate and the ATMega to Arm chip communication rates interact I find (that with leJOS at least) that this is the fastest sample rate that also minimizes jitter...

Doc. Looking at the comments on the article it would seem that RK4 may not be suitable for situations where you get a set of discrete values rather than have a continuous function (see the comment about calculating velocity/position from an accelerometer reading). Will be inteersting to see if you get better results using this than you get with midpoint...

Doc You may also find that the offset changes over time (due to battery voltage and temperature effects). When I played around with this I found that the offset would change a fair bit when you first start to use the sensor (I think this may possibly be to self heating effects). It then seems to settle down but voltage drop can also impact it.