Relative Compass Heading


New Member
We are building soccerbots based on 28X Project Boards using AXE033, Lego Hitechnics Compass and IRseeker sensors on I2C. See thread here

The PICaxe is calculating absolute heading (range 0-360)

While all works brilliantly the compass reading needs to be used in a proportional control scheme for the drive motors. When programming in C this is not an issue as we convert to a relative (to a setpoint) heading using a few lines of code. Thought it would be just as easy in BASIC but unfortunately the PIC doesn't allow negative numbers. I have been trying today to get around this by calculating an error (ie deviation from setpoint) and a direction but I am having trouble finding a simple solution. I must be missing something obvious here.

I have failed to find anything I can use on the forum but surely I am not the first to need to solve this problem.

Can anyone offer me some guidance here.


Fast Freddy


New Member
the byte/word variables dont do negitives but they will under/over flow eg 0 - 2 in a picaxe word variable would equal 65534 take it away from 65535, add 1 and set a flag which sends a negative indication in the serial and you got your negative numbers
you will want to set the upper limit to 359 either way so 65535 - 359 = 65176 if the variable is larger than that it will be the range of the negatives

b4 = 32 ' default sending out a space

if w1 >= 65176 then
w1 = 65535 - w1 + 1
b4 = 45
end if

sertxd (b4,#w1)

Last edited:


I had to do something with negative numbers recently with my lunar lander project (see thread here)

I had to cope with positive and negative acceleration and velocity. Basically what i did was take a variable define the centre as 0 then used the values above or below for positive and negative.

For example (since I can't explain things well)
For a variable b0, 0-255, you define 128 as 0, 129 would then become +1 and 127 becomes -1, 126 = -2 and so on and so forth.

This works equally as well with word variables as well.


New Member
Just to close off the thread ........

It all works! Took a little time to get my head around it but all seems good now. Not sure about running the AXE033 in I2C mode - the conversions to ascii are a bit of a pain.

Thanks for all the inputs and I hope that this helps out someone in a similar "bind"

#picaxe 28x1

' PICAXE-28X1 sample program for Hitechnic NXT Sensors plus AXE033
' display in I2C mode.
' Note : As operating on 4.5V supply installed jumpers on J1 and J2
' Hitechnic NXT Compass Sensor (part MS1034)

'This program reads the HT Compass and calculates heading relative to
'the direcion the compass is facing when the processor boots up
'Compass reading (0-360) and relative heading (-180-180) are displayed
'on the AXE033 compass in I2C mode. We will probably switch over to
'serial mode for our soccerbots.

symbol heading_2degree = b0
symbol heading_adder = b1
symbol heading = w1 
symbol setdir = w2
symbol relBearing= w3
symbol delta=w4
symbol dir=b21
' Wires on NXT jack plug.
' Wire colours may vary. Pin 1 is always end nearest latch.
' 1 White 9V (for IRseeker)
' 2 Black 0V
' 3 Red 0V
' 4 Green V+ (4.5V or 5V)
' 5 Yellow SCL
' 6 Blue SDA
' Do not use i2c pullup resistor - already provided within sensor.

 'Slave address of compasss is $02
 'Slave address of AXE033 is $C6
 hi2csetup i2cmaster, $02, i2cslow, i2cbyte
 hi2csetup i2cmaster, $C6,i2cslow,i2cbyte
 'Optional configuration of compass
 hi2cout [$02],$41,($00)  ; normal mode
 ;hi2cout [$02],$41,($43) ; hard iron calibrate mode
 pause 500 
 hi2cout [$c6], 0,(254,1,255) ' clearing screen
 pause 100
 hi2cout [$c6], 0,(254,128,"  SHC Soccerbot ",255) ' just some random message
 pause 100
 hi2cout [$c6], 0,(254,192,"  set direction ",255)' another random message
 pause 2000
 'POINT COMPASS IN DEDIRED DIRECTION - this will become setpoint 
 ; read values from compass (address $02)
 hi2cout [$c6], 0,(254,192,"  calibrating...",255)' another random message
 pause 2000
 hi2cin [$02], $42,(heading_2degree, heading_adder) 
 pause 1000
 heading = heading_2degree * 2 + heading_adder
 hi2cout [$c6], 0,(254,1,255)' clearing screen


 ; read values from compass (address $02)
 hi2cin [$02], $42,(heading_2degree, heading_adder) 
 heading = heading_2degree * 2 + heading_adder

 bintoascii heading,b10,b11,b12,b13,b14'converting heading to ascii	
 relBearing = heading-setdir
 if relBearing >=0 and relBearing <180 then
 	delta=relBearing ' 0<relBearing<180
 	dir=1 ' positive direction
 elseif relBearing >=180 and relBearing <360 then
 	relBearing=relBearing-360 ' correction
	delta=65535-relBearing ' calculating magnitude
	dir=2 ' negative direction
 elseif relBearing >65355 and relbearing =< 65535 then
	relBearing=relBearing+360 ' correction
	delta=360-relBearing ' calculating magnitude
	dir=2 ' negative direction
 hi2cout [$c6], 0,(254,192,"<<<<Error>>>>",255)

 bintoascii delta,b16,b17,b18,b19,b20
 hi2cout [$c6], 0,(254,128,"Compass    ",b12,b13,b14,255) 'displaying heading (0-360)
 pause 100
 if dir=1 then gosub display1
 if dir=2 then gosub display2
 ; wait 1/10 second then loop
 pause 100
 goto main


hi2cout [$c6], 0,(254,192,"relative =+",b18,b19,b20,255) 'displaying positive relative heading (0-180)



hi2cout [$c6], 0,(254,192,"relative =-",b18,b19,b20,255) 'displaying negative relative heading (-180-0)

Last edited:


I see in the program remarks that you have:
"'Compass reading (0-360) and relative heading (-180-180) are displayed
'on the AXE033 compass in I2C mode. We will probably switch over to
'serial mode for our soccerbots."

Unless you need to read the time from a DS1307 RTC on the AXE033, you would be far better using the serial mode which provides some additional control/ease over the postioning and formatting of text.

Then instead of BINTOASCII heading, . . . . .
and HI2COUT . . .

you can consider using
SEROUT <pin>, <Baud>, (#heading, . . . )
depending upon what formatting you need (eg leading blanks for right justified numbers)


New Member
Agreed. The I2C is good from a wiring connections aspect but is a bit over complicated to use. Hooking up to serial comms on the AXE020, however, looks also to be another (unwanted) hardware hack. Have you hooked up AXE030 on axe020?
Seriously considering dumping the axe020 platform and designing our own custom board around the AXE200. I can set up PWM (another hack on the AXE020) as well then.


Technical Support
Staff member
Most project boards tend to be oriented towards specific tasks which can be limiting for things they were not designed to specifically cater for. It may be worth looking at the AX022 which is more like a 'break-out board' for 28 and 40-pin PICAXE ...


The AXE022 also provides:
  • locations for the i2c pull up resistors
  • a socket for an i2c EEPROM should you need one
I have a couple of them. Great with straight access to all PICAXE IO pins as hippy indicates