Noobie help modifying code

Hi All

I am very new to Arduino and would like some help with a code.

I have been reading a old forum post

https://forum.sparkfun.com/viewtopic.ph … it=kontiki

I am using a HMC5883L compass and the original is for a HMC6343 which is discontinued.

I would like some help modifying the code as my attempts have been very wrong.

#include <Wire.h>
#include <Serial.h>
#include <Servo.h>

#define compassAddress 0x32 >> 1

Servo rudder;                     //Rudder servo object

const float minRudder = -75.0;
const float maxRudder = 75.0;
const float centerRudder = 90.0;
const float offsetRudder = 7.5;      //Deg to correct prop torque
const unsigned int smallWiggle = 10;
const unsigned long testDelay = 1000;
const unsigned long loopDelay = 1000;

byte compassReadingBytes[2];      //Heading read bytes from compass
unsigned int rudderCommand = 90;  //Command for rudder servo
float compassReading = 0.0;       //Reading from compass
float desiredHeading = 0.0;       //Heading to be followed
float errorDeg = 0.0;             //Error btw course and desired course
float Gain = 2.0;                //Gain for proportional loop
float rudderPosition = 0.0;       //Desired position of rudder
unsigned int loopCount = 0;       //Running loop count
unsigned long initTime = 0;       //Time when compass was initialized

void setup() {
  Serial.begin(38400);            //Start the serial port for testing
  Serial.println("Initializing the system");
  Wire.begin();                   //Start i2c
  // put any needed compass init code below this line
  
  // Wait for the compass to initialise
  initTime = millis();
  rudder.attach(9);               //Rudder servo on pin 9
  Serial.println("Doing a rudder servo test");
  //Command hard over
  rudderCommand = word(minRudder + 90);
  rudder.write(rudderCommand);
  delay(testDelay);
  //Command hard over the other way
  rudderCommand = word(maxRudder + 90);
  rudder.write(rudderCommand);
  delay(testDelay);
  //Command back to center
  rudderCommand = 90;
  rudder.write(rudderCommand);
  delay(testDelay);
  //check that enough time has passed for compass to be ready
  while(millis() - initTime < 500 ){
    delay(10);
  }
  //get an average of 10 readings to set desired heading
  for(int i = 0; i < 10; i++){
    readCompass();                 //Get heading from compass
    desiredHeading += compassReading/10.0;
    delay(210);
  }
  Serial.print("Desired heading is ");
  Serial.println(desiredHeading);
  Serial.println(" ");
  //Now do a quick rudder wiggle to let the operator
  //know that the tiki is ready for launch
  //Command -10 deg
  rudderCommand = 90 - smallWiggle;
  rudder.write(rudderCommand);
  delay(testDelay/4);
  //Command +10 deg
  rudderCommand = 90 + smallWiggle;
  rudder.write(rudderCommand);
  delay(testDelay/2);
  //Command back to center
  rudderCommand = 90;
  rudder.write(rudderCommand);
  delay(testDelay/4);
}

void loop(){
  loopCount++;
  readCompass();
   // compute how many deg offcourse tiki is
  errorDeg = compassReading - desiredHeading;
  if(errorDeg >= 180.0){
    errorDeg = errorDeg - 360.0;
  }
  if(errorDeg <= -180.0){
    errorDeg = errorDeg + 360.0;
  }

  // compute rudder position needed to correct error
    rudderPosition = constrain((Gain * errorDeg), minRudder, maxRudder);
  // translate that position into a servo command
  //rudderCommand = 90 - word(rudderPosition);
  rudderCommand = word(rudderPosition + centerRudder + offsetRudder);
  rudder.write(rudderCommand);
  Serial.print("Loop count is ");
  Serial.println(loopCount);
  Serial.print("Measured heading is ");
  Serial.println(compassReading);
  Serial.print("Rudder position is ");
  Serial.println(rudderPosition);
  Serial.print("Servo command is ");
  Serial.println(rudderCommand);
  Serial.println(" ");
  delay(loopDelay);
}

