reallynotburner / MyRoomba

Expedient and incomplete way to connect your Arduino to a Roomba
0 stars 0 forks source link

Getting wild 65000 + number for abs(2900 - RoombaState.cliffAnalogFrontRight) #4

Open reallynotburner opened 5 years ago

reallynotburner commented 5 years ago

Submitted by https://github.com/xXCrozSpartaXx on the HelloRoomba repository. I deleted that repo and moved this issue to the the MyRoomba repo.

Why are we getting readings in the 65000 range when running this code?

#include "MyRoomba.h"

void setup() {
  Serial1.begin(115200); // we need this separate port to talk to the Roomba
  Serial.begin(115200);
  // this command puts the roomba into hacking mode and will follow Asimov's Third Law
  startSafe();
}

void drive(short distance, short turbo) { //Turbo is short for velocity
  ledState.powerColor = red; // let's make the big button color Orange
  updateLeds(); // update to make it real
  driveStandard(turbo, 0);

  long int previousdistance = RoombaState.distance; //record how far the roomba has gonez
  while ((RoombaState.distance - previousdistance) < distance) {
    updateRoombaState();
    if (abs(2900 - RoombaState.cliffAnalogLeft) > 200) { //check if surface is not wood
      driveStandard(0, 0);
    }
    if (abs(2900 - RoombaState.cliffAnalogFrontLeft) > 200) {
      driveStandard(0, 0);
    }
    if (abs(2900 - RoombaState.cliffAnalogFrontRight) > 200) {
      driveStandard(0, 0);
    }
    if (abs(2900 - RoombaState.cliffAnalogRight) > 200) {
      driveStandard(0, 0);
    }
    Serial.print("Analog Cliff Left: ");
    Serial.print(RoombaState.cliffAnalogLeft);
    Serial.print(" Front Left: ");
    Serial.print(RoombaState.cliffAnalogFrontLeft);
    Serial.print(" Front Right: ");
    Serial.print(RoombaState.cliffAnalogFrontRight);
    Serial.print(" Right: ");
    Serial.println(RoombaState.cliffAnalogRight);
    Serial.println(abs(2900 - RoombaState.cliffAnalogLeft));

  }

  driveStandard(0, 0);
  //RoombaState.distance = 0;
  ledState.powerColor = green; // let's make the big button color Orange
  updateLeds(); // update to make it real
}

void twirl(short rotation, short velocity) { //to make the robot turn right input a negative velocity, rotation is always possitive.
  ledState.powerColor = orange;
  updateLeds();
  driveDirect(velocity, -velocity); //double check if negative is ok in front of variable
  long int previousangle = RoombaState.angle; //record how far the roomba has gone
  while (abs((RoombaState.angle - previousangle)) < rotation) {
    updateRoombaState();
    Serial.print("RoombaState.angle ");
    Serial.print(RoombaState.angle);
    Serial.print(" previous angle ");
    Serial.println(previousangle);
  }
  Serial.print(velocity);
  driveStandard(0, 0);
  ledState.powerColor = green; // let's make the big button color Orange
  updateLeds(); // update to make it real
}

void exitRoomba() { // it's over
  stop(); // call stop, returning Roomba back to normal consumer operation, startSafe() will go back into hack mode
  while (true) {} // INFINITE LOOP!
}

// the loop routine runs over and over again forever:
void loop() {
  updateLeds();
  updateRoombaState(); // you MUST call this in your program loops to know what the Roomba is doing
  if (RoombaState.dockButton) {
    exitRoomba();
  } else if (RoombaState.cleanButton) {
    int loopcounter = 0;
    while (loopcounter < 2) {
      drive(500, 150);
      twirl(90, 100);
      drive(150, 150);
      twirl(90, 100);
      drive(500, 150);
      twirl(90, -100);
      drive(150, 150);
      twirl(90, -100);
      loopcounter = loopcounter + 1;
    }
    findlocation();
  }
}
reallynotburner commented 5 years ago

Unsigned Integer Issue

If you try to subtract an UNSIGNED number from something else, and the result is supposed to be a negative number, you will have unexpected results. For example, your issue can be reproduced in your Arduino IDE with this simple code:

word cliffAnalogLeft = 2901;

void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.println(abs(2900 - cliffAnalogLeft));  // prints 65535, what the heck?
  delay(200);
}

When you read the Roomba Open Interface Specification, you'll find out that the cliffAnalog sensors can read anything from 0 to 4096. Humans can see that subtracting 1 from 0 should be -1. However, knowing that requires quite a few assumptions that computers can't take for granted. Unlike a human mathematician, you have to tell an Arduino how much memory to take when storing a number for you. You also need to tell it what to do if it gets negative. It won't assume that for you.

The language your code uses is called C++. It lets you define numbers that can take up 8 bits, 16 bits and 32 bits, and so on. When you define a number as byte, it will use 8 bits of memory and it can be 0 all the way up to 255. That's not big enough to fit the biggest cliffAnalog reading of 4096. So, I defined the number in my code with word. If you call define a number as word, it will use 16 bits of memory, and can be from 0 to 65535. Plenty big, but it cannot do -1. That turns it into 65535. If I try -2, now it's 65534, and so on. So the hardware doesn't explode, but we get our data wrong and have to figure out a solution.

There's a very easy way to do this. C++ has a syntax for converting one type of a number into another type. This process is called "casting". I want to "cast" the unsigned 16 bit value of the cliffAnalog sensor into something with a signed value. Something like short. So here's the code again:

word cliffAnalogLeft = 2901;

void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.println(abs(2900 - (short) cliffAnalogLeft));  // prints 1, now that makes sense to me!
  delay(200);
}

That will get you past your current issue, your numbers will start to make sense. Just do yourself a favor, don't hard - code your value for "wood" as 2900. You should read the cliff sensors when the program starts up and have that be your base value. Then your code would catch when the cliff sensors have deviated from the original value by a certain amount.