Interfacing a digital compass with the RC

As an off-season project, my team wants to add a digital compass to this year’s robot. We are currently interested in the one featured here:

I was wondering if anyone has experience with this or other digital compasses or if anyone has specific advice for getting data from it with the robot controller.

The documentation says it can use PWM and I2C outputs (outputs on the compass, meaning inputs on the RC). Which of these would I want to use? Which pins would I connect it to on the controller?

Also, we’re looking for something that can handle spinning around pretty quickly without getting out of whack. How quickly does this compass update?

We planed on using on this season but we were unable to include it due to a lack of time. Ill see if i can get any notes from the programmer about it, and if you want i think we have a program that sends the orientation of the to the controller. It’s somewhat of a drivercentric prototype.

We had looked into using a compass on a few occassions. The ones we were looking at (and I am guessing this one as well) reguire a rather large current pulse or pulses to help calibrate and restore operation. The I2C reference is a car serial control protocol as I remember. Perhaps someone from the auto makers could elaborate on this. We had trouble working with our prototype depending on the building structure. Although we were able to get usable data in most locations, we didn’t want to depend on arena variables to prevent us from doing a good auto mode. FYI so you don’t get too discouraged, we spent some long hours trying to debug the compass while working on a stainless steel conference room table. Rack that up to late hours at the end of the build. It took us a while to realize where the error was coming from.


Please forgive a uninformed question but,
How would you use a digital compress in a robot?
And wouldn’t the electronics and metal of the robot throw it off a few dozen degrees?
Especially when inside a building.

Your only issue with the Inter-Integrated Circuit (I2C) communications is… none of the lines from the processor that do I2C are routed outside the board! :ahh:

If your working on an non-FIRST project, then definintely you can use I2C, however, on the FIRST RC you’ll need to use PWM.

According to the website that you ordered this from, the PWM signal updates at anywhere from 66ms - 102ms (or 9.8 - 15.2Hz, slower the closer you get to 359.9degrees).

If you need help doing PWM pulse timing, just give me a yell, didnt know if you just wanted advice with which way to go or what. You can checkthis postto see if it will help you any, but can’t remember if i said much on pwm timing here. Again, if not, just give me a yell back on this thread and i’ll be happy to help.

By the way just for my curiosity, what’s this compass for exactly? Why do you want to know which way your robot’s going? Arent you worried about flux fields from motors and such in your robot throwing it off?


That is part of the high current pulse for cal, etc. Car compass modules use this type of device. It requires some thought and planning as to placement but it is done all the time. Cars don’t really need to depend on direction when inside a building or structure so it is usually not a problem. I have had a car compass go a little whacky inside big garages or undergound though.

We have a holonomic drive train, and we want to use the compass to determine which way our robot is pointing so we can make a field-centric drive system. We aren’t worried about it being off relative to the Earth, we just need it to be consistently off.

We’re trying to use the 2007 RC for this project. Can it receive PWM input?

Ahhh I always wanted to try this! Though with the added bonus of a fluxgate compass in the OI pannel too, so a crab drive could always be relative to the OI pannel, even if the operator is walking with the robot. ANYHOW…

Absolutely it can recieve PWM input, thats the great thing about embedded processors, you can do about anything you want! If you need help with how to program up a pulse timer using a hardware timer and a PORTB external interrupt, i can definitely help, just get me in touch with your programmer and i’ll see what i can do.


You’re probably thinking of CAN. I2C a very short range, low speed serial interface and designed to be a simple interface between microprocessors/microcontrollers and various peripherals. The uses of I2C are basically the same as SPI - in some ways they could be considered to be competing standards (though many microcontrollers will support both interfaces). It is typically used to connect chips that are all on the same PCB, and isn’t that hard to implement in software if necessary.

Al, I’m going to step in here and defend the team that worked on this. Nate and the rest of the firmware team explored the compass as one possible solution to determining orientation, and we all knew that the room we were working in wasn’t a good location to test in. We never wasted long hours trying to figure anything like that out. We tested it in many locations, including at our field and in the model shop. The bottom line is that the compass we were using at the time (can’t remember the model #) was totally ineffective. When installed on the robot it didn’t report anything useful at all (the readings would change with fluctuations in motor speed, which is what we were afraid of). Adjusting the reading with the high-current pulse or whatever method that one used wouldn’t have made any difference (the compass we were using was not I2C - as I recall it output an analog signal).

The year this took place was 2003. We explored a bunch of options and ended up going with a gyro and integrating to get rotational position. This worked perfectly for the 15 seconds of autonomous, but unfortunately it would not be stable enough for Kelly’s needs (where it would need to maintain correct orientation for basically the whole match).

As for reading the PWM input, sometimes you can take the PWM output and run it through a simple RC circuit to convert it to an analog value that you could read directly with the RC.

Give me a pwm signal, a timer (internal peripheral) and an external interrupt (portb) and i’ll time you a pulse… :wink:

Have had to do this this year and in the past for getting distance data out of an ultrasonic sensor…


How hard is that?

Algorithm wise its easy peasy. Hardware wise, you’ll need to know how to use interrupts, and how to use a hardware timer… nothing too bad.

If you’d like to try, i’ll write up how you do it, just don’t want to take the time to write it till i’m sure somebody needs it. (call me lazy :o )


Yes, that’s not hard to do at all. I was simply offering a potential alternative solution in case the original poster isn’t comfortable using timer interrupts and such. Occasionally things which seem most obvious to one person can be very daunting to another.

We have a Devantech CMPS03 Digital Compass I would apresiate if someone could give me some step by step instructs on hw to do this, please.

I’ve been wanting to publish the code for this, as well as some other code, for quite some time, but I can’t get a hold of Kevin Watson to allow me to reprint parts of his code. So here’s the best I can do.

Step one: Get a copy of Kevin Watson’s interrupt code here.
Step two: Enable timer 1, set the prescaler to 1:8, change register operations to 8-bit accesses, and disable the timer 1 interrupt. These are all documented in Initialize_Timer_1(). Also, enable interrupt 1 in Initialize_Interrupts().
Step three: Add these declarations to the top of interrupts.c. Increasing the value of SAMPLES should decrease the noise in your readings, to an extent:

#define SAMPLES 1
unsigned char Temp_Buf;
unsigned int Timer_Snapshot;
unsigned int Readings[SAMPLES];
unsigned char p=0;

Step four: Replace the blank Int_1_Handler() with:

void Int_1_Handler(void)
  Temp_Buf = TMR1L;
  Timer_Snapshot = TMR1H;
  if(Temp_Buf == 0xFF)
  Timer_Snapshot <<= 8;
  Timer_Snapshot += Temp_Buf;
  TMR1L = 0;
  TMR1H = 0;
  Readings[p++] = ((Timer_Snapshot - 0x4000) / 125) % 360;
  p %= SAMPLES;

Step five: Add this to the end of interrupts.c (and add the appropriate prototype to interrupts.h):

unsigned int Get_Compass(void)
  int i,x=0;
  return x/SAMPLES;

Step six: Wire pin 1 on the compass to +5V on digital I/O 1 on the RC, pin 4 to signal, and pin 9 to ground.
Step seven: Call Get_Compass() to get the current reading from the compass… I can’t remember right now if the value is in degrees or tenths of degrees, but you should be able to figure it out pretty quickly.

Best of luck!*