void readCompass(){
  //Instruct compass to read echoes
  Wire.beginTransmission(compassAddress);  // transmit to device
  // the address specified in the datasheet is 66 (0x42)
  // but i2c adressing uses the high 7 bits so it's 33
  Wire.write(0x50);                       // Send a "Post Heading Data" (0x50) command to the HMC6343 
  Wire.endTransmission();                 // stop transmitting

  //Wait for readings
  delay(2);                               // datasheet suggests at least 1 ms

  //Request heading reading from compass
  Wire.requestFrom(compassAddress, 2);    // request 2 bytes from slave device #33

  //Receive heading reading from compass
  if(2 <= Wire.available())               // if 2 bytes were received
  {
    for(int i = 0; i<2; i++) {
      compassReadingBytes[i] = Wire.read();
    }
  }
  compassReading = ((int)compassReadingBytes[0]<<8) | ((int)compassReadingBytes[1]);  // heading MSB and LSB
  compassReading = compassReading * 0.1;    //Translate heading to degress
  if(compassReading == 360.0){
    compassReading = 0.0;
  }
}

Thanks inadvance

The old device was a tilt compensated compass, the new device is a 3 axis magnetometer. They’re not exactly the same thing. You can use the magnetometer, process it’s outputs to be a compass but it won’t be tilt compensated and so if used on a 'tiki, the heading will likely change as the 'tiki rolls and pitches in the seas. Read this thread first …

http://forum.arduino.cc/index.php/topic,100672.0.html

I’m not sure that aligning the magnetometer w/the Earths field will work but it might help. ???

I believe there’s a library for the HMC5883L but according to this thread it might be “old” and needs the changes described herein …

http://forum.arduino.cc/index.php/topic,178645.0.html

Once you can read X, Y and Z values from the magnetometer you probably should calibrate it since they tend to be grossly out of cal. There’s more than a few threads here on that topic. And also on the processing/code to turn X, Y and Z measurements into a compass reading (that code is in the prior link). Read up on those before you decide to go ahead, it’s not a simple project for a complete newbie. You may find it easier to use this (also not tilt compensated) …

https://www.sparkfun.com/products/7915

More reading …

http://forum.arduino.cc/index.php/topic,143184.0.html

http://forum.arduino.cc/index.php/topic,197929.0.html

http://www.timzaman.com/?p=970&lang=en

http://playground.arduino.cc/Main/Inter … thHardware (see the Love electronic tutorial link)

Thanks I will order a HMC6352 and give it go. Is this likely to need any modifications to the sketch.

beretta:
Is this likely to need any modifications to the sketch.

Yes but I would think relatively minor ones. Off the top of my head you'll need to import a new library into your Arduino IDE and include that library at the top of your code, replacing the old include for the original compass. The I2C address will likely have to change. And then it's an issue of what library functions are named, you'll like have to change the names of some of the old compass functions to do the equivalent tasks w/the new library. Tracking these down can be annoying as it'll seem there's always one you missed, but it's do-able. There may be a different initialization routine. That all said it should be possible to find some basic sketch that initializes, and reads out, the compass using the library functions, that can be used as a good guide of what needs to be done.

As for libraries, I found at least two, there’s likely more. I don’t know if one is any better than another …

http://mbed.org/users/aberk/code/HMC6352/

https://github.com/misenso/HMC6352-Arduino-Library

There may be more out there too. Perhaps the last updated is the “best” ??? Google around and see what comments re:difficulties you can find.

Are you intending to use this in a 'tiki of your own ? If so I have more to say.

Yes I am going to use it in my own kontiki. I have just modified it and am setting it up to be controlled by rc at the moment but if

I can get the arduino working properly that will be the preferred option.

beretta:
Yes I am going to use it in my own kontiki.

If you've read the whole thread you listed then this may be redundant.
  1. Keep the compass away from the motor and wires carrying current. You don’t need the compass to be accurate but you do need it to be repeatable.

  2. While I think I fixed the 359 - 0 deg transition error, the OP in that thread never got to tweak the loop gain term (presently = 2). In any case it might need to be different for your 'tiki. If your’s is slow to respond when knocked offcourse then increase the gain. If it overshoots and tends to go both right and left of course and not settle down, then decrease the gain.

  3. The OP in that other thread used a tilt compensated compass and the one above isn’t. I’m not sure which is better. Your compass, when the 'tiki rolls or pitches but is otherwise still on-course, will indicate it’s off-course and so the 'tiki will steer off-course until it’s level again. Then it should steer to back on-course.

OTOH a tilt compensated compass shouldn’t suffer from the above but it does use an accelerometer to measure tilt. And so it’ll misread and mis-compensate for tilt when it undergoes acceleration, like when busting through surf ?

I have ordered a new compass which should be here by the end of the week. Hopefully all will go well with the setup.

It doesnt need to be super accurate. I am using my kontiki at the moment without any steering compensation and it is fairly controllable for the first 400m but after that the tidal current really takes over and that is where the compass is needed.

The commercial units use gps as well. I believe they use the compass to take the bearing and then the gps sets a waypoint 3kms away on that bearing so they run very straight and are very good but you pay a $1000 premium for a self steering unit.

Thanks again for the input. I will keep you informed on the result.

beretta:
… but after that the tidal current really takes over and that is where the compass is needed.

A lot will depend on how the tidal current carries the 'tiki. If it just sideslips, always pointing in the correct direction, then adding a compass won't help. Only a GPS could correct for that type error. Afterall the compass would read the same all that time.

Now if the 'tiki changes course … a compass could help.

I’m interested in reading your results. I was amazed at the prices some of the commercial 'tikis were charging and wondered if I shouldn’t start a business up here in the US ! :twisted:

A lot will depend on how the tidal current carries the 'tiki. If it just sideslips, always pointing in the correct direction, then adding a compass won’t help. Only a GPS could correct for that type.

The main problem is the nose is turned off course buy the current so I am sure a compass will help but a GPS is the best solution but I may be biting off more than I can chew at the moment. Definitely a future project.

My HMC6352 arrived today and I have spent all afternoon trying sketches and am only getting 0 deg heading which seems to be the main problem getting this compass to work.

This is the best code I have so far is

#include <Wire.h>
int HMC6352Address = 0x42;
// This is calculated in the setup() function
int slaveAddress;
int ledPin = 13;
boolean ledState = false;
byte headingData[2];
int i, headingValue;
void setup()
{
// Shift the device's documented slave address (0x42) 1 bit right
// This compensates for how the TWI library only wants the
// 7 most significant bits (with the high bit padded with 0)
slaveAddress = HMC6352Address >> 1;   // This results in 0x21 as the address to pass to TWI
Serial.begin(9600);
pinMode(ledPin, OUTPUT);      // Set the LED pin as output
Wire.begin();
}
void loop()
{
  // Flash the LED on pin 13 just to show that something is happening
  // Also serves as an indication that we're not "stuck" waiting for TWI data
  ledState = !ledState;
  if (ledState) {
    digitalWrite(ledPin,HIGH);
  }
  else
  {
    digitalWrite(ledPin,LOW);
  }
  // Send a "A" command to the HMC6352
  // This requests the current heading data
  Wire.beginTransmission(slaveAddress);
  Wire.write("A");              // The "Get Data" command
  Wire.endTransmission();
  delay(10);                   // The HMC6352 needs at least a 70us (microsecond) delay
  // after this command.  Using 10ms just makes it safe
  // Read the 2 heading bytes, MSB first
  // The resulting 16bit word is the compass heading in 10th's of a degree
  // For example: a heading of 1345 would be 134.5 degrees
  Wire.requestFrom(slaveAddress, 2);        // Request the 2 byte heading (MSB comes first)
  i = 0;
  while(Wire.available() && i < 2)
  { 
    headingData[i] = Wire.read();
    i++;
  }
  headingValue = headingData[0]*256 + headingData[1];  // Put the MSB and LSB together
  Serial.print("Current heading: ");
  Serial.print(int (headingValue / 10));     // The whole number part of the heading
  Serial.print(".");
  Serial.print(int (headingValue % 10));     // The fractional part of the heading
  Serial.println(" degrees");
  delay(500);
}

I’m interested in reading your results. I was amazed at the prices some of the commercial 'tikis were charging and wondered if I shouldn’t start a business up here in the US ! :twisted:

Yea I will come over and help set it up :smiley:

beretta:
My HMC6352 arrived today and I have spent all afternoon trying sketches and am only getting 0 deg heading which seems to be the main problem getting this compass to work.

I would install the library from here ...

https://github.com/misenso/HMC6352-Arduino-Library

… and then copy and try the example code to see if you can get a reading from the compass.

http://arduino.cc/en/Guide/Libraries

Thank you very much my friend that worked a treat. I installed the library and managed to figure out the changes to the original sketch and I have a working steering unit.

I haven’t played with the float gain yet which I take it is how fast the servo responds the compass movement.

What is the value of the numbers in the original sketch it is 2 is this seconds.

Once again thank you very much. I will keep you informed on progress in the near future.