code not working

ARRRRGGGGH!

So this code is for that Ardubot project I’ve been working on. It starts up, gets its heading from a compass sensor (hmc6352) , goes forward until it sees something in the way, and then IS SUPPOSED TO turn right and stop after the heading is about 90 degrees higher than it was previously (it makes a right 90 degree turn.)

It works all the way up to the point where it starts turning. But it never stops the motors. The compass works.

Here’s the code:

#include <Wire.h>

int rangelow;
int rangehigh;
int irdistance = 1;
int irsensed = 1;
int turning = 0;
int HMC6352Address = 0x42;
int slaveAddress;
byte headingData[2];
int i, headingValue;
int headingStart;
int headingTurn;
int done = 0;
/////////////////////////////////////////////////////////////
void setup() {
  getHeading();
  headingStart = headingValue / 10;
  rangelow = headingStart + 85;
  rangehigh = headingStart + 95;
  delay (500);
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);
  digitalWrite(3, HIGH);   
  digitalWrite(5, LOW);    
  digitalWrite(6, LOW);   
  digitalWrite(9, HIGH);
}
/////////////////////////////////////////////////////////////
void loop() {
  irsensed = analogRead(0);
  irdistance = irsensed;
  if (done = 1) {
    if (irdistance >= 488 && irdistance <= 536) {
      turning = 1;
    }
    if (turning == 1) {
      digitalWrite(3, HIGH);
      digitalWrite(5, LOW);
      digitalWrite(6, HIGH);
      digitalWrite(9, LOW);//STOPS WORKING HERE!!!!!!!!!!!!!!!!
      getHeading();//the getHeading routine is below.
        headingTurn = headingValue / 10;
        if (headingTurn <= rangehigh && headingTurn >= rangelow) {
          done = 0;
          digitalWrite(3, LOW);
          digitalWrite(5, LOW); 
          digitalWrite(6, LOW);
          digitalWrite(9, LOW);
        }
    }
  }
}
/////////////////////////////////////////////////////////////
void getHeading() {
    Wire.beginTransmission(slaveAddress);
  Wire.send("A");              // The "Get Data" command
  Wire.endTransmission();
  delay(1);                   // The HMC6352 needs at least a 70us (microsecond) delay
  // after this command.  Using 1ms 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.receive();
    i++;
  }
  headingValue = headingData[0]*256 + headingData[1];  // Put the MSB and LSB together
}
/////////////////////////////////////////////////////////////

PS: The compass heading code is from the Arduino Playground.

Selenaut,

Here’re some questions that, I hope, will point you (or us, if you post the answers) in a helpful direction:

  • - How is your code supposed to handle cases in which the starting heading is > 275? In such cases, the range in which you’ve told it to stop turning appears to be outside the range of a compass. For example, if you start at 280, then the range in which it will stop turning is 365 to 375, but a compass should return a value of 10 after a 90 degree turn from 280.
  • - You said "the compass works", but how do you know? Put another way, if you add a write to a screen as part of your compass reading routine, what does it display?
  • - You appear to have defined an integer value to hold a non-integer result. Using your example, if headingValue = 1345, headingStart = headingValue / 10 = 134.5.
  • - Why use a "void" subroutine that assigns a value to a global variable rather than a subroutine that returns the value?
  • - Where/how is the value of "slaveaddress" assigned?
  • - Was this intended to move in the initial direction, turn if it sensed an object, then stop?
  • - Is "turning" the variable that is supposed to cause the robot to turn? I see where you initialize it as 0 and where IR detection of an object causes it to be set to 1, but I don't see where detecting the completion of the ~90 degree turn sets "turning" back to 0.
  • - What is the intended use of "done"?
  • - What does the program do when it gets to the line you've marked as the stopping point, halt execution, or get stuck in some loop?
  • I need to run along now, but please let us know what you find.

    TIA,

    Eric

    1. I was actually thinking about that as I posted the code. I’m adding that later today.

    2. In the PS in my original post, I said that the compass code was from the Arduino playground. I loaded that up by itself and it worked great - and yes, it did have serial feedback, so I know it works.

    3. I wasn’t quite sure how to go about that. Could that be the source of the issues? What type of variable should it be?

    4. Again, I wasn’t exactly too sure how to add that in without having to literally paste it into the code two to three times (which would increase the size of the code considerably).

    5. I’ll give you the link to the compass code at the end. I’m not exactly too sure myself. :?

    6.Yes. In the end it will go all the way around the object, continue on for a bit, and stop. For now I’m just testing each step as I go along.

    1. Yes, and it’s not supposed to - yet. See 6.

    2. It’s supposed to signal to the bot that it has completed the task (so that I don’t end up running down the hallway trying to catch up with it).

    3. It just stops. And sits there.

    BTW, here’s the link to the compass code: http://www.arduino.cc/playground/Learning/Hmc6352

    Hey, thanks for the feedback so quickly - this code was driving me crazy trying to get it to work.

    After re-checking my code Irealized a few things were wrong, so:

    1. fixed “if (done = 1)” to “if (done == 0)”

    2. added slaveAddress code so that it actually KNOWS where the compass is. Duh.

    Here’s my modified (and newly commented!) code:

    #include <Wire.h>
    
    int rangelow;
    int rangehigh;
    int irdistance = 1;
    int irsensed = 1;
    int turning = 0;
    int HMC6352Address = 0x42;
    int slaveAddress;
    byte headingData[2];
    int i, headingValue;
    int headingStart;
    int headingTurn;
    int done = 0;
    /////////////////////////////////////////////////////////////
    void setup() {                                     //Note: the following four lines of code are not mine.
                                                       // 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
      getHeading();                                    //(My own code continues here.) Uses below routine to get the heading of the robot.
      headingStart = headingValue / 10;                //This sets up a variable called headingStart that gives a real heading and saves it as its initial heading.
      rangelow = headingStart + 90;                    //this sets up the threshold for the turn later in the code (see loop).
      delay (500);                                     //Just for good measure.
      pinMode(3, OUTPUT);                              //These four
      pinMode(5, OUTPUT);                              //lines of code
      pinMode(6, OUTPUT);                              //are to set
      pinMode(9, OUTPUT);                              //the motors up.
      digitalWrite(3, HIGH);                           //And these
      digitalWrite(5, LOW);                            //four are to
      digitalWrite(6, LOW);                            //get them to
      digitalWrite(9, HIGH);                           //go forward.
    }
    /////////////////////////////////////////////////////////////
    void loop() {
      irsensed = analogRead(0);                        //Gets distance of object in front of the robot.
      irdistance = irsensed;                           //Doublechecks. I added this in because the sensor sometimes would just return 0.
      if (done == 0) {                                 //fixed this. Its purpose is to make sure it doesn't keep going and going.
        if (irdistance >= 488 && irdistance <= 536) {  // if an object is about 20 cm away
          turning = 1;                                 //this tells itaself that it needs to start turning, hence the name of the variable.
        }
        if (turning == 1) {                            //If it is beginning its turn
          digitalWrite(3, LOW);                        //stop both motors
          digitalWrite(5, LOW); 
          digitalWrite(6, LOW);
          digitalWrite(9, LOW);
          delay(500);
          getHeading();                                //allows for a doublecheck of the initial heading
          headingStart = headingValue / 10;
          digitalWrite(3, HIGH);                       //turns right
          digitalWrite(5, LOW);
          digitalWrite(6, HIGH);
          digitalWrite(9, LOW);
          getHeading();                                //From here on it is supposed to stop after it has turned right 90 degrees.
          headingTurn = headingValue / 10;             //I have no idea as to why it isn't working.
            if (headingTurn >= rangelow) {
              done = 1;
              digitalWrite(3, LOW);
              digitalWrite(5, LOW); 
              digitalWrite(6, LOW);
              digitalWrite(9, LOW);
            }
        }
      }
    }
    /////////////////////////////////////////////////////////////From here on, it is not my code.
    void getHeading() {
        Wire.beginTransmission(slaveAddress);
      Wire.send("A");              // The "Get Data" command
      Wire.endTransmission();
      delay(1);                   // The HMC6352 needs at least a 70us (microsecond) delay
      // after this command.  Using 1ms 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.receive();
        i++;
      }
      headingValue = headingData[0]*256 + headingData[1];  // Put the MSB and LSB together
    }
    /////////////////////////////////////////////////////////////
    

    Okay, so the above code that I just fixed works - up until the point where it stopped working in the first place. But now, there’s a ticking noise, coming from either the Arduino or the motor driver - I’m not sure. And I’m guessing that it’s either stuck, or something broke. But I can reset it and it will start over. By the way, I figured out that you can trim the motors by adding potentiometers. I’m pretty sure this isn’t amazing, but it helps to keep it from going out of control (it was originally popping wheelies).

    Selenaut:

    1. I was actually thinking about that as I posted the code. I’m adding that later today.

    If you haven’t found it already, take a look at [modulo.

    Selenaut:
    2. In the PS in my original post, I said that the compass code was from the Arduino playground. I loaded that up by itself and it worked great - and yes, it did have serial feedback, so I know it works.

    I accept that you’ve confirmed that your hardware works and that there is code that will exercise it. However, that’s not evidence that your code is communicating successfully with the hardware. Try putting the serial feedback in your code, so you can see what it’s doing.

    Selenaut:
    3. I wasn’t quite sure how to go about that. Could that be the source of the issues? What type of variable should it be?

    [Float comes to mind, but you should familiarize yourself with the [available data types and get in the habit of using the smallest one that meets your needs without having to encode/decode to shoehorn the information into the variable. For example, you have a couple of variables that appear to be restricted to the range 0,1. Those could be bit variables. At the moment, you’re probably nowhere near the memory limit, but the sooner you get in the habit of doling out memory as stingily as you can, the less time you’ll spend in life struggling to fit things.

    Selenaut:
    4. Again, I wasn’t exactly too sure how to add that in without having to literally paste it into the code two to three times (which would increase the size of the code considerably).

    See [the Function Declaration page in the Arduino reference.

    Selenaut:
    5. I’ll give you the link to the compass code at the end. I’m not exactly too sure myself. :?

    I took a quick look at the code to which you linked and found it contains:

    // 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
    

    but your code does not. It seems to me that this is a fatal omission.

    Selenaut:
    6.Yes. In the end it will go all the way around the object, continue on for a bit, and stop. For now I’m just testing each step as I go along.

    Your approach makes sense, but I don’t see how your code is supposed to stop.

    Selenaut:
    7. Yes, and it’s not supposed to - yet. See 6.

    What in your code do you believe should stop the turning?

    Selenaut:
    8. It’s supposed to signal to the bot that it has completed the task (so that I don’t end up running down the hallway trying to catch up with it).

    How is the Arduino supposed to check the value of and respond to a change in the value of “done”?

    Selenaut:
    9. It just keps spinning - and spinning, and spinning, and spinning…

    If you address the uses of “turning” and “done”, you should be able to correct this behavior.

    Selenaut:
    Hey, thanks for the feedback so quickly - this code was driving me crazy trying to get it to work.

    You’re welcome!

    Happy Hunting,

    Eric](http://arduino.cc/en/Reference/FunctionDeclaration)](Arduino - Home)](http://arduino.cc/en/Reference/Float)](http://arduino.cc/en/Reference/Modulo)

    Selenaut:
    Okay, so the above code that I just fixed works - up until the point where it stopped working in the first place.

    It appears that you were fixing things while I was writing suggestions, so you’re welcome to ignore the suggestions that pertain to the compass address. However, I still don’t see you resetting “turning” when the end of the turn is completed.

    Selenaut:
    But now, there’s a ticking noise, coming from either the Arduino or the motor driver - I’m not sure. And I’m guessing that it’s either stuck, or something broke.

    Those failure modes might well cause “ticking”. However, I suspect it’s because you are starting and stopping the motors in the turning loop.

    Selenaut:
    But I can reset it and it will start over. By the way, I figured out that you can trim the motors by adding potentiometers. I’m pretty sure this isn’t amazing, but it helps to keep it from going out of control (it was originally popping wheelies).

    If you are using a motor driver external to the Arduino, it should provide some means of speed control. If you are driving the motors directly from the Arduino (which works for very small motors), I suggest you poke around the Arduino site, starting [here, for information on software motor speed control.

    Happy Hunting,

    Eric](analogWrite() - Arduino Reference)

    This happened…

    Beginning setup...
    getting heading...
    Setup completed.
    Beginning turning sequence...
    getting heading...
    Heading found.
    0
    getting heading...
    Heading found.
    0
    

    from this:

    #include <Wire.h>
    
    float rangelow;
    int irdistance = 1;
    int irsensed = 1;
    int turning = 0;
    int HMC6352Address = 0x42;
    int slaveAddress;
    byte headingData[2];
    int i, headingValue;
    float headingStart;
    float headingTurn;
    int done = 0;
    /////////////////////////////////////////////////////////////
    void setup() {
      Serial.begin(9600);
      Serial.print("Beginning setup.");
      digitalWrite(13, HIGH);
      Serial.print(".");
      delay(10);
      digitalWrite(13, LOW);
      Serial.println(".");
                                                       //Note: the following four lines of code are not mine.
                                                       // 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
      headingStart = getHeading() / 10;                //(My own code continues here.)This sets up a variable called headingStart that gives a real heading and saves it as its initial heading.
      rangelow = headingStart + 90;                    //this sets up the threshold for the turn later in the code (see loop).
      delay (50);                                     //Just for good measure.
      pinMode(3, OUTPUT);                              //These four
      pinMode(5, OUTPUT);                              //lines of code
      pinMode(6, OUTPUT);                              //are to set
      pinMode(9, OUTPUT);                              //the motors up.
      Serial.println("Setup completed.");
      digitalWrite(3, HIGH);                           //And these
      digitalWrite(5, LOW);                            //four are to
      digitalWrite(6, LOW);                            //get them to
      digitalWrite(9, HIGH);                           //go forward.
    }
    /////////////////////////////////////////////////////////////
    void loop() {
      irsensed = analogRead(0);                        //Gets distance of object in front of the robot.
      irdistance = irsensed;                           //Doublechecks. I added this in because the sensor sometimes would just return 0.
      if (done == 0) {                                 //fixed this. Its purpose is to make sure it doesn't keep going and going.
        if (irdistance >= 488 && irdistance <= 536) {  // if an object is about 20 cm away
          turning = 1;                                 //this tells itaself that it needs to start turning, hence the name of the variable.
          Serial.println("Beginning turning sequence...");
        }
        if (turning == 1) {                            //If it is beginning its turn
          digitalWrite(3, LOW);                        //stop both motors
          digitalWrite(5, LOW); 
          digitalWrite(6, LOW);
          digitalWrite(9, LOW);
          delay(10
          );
          headingStart = getHeading() / 10;            //
          digitalWrite(3, HIGH);                       //turns right
          digitalWrite(5, LOW);
          digitalWrite(6, HIGH);
          digitalWrite(9, LOW);
                                                       //From here on it is supposed to stop after it has turned right 90 degrees.
          headingTurn = getHeading() / 10;                    //I have no idea as to why it isn't working.
            if (headingTurn >= rangelow) {
              done = 1;
              digitalWrite(3, LOW);
              digitalWrite(5, LOW); 
              digitalWrite(6, LOW);
              digitalWrite(9, LOW);
              Serial.println("First turn completed.");
            }
        }
      }
    }
    /////////////////////////////////////////////////////////////From here on, it is not my code.
    int getHeading() {
      Serial.println("getting heading...");
      Wire.beginTransmission(slaveAddress);
      Wire.send("A");              // The "Get Data" command
      Wire.endTransmission();
      delay(1);                   // The HMC6352 needs at least a 70us (microsecond) delay
      // after this command.  Using 1ms 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.receive();
        i++;
      }
      Serial.println("Heading found.");
      headingValue = headingData[0]*256 + headingData[1];  // Put the MSB and LSB together
      Serial.println(headingValue);
      return headingValue;
    }
    /////////////////////////////////////////////////////////////
    

    Selenaut,

    I suggest you add “printing” of the two bytes as they are read from the compass.

    I’m curious as to why you got the “getting heading” message, but not the “Heading found” message the first time you tried to read the compass.

    Also, I have a vague recollection that one may need to convert the numbers to their ASCII representations to get them to “print”, or to use a “print” function designed for non-ASCII data.

    Eric

    Sorry, that was a copy error. It shows up like this:

    Beginning setup...
    getting heading...
    Heading found.
    0
    Setup completed.
    Beginning turning sequence...
    getting heading...
    Heading found.
    0
    getting heading...
    Heading found.
    0
    

    Good news and bad news:

    Good news: I figured out that the while block was being skipped over, and that was most likely the reason it is not working.

    Bad news: I don’t know how to fix this.

    HOORAYYYYYYYYYYYYY!!!

    So I got it working.

    The problem was indeed skipping over the while block. The reason this was happening was because I initialized the wire library after I tried to read the compass initially. facepalm

    So, here’s the code so far:

    #include <Wire.h>
    
    float rangelow;
    int irdistance = 1;
    int irsensed = 1;
    int turning = 0;
    int HMC6352Address = 0x42;
    int slaveAddress;
    byte headingData[2];
    int i, headingValue;
    float headingStart;
    float headingTurn;
    int done = 0;
    /////////////////////////////////////////////////////////////
    void setup() {
      Wire.begin();
      Serial.begin(9600);
      Serial.print("Beginning setup.");
      digitalWrite(13, HIGH);
      Serial.print(".");
      delay(10);
      digitalWrite(13, LOW);
      Serial.println(".");
                                                       //Note: the following four lines of code are not mine.
                                                       // 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
      headingStart = getHeading() / 10;                //(My own code continues here.)This sets up a variable called headingStart that gives a real heading and saves it as its initial heading.
      rangelow = headingStart + 90;                    //this sets up the threshold for the turn later in the code (see loop).
      delay (50);                                     //Just for good measure.
      pinMode(3, OUTPUT);                              //These four
      pinMode(5, OUTPUT);                              //lines of code
      pinMode(6, OUTPUT);                              //are to set
      pinMode(9, OUTPUT);                              //the motors up.
      Serial.println("Setup completed.");
      digitalWrite(3, HIGH);                           //And these
      digitalWrite(5, LOW);                            //four are to
      digitalWrite(6, LOW);                            //get them to
      digitalWrite(9, HIGH);                           //go forward.
    }
    /////////////////////////////////////////////////////////////
    void loop() {
      irsensed = analogRead(0);                        //Gets distance of object in front of the robot.
      irdistance = irsensed;                           //Doublechecks. I added this in because the sensor sometimes would just return 0.
      if (done == 0) {                                 //fixed this. Its purpose is to make sure it doesn't keep going and going.
        if (irdistance >= 488 && irdistance <= 536) {  // if an object is about 20 cm away
          turning = 1;                                 //this tells itaself that it needs to start turning, hence the name of the variable.
          Serial.println("Beginning turning sequence...");
        }
        if (turning == 1) {                            //If it is beginning its turn
          digitalWrite(3, LOW);                        //stop both motors
          digitalWrite(5, LOW); 
          digitalWrite(6, LOW);
          digitalWrite(9, LOW);
          delay(10
          );
          headingStart = getHeading() / 10;            //
          digitalWrite(3, HIGH);                       //turns right
          digitalWrite(5, LOW);
          digitalWrite(6, HIGH);
          digitalWrite(9, LOW);
                                                       //From here on it is supposed to stop after it has turned right 90 degrees.
          headingTurn = getHeading() / 10;                    //I have no idea as to why it isn't working.
            if (headingTurn >= rangelow) {
              done = 1;
              digitalWrite(3, LOW);
              digitalWrite(5, LOW); 
              digitalWrite(6, LOW);
              digitalWrite(9, LOW);
              Serial.println("First turn completed.");
            }
        }
      }
    }
    /////////////////////////////////////////////////////////////
    int getHeading() {
      Serial.print("getting heading.");
      Wire.beginTransmission(slaveAddress);
      Serial.print(".");
      Wire.send("A");              // The "Get Data" command
      Serial.print(".");
      Wire.endTransmission();
      Serial.print(".");
      delay(10);                   // The HMC6352 needs at least a 70us (microsecond) delay
      // after this command.  Using 1ms 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
      Serial.print(".");
      Wire.requestFrom(slaveAddress, 2);        // Request the 2 byte heading (MSB comes first)
      Serial.print(".");
      i = 0;
      Serial.print(".");
      delay(5);
      while (Wire.available() && i < 2)
      { 
        Serial.print(".");
        headingData[i] = Wire.receive();
        Serial.print(".");
        i++;
        Serial.println(".");
        Serial.println("Heading found.");
      }
      headingValue = headingData[0]*256 + headingData[1];  // Put the MSB and LSB together
      Serial.println(float (headingValue / 10));
      return headingValue;
    }
    /////////////////////////////////////////////////////////////
    

    Also, the ticking was indeed from the motors being turned on and off repeatedly at very low power (from the USB.)

    Selenaut,

    Thanks for letting me know we haven’t both wasted major chunks of our day!

    A few more things for you to check:

  • - It appears that you compute the endpoint for the turn (rangelow) in the setup procedure, not the loop. As I see it, you should move the calculation into the loop, in the sequence, to be executed if an object is detected:
  • - stop
  • - measure heading
  • - calculate endpoint
  • - measure heading
  • - if heading is less than endpoint, turn for, say, 10 milliseconds, and return to the previous step
  • - otherwise, stop and reset the flags
  • and delete the heading check in the setup. (You're not using that data anyway, as you overwrite it inside the loop.)
  • - At the risk of sounding horribly old school, I suggest you try flowcharting what you're trying to do as a way to tune where in the program flow you are doing what. For example, it appears that you have a motor stop inside the turning loop, rather than before the turning loop.
  • - It appears you need to put resetting "turning" within the "if" loop that runs when the end of the turn is detected.
  • - It appears you still need to address the "wraparound" of compass headings.
  • - I suggest you read through this thread, as there are probably things mentioned above that are worth doing.
  • Also, I don’t understand your second comment in:

    irsensed = analogRead(0);     //Gets distance of object in front of the robot.
    irdistance = irsensed;        //Doublechecks. I added this in because the sensor sometimes would just return 0.
    

    The second line assigns the value to a second variable, but it doesn’t read the sensor a second time, nor does it select between two values.

    Lastly, please keep posting updates.

    TIA,

    Eric

    I don’t understand why sometimes my IR sensor will just randomly stop working. It will suddenly read 0 for the incoming analog. But if I do this:

    #include <SoftwareSerial.h>
    int a0;
    int a1;
    int a2;
    int a3;
    int a4;
    int a5;
    void setup() {
      Serial.begin(9600);
    }
    void loop() {
      a0 = analogRead(0);
      a1 = analogRead(1);
      a2 = analogRead(2);
      a3 = analogRead(3);
      a4 = analogRead(4);
      a5 = analogRead(5);
      Serial.println(a0);
      Serial.println(a1);
      Serial.println(a2);
      Serial.println(a3);
      Serial.println(a4);
      Serial.println(a5);
      delay(1000);
    }
    

    It will suddenly start working again. Also, assigning it to a second variable seems to keep it from returning 0 (i have no idea why, maybe my IR sensor’s fidgety?)

    also:

    1. Working on it

    2. I’m actually writing down a chronological list of procedures, like “first, turn on, then get heading, etc.”

    3. That’s what the done variable is for. It pretty much signals the end of the process. BTW, that was actually supposed to be there, to help with turning; it causes it to move a little, then stop. (if only it weren’t so jerky…)

    4. Yes. Yes I do.

    5. True. But I have to adress the previous four things.

    And yes, I will keep posting updates until I have this code completely flawless (which is going to take a while :smiley: ).

    So good news and bad news:

    Good news is… THIS ONE WORKS!!! YAY!!!

    Bad news is… This one overshoots the 90 degree turns quite a bit, particularly the 3rd turn.

    I don’t know why this is, but when I try testing it by holding it in my hand, putting something in front of it, and then turning around so that it goes through the code, it overshoots on the 1st, 2nd, and 4th turns by about 5-10 degrees, and on the 3rd up to roughly 30 degrees. The “turning” variables are respective to which turn it is presently on.

    #include <Wire.h>
    
    float range;
    float range2;
    float range3;
    int irdistance = 1;
    int irsensed = 1;
    byte turning = 0;
    byte turning2 = 0;
    byte turning3 = 0;
    byte turning4 = 0;
    int HMC6352Address = 0x42;
    int slaveAddress;
    byte headingData[2];
    int i, headingValue;
    float headingStart;
    float headingTurn;
    byte done = 0;
    /////////////////////////////////////////////////////////////
    void setup() {
      pinMode(13, OUTPUT);
      Wire.begin();
      Serial.begin(9600);
      Serial.print("Beginning setup.");
      digitalWrite(13, HIGH);
      Serial.print(".");
      delay(10);
      digitalWrite(13, LOW);
      Serial.println(".");
                                                       //Note: the following four lines of code are not mine.
                                                       // 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
      delay (50);                                      //(my own code continues here)Just for good measure.
      pinMode(3, OUTPUT);                              //These four
      pinMode(5, OUTPUT);                              //lines of code
      pinMode(6, OUTPUT);                              //are to set
      pinMode(9, OUTPUT);                              //the motors up.
      digitalWrite(13,HIGH);
      headingStart = getHeading() / 10;            //This sets up a variable called headingStart that gives a real heading and saves it as its initial heading.
      if (headingStart >= 270) {
        headingStart = headingStart - 360;
      }
      digitalWrite(13,LOW);
      Serial.println("Setup completed.");
      digitalWrite(3, HIGH);                           //And these
      digitalWrite(5, LOW);                            //four are to
      digitalWrite(6, LOW);                            //get them to
      digitalWrite(9, HIGH);                           //go forward.
    }
    /////////////////////////////////////////////////////////////
    void loop() {
      irsensed = analogRead(0);                        //Gets distance of object in front of the robot.
      irdistance = irsensed;                           //Doublechecks. I added this in because the sensor sometimes would just return 0.
      if (done == 0) {                                 //fixed this. Its purpose is to make sure it doesn't keep going and going.
        if (irdistance >= 488 && irdistance <= 536 && turning == 0) {  // if an object is about 20 cm away and turning is not true
          digitalWrite(13,HIGH);
          turning = 1;                                //this tells itaself that it needs to start turning, hence the name of the variable.
          Serial.println("Beginning turning sequence...");
          range = headingStart + 85;                   //this sets up the threshold for the turn later in the code (see loop).
          digitalWrite(13,LOW);
        } 
        if (turning == 1) {                            //If it is beginning its turn
          digitalWrite(3, LOW);                        //stop both motors
          digitalWrite(5, LOW); 
          digitalWrite(6, LOW);
          digitalWrite(9, LOW);
          delay(10);
          digitalWrite(3, HIGH);                       //turns right
          digitalWrite(5, LOW);
          digitalWrite(6, HIGH);
          digitalWrite(9, LOW);
          headingTurn = getHeading() / 10;
          if (headingTurn >= range) {
            digitalWrite(13,HIGH);
            turning++;
            turning2 = 1;
            digitalWrite(3, LOW);
            digitalWrite(5, HIGH); 
            digitalWrite(6, LOW);
            digitalWrite(9, HIGH);
            digitalWrite(3, LOW);
            digitalWrite(5, LOW); 
            digitalWrite(6, LOW);
            digitalWrite(9, LOW);
            Serial.println("First turn completed.");
            digitalWrite(13,LOW);
            digitalWrite(3, HIGH);                       
            digitalWrite(5, LOW);                     
            digitalWrite(6, LOW);                         
            digitalWrite(9, HIGH);
            delay(1500);
            digitalWrite(3, LOW);                   
            digitalWrite(5, LOW); 
            digitalWrite(6, LOW);
            digitalWrite(9, LOW);
            digitalWrite(13,HIGH);
          }
        }
        if (turning2 == 1) {
          delay(10);
          digitalWrite(3, LOW);         
          digitalWrite(5, HIGH);
          digitalWrite(6, LOW);
          digitalWrite(9, HIGH);
          headingTurn = getHeading() / 10;
          if (headingTurn <= headingStart || headingTurn - 360 >= headingStart) {
            turning3 = 1;
            turning2 = 0;
            digitalWrite(3, HIGH);
            digitalWrite(5, LOW); 
            digitalWrite(6, HIGH);
            digitalWrite(9, LOW);
            digitalWrite(3, LOW);
            digitalWrite(5, LOW); 
            digitalWrite(6, LOW);
            digitalWrite(9, LOW);
            digitalWrite(13,LOW);
            digitalWrite(3, HIGH);                       
            digitalWrite(5, LOW);                     
            digitalWrite(6, LOW);                         
            digitalWrite(9, HIGH);
            delay(1500);
            digitalWrite(3, LOW);              
            digitalWrite(5, LOW); 
            digitalWrite(6, LOW);
            digitalWrite(9, LOW);
            digitalWrite(13,HIGH);
          }
        }
        if (turning3 == 1) {
          delay(10);
          digitalWrite(3, LOW);                      
          digitalWrite(5, HIGH);
          digitalWrite(6, LOW);
          digitalWrite(9, HIGH);
          headingTurn = getHeading() / 10;
          if (headingTurn <= range - 180 || headingTurn >= range + 180) {
            turning4 = 1;
            turning3 = 0;
            digitalWrite(3, HIGH);
            digitalWrite(5, LOW); 
            digitalWrite(6, HIGH);
            digitalWrite(9, LOW);
            digitalWrite(3, LOW);
            digitalWrite(5, LOW); 
            digitalWrite(6, LOW);
            digitalWrite(9, LOW);
            digitalWrite(13,LOW);
            digitalWrite(3, HIGH);                       
            digitalWrite(5, LOW);                     
            digitalWrite(6, LOW);                         
            digitalWrite(9, HIGH);
            delay(1500);
            digitalWrite(3, LOW);                   
            digitalWrite(5, LOW); 
            digitalWrite(6, LOW);
            digitalWrite(9, LOW);
            digitalWrite(13,HIGH);
          }
        }
        if (turning4 == 1) {
          delay(10);
          digitalWrite(3, HIGH);                      
          digitalWrite(5, LOW);
          digitalWrite(6, HIGH);
          digitalWrite(9, LOW);
          headingTurn = getHeading() / 10;
          if (headingTurn >= headingStart || headingTurn - 360 >= headingStart) {
            done = 1;
            turning4 = 0;
            digitalWrite(3, LOW);
            digitalWrite(5, HIGH); 
            digitalWrite(6, LOW);
            digitalWrite(9, HIGH);
            digitalWrite(3, LOW);
            digitalWrite(5, LOW); 
            digitalWrite(6, LOW);
            digitalWrite(9, LOW);
            digitalWrite(13,LOW);
            digitalWrite(3, HIGH);                       
            digitalWrite(5, LOW);                     
            digitalWrite(6, LOW);                         
            digitalWrite(9, HIGH);
            delay(1500);
            digitalWrite(3, LOW);                        //stop both motors
            digitalWrite(5, LOW); 
            digitalWrite(6, LOW);
            digitalWrite(9, LOW);
            digitalWrite(13,HIGH);
            delay(1000);
            digitalWrite(13,LOW);
          }
        }
      }
    }
    /////////////////////////////////////////////////////////////
    int getHeading() {
      Serial.print("getting heading.");
      Wire.beginTransmission(slaveAddress);
      Serial.print(".");
      Wire.send("A");              // The "Get Data" command
      Serial.print(".");
      Wire.endTransmission();
      Serial.print(".");
      delay(10);                   // The HMC6352 needs at least a 70us (microsecond) delay
      // after this command.  Using 1ms 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
      Serial.print(".");
      Wire.requestFrom(slaveAddress, 2);        // Request the 2 byte heading (MSB comes first)
      Serial.print(".");
      i = 0;
      Serial.print(".");
      delay(5);
      while (Wire.available() && i < 2)
      { 
        Serial.print(".");
        headingData[i] = Wire.receive();
        Serial.print(".");
        i++;
        Serial.println(".");
        Serial.println("Heading found.");
      }
      headingValue = headingData[0]*256 + headingData[1];  // Put the MSB and LSB together
      Serial.println(float (headingValue / 10));
      return headingValue;
    }
    /////////////////////////////////////////////////////////////
    

    Any ideas?

    Selenaut,

    Several, but I’ll start with a firm suggestion that you define a few drive functions so my brain doesn’t hurt so much and I can follow what you’re doing. For example:

    void botForward () {
          digitalWrite(3, HIGH);                           //And these
          digitalWrite(5, LOW);                            //four are to
          digitalWrite(6, LOW);                            //get them to
          digitalWrite(9, HIGH);                           //go forward.
          }
    void botStop () {
          digitalWrite(3, LOW);                        //stop both motors
          digitalWrite(5, LOW);
          digitalWrite(6, LOW);
          digitalWrite(9, LOW);
          }
    void botRight () {
          digitalWrite(3, HIGH);                       //turns right
          digitalWrite(5, LOW);
          digitalWrite(6, HIGH);
          digitalWrite(9, LOW);
          }
    

    Then, replace each of the blocks of digitalWrite commands with a call to the appropriate drive function. That will make the code much shorter and much easier to read. (When you get around to learning about PWM speed control, you can change each drive function to take a speed argument.)

    I also suggest you move the division by 10 inside the heading function. That will shorten the code a bit and reduce the risk that you’ll forget to do the division. Note that moving the division inside will change the data type of what the function returns. You can avoid that by rounding or truncating the quotient inside the heading function. (It seems unlikely that tenths of a degree are relevant at this point.)

    It’s not clear to me what you were trying to do with the multiple turns and how they are supposed to differ from each other. If you’ve prepared a flow chart or some other description of what you’re trying to do, please share it.

    Also, you do not appear to have addressed compass wraparound for all of your turns.

    Good Luck,

    Eric

    To address the forward, stop, left, and right blocks, yes, I will surely do that.

    As for the whole point of multiple turns, it is supposed to travel al of the way around the object and continue on in its original driving line, by taking a right turn, two left turns, and then another right turn. (In the beginning, the point was to use the compass readouts and trig to make the process much shorter, along with allowing for multiple obstacles and such, but that’s another project entirely :wink: .)

    For the “dividing by 10” problem, I’ll make a general “Heading” float variable to handle this, and put it inside the compass heading function.

    The wraparound is a bit dicey, but this gets the job done for all of the turns - somewhat. Like I said, it REALLY overshoots the 3rd turn. I need some help on that - it seems to me like I either got confused in my own reasoning or I just screwed up a number somewhere.

    Selenaut:
    To address the forward, stop, left, and right blocks, yes, I will surely do that.

    If you do that and post the revised code, I’ll makde another attempt to understand it.

    Selenaut:
    As for the whole point of multiple turns, it is supposed to travel al of the way around the object and continue on in its original driving line, by taking a right turn, two left turns, and then another right turn. (In the beginning, the point was to use the compass readouts and trig to make the process much shorter, along with allowing for multiple obstacles and such, but that’s another project entirely :wink: .)

    Well, at least I’ve left “botLeft” as an exercise for the reader. :wink:

    I still don’t understand your “turning1”, “turning2”, etc. variables. As I understand things, you’re always going to execute the 4 turns. If that’s the case, why have them executed conditionally?

    Selenaut:
    The wraparound is a bit dicey, but this gets the job done for all of the turns - somewhat.

    Check out the “modulo” function. That will allow you to compute, based on the initial heading, the two intermediate headings you need. (It appears that the heading between the second and third turns and the heading after the fourth turn should all be the same as the initial heading.){/color]

    Selenaut:
    Like I said, it REALLY overshoots the 3rd turn. I need some help on that - it seems to me like I either got confused in my own reasoning or I just screwed up a number somewhere

    If you still have that problem after making the code changes you’ve said you’ll make, I’ll try to help you find the bug. (Making the changes should reduce the risk of errors in “duplicating” parts of your code internally.

    Good Luck,

    Eric

    Here’s the condensed code - and it is a LOT easier to read now (as well as a good deal shorter). There are only a few more steps to address all of the problems listed thus far.

    #include <Wire.h>
    
    float range;
    float range2;
    float range3;
    int irdistance = 1;
    int irsensed = 1;
    byte turning = 0;
    byte turning2 = 0;
    byte turning3 = 0;
    byte turning4 = 0;
    int HMC6352Address = 0x42;
    int slaveAddress;
    byte headingData[2];
    int i, headingValue;
    float headingStart;
    float headingTurn;
    byte done = 0;
    /////////////////////////////////////////////////////////////
    void setup() {
      pinMode(13, OUTPUT);
      Wire.begin();
      Serial.begin(9600);
      Serial.print("Beginning setup.");
      digitalWrite(13, HIGH);
      Serial.print(".");
      delay(10);
      digitalWrite(13, LOW);
      Serial.println(".");
                                                       //Note: the following four lines of code are not mine.
                                                       // 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
      delay (50);                                      //(my own code continues here)Just for good measure.
      pinMode(3, OUTPUT);                              //These four
      pinMode(5, OUTPUT);                              //lines of code
      pinMode(6, OUTPUT);                              //are to set
      pinMode(9, OUTPUT);                              //the motors up.
      digitalWrite(13,HIGH);
      headingStart = getHeading() / 10;            //This sets up a variable called headingStart that gives a real heading and saves it as its initial heading.
      if (headingStart >= 270) {
        headingStart = headingStart - 360;
      }
      digitalWrite(13,LOW);
      Serial.println("Setup completed.");
      goForward();
    }
    /////////////////////////////////////////////////////////////
    void loop() {
      irsensed = analogRead(0);                        //Gets distance of object in front of the robot.
      irdistance = irsensed;                           //Doublechecks. I added this in because the sensor sometimes would just return 0.
      if (done == 0) {                                 //fixed this. Its purpose is to make sure it doesn't keep going and going.
        if (irdistance >= 488 && irdistance <= 536 && turning == 0) {  // if an object is about 20 cm away and turning is not true
          digitalWrite(13,HIGH);
          turning = 1;                                //this tells itaself that it needs to start turning, hence the name of the variable.
          Serial.println("Beginning turning sequence...");
          range = headingStart + 85;                   //this sets up the threshold for the turn later in the code (see loop).
          digitalWrite(13,LOW);
        }
        if (turning == 1) {                            //If it is beginning its turn
          Stop();
          delay(10);
          goRight();
          headingTurn = getHeading() / 10;
          if (headingTurn >= range) {
            digitalWrite(13,HIGH);
            turning++;
            turning2 = 1;
            goLeft();
            Stop();
            Serial.println("First turn completed.");
            digitalWrite(13,LOW);
            goForward();
            delay(1500);
            Stop();
            digitalWrite(13,HIGH);
          }
        }
        if (turning2 == 1) {
          Stop();
          delay(10);
          goLeft();
          headingTurn = getHeading() / 10;
          if (headingTurn <= headingStart || headingTurn - 360 >= headingStart) {
            turning3 = 1;
            turning2 = 0;
            goRight();
            Stop();
            digitalWrite(13,LOW);
            goForward();
            delay(1500);
            Stop();
            digitalWrite(13,HIGH);
          }
        }
        if (turning3 == 1) {
          Stop();
          delay(10);
          goLeft();
          headingTurn = getHeading() / 10;
          if (headingTurn <= range - 180 || headingTurn >= range + 180) {
            turning4 = 1;
            turning3 = 0;
            goRight();
            Stop();
            digitalWrite(13,LOW);
            goForward();
            delay(1500);
            Stop();
            digitalWrite(13,HIGH);
          }
        }
        if (turning4 == 1) {
          Stop();
          delay(10);
          goRight();
          headingTurn = getHeading() / 10;
          if (headingTurn >= headingStart || headingTurn - 360 >= headingStart) {
            done = 1;
            turning4 = 0;
            goLeft();
            Stop();
            digitalWrite(13,LOW);
            goForward();
            delay(1500);
            Stop();
            digitalWrite(13,HIGH);
            delay(1000);
            digitalWrite(13,LOW);
          }
        }
      }
    }
    /////////////////////////////////////////////////////////////
    int getHeading() {
      Serial.print("getting heading.");
      Wire.beginTransmission(slaveAddress);
      Serial.print(".");
      Wire.send("A");              // The "Get Data" command
      Serial.print(".");
      Wire.endTransmission();
      Serial.print(".");
      delay(10);                   // The HMC6352 needs at least a 70us (microsecond) delay
      // after this command.  Using 1ms 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
      Serial.print(".");
      Wire.requestFrom(slaveAddress, 2);        // Request the 2 byte heading (MSB comes first)
      Serial.print(".");
      i = 0;
      Serial.print(".");
      delay(5);
      while (Wire.available() && i < 2)
      { 
        Serial.print(".");
        headingData[i] = Wire.receive();
        Serial.print(".");
        i++;
        Serial.println(".");
        Serial.println("Heading found.");
      }
      headingValue = headingData[0]*256 + headingData[1];  // Put the MSB and LSB together
      Serial.println(float (headingValue / 10));
      return headingValue;
    }
    /////////////////////////////////////////////////////////////
    void goForward() {
      digitalWrite(3, HIGH);                       
      digitalWrite(5, LOW);                     
      digitalWrite(6, LOW);
      digitalWrite(9, HIGH);
    }
    void goRight() {
      digitalWrite(3, HIGH);
      digitalWrite(5, LOW);
      digitalWrite(6, HIGH);
      digitalWrite(9, LOW);
    }
    void Stop() {
      digitalWrite(3, LOW);
      digitalWrite(5, LOW);
      digitalWrite(6, LOW);
      digitalWrite(9, LOW);
    }
    void goLeft() {
      digitalWrite(3, LOW);
      digitalWrite(5, HIGH);
      digitalWrite(6, LOW);
      digitalWrite(9, HIGH);
    }
    

    Oh, and the reason I’m keeping the turns separate is so that it can loop through each one separately; the reason for this is to allow for more than one heading reading for each turn (the only way I can think of this working other than the one I have is to use goto - which I don’t like).

    BTW, if you get confused as to why the bot goes left, then goes right for a fery short amount of time, and then stops, it is so that the wheels don’t “drift” while stopping.