Environment mapping

I'm currently working on an application for mapping the environment with a range sensor. Right now it's only a sharp sensor (GP2D12) mounted on a servo that is turning slowly, while the readings and corresponding servo angles are being sent constantly to my PC via serial. The program then converts the angle and distance to x/y coordinates and draws a map.

Later it's is my plan to use this on my robot in combination with a homemade digital compass (hall effect sensors) and quadrature enocoders on the wheels to measure the approximated distance the robot is traveling. All these factors will be integrated into a so called SLAM application (simultaneous localization and mapping).

I'll be posting more info and source code etc later. Just thought I'd share the 1st screen shot of the application. I'll try to make a video later. It's pretty cool to see the red "laser beam" sweep the surrounding for objects. :slight_smile:

I've seen this idea a couple of times now. If you can pull it off with the AVR it'll be very impressive.

Don't forget to share you're code :wink:

That's great - personal sonar or radar! In the screenshot do the echos correspond to real objects? How far away are they?

This is on my list of fun things to do :smiley:

It's one of my LONG term projects and I know it wont be easy. In particular with the lowtech setup I'll start out with: A home made digital compass like this and 2 homemade quadrature encoders a la this.

I'll probably end up with a fancy digital compass and GPS and the lot some day but right now my budget wont allow it, and besides I wanna atleast try out the cheap lowtech solutions before I move on.

In the screenshot do the echos correspond to real objects? How far away are they?

Yes they correspond to real objects. It tends to give weird reading around the edges of objects though. I'm currently using a GP2D12 sharp sensor as mentioned, which only has a range of 10 - 80 cm, and the objects on the map are within that range.

Actually I got readings from well over a meter, but the further you get the less reliable the readings are. However they are very precise at short range. I believe more precise than sonars. Sonars rule at longer ranges though.

PS: And off course I'll be sharing code (and details) along the way. But I generally don't like posting my code before I had a chance to clean it up a bit. It's sorta like having people snooping around in your dirty underwear :slight_smile: Hehe

I believe more precise than sonars

The problem with sonar is the target's surface. Soft surfaces (e.g. clothing) give terrible reflections and poor results. Very soft surfaces can absorb the sound and give no reflection. Hard flat vertical surfaces (e.g. maze walls) give clean reflections and good results.

I am working on a similar project but it's for my robot. Right now I've got the scan and display the map on a Nokia LCD using a Ping ultrasonic sensor. Why Ping? Because it has the fastest response. I got it scan left to right and right to left and display the objects on the display. It's so fast, I wish this could be done with Sharp sensors for greater accuracy. But the Sharp sensors take several measurements and average them internally and output the result over a 39ms period. And that is not good enough, we also need to average a few scans to get the proper distance. This slows down the scanning greatly. My next step is to use 2 long distance Sharp sensors mounted at 45 degrees on each side of the Ping sensor and scan only 90 degrees taking measurements with both sensors at once. I will also scan with the Ping sensor and display the results on the same map using different colors. Perhaps I'll use the Ping when I need to fast scan and the Sharps for a greater accuracy scan.

Edit: forgot to add that my robot has encoders and an I2C compass that I intend to use for map following after I get the scanning stuff completed.

Here is a video:

Here is the code I have so far:

/*
  Scan and display map on Nokia LCD (Epson).
  Ping sensor on a pan servo.
  Created by Gabriel Petrut, Oct 27th, 2009.
  Released into the public domain.
*/

#include <NokiaLCD.h>
#include <SoftwareServo.h>

#define PanPin 16        
#define PingPin 15       

// Nokia LCD Setup settings
// Basic Colors
#define WHITE 0xFFF
#define BLACK 0x000
#define RED 0xF00
#define GREEN 0x0F0
#define BLUE 0x00F
#define CYAN 0x0FF
#define MAGENTA 0xF0F
#define YELLOW 0xFF0
#define BROWN 0xB22
#define ORANGE 0xFA0
#define PINK 0xF6A

// Nokia LCD pins:
#define CSE 4
#define RST 5
#define SDA 11
#define SCK 13

#define MapXcenter  65
#define MapYcenter  35

SoftwareServo Pan; 
NokiaLCD nokiaLcd;

byte PingDistance = 0;
byte USValue[181];
byte x=0;
byte y=0;
byte a=0;
char text [50];
char byteString[4];

void setup() 
{ 
  pinMode(CSE, OUTPUT);
  digitalWrite(CSE, HIGH);
  pinMode(SCK, OUTPUT);
  digitalWrite(SCK, HIGH);
  pinMode(SDA, OUTPUT);
  digitalWrite(SDA, HIGH);
  pinMode(RST, OUTPUT);
  digitalWrite(RST, HIGH);

  pinMode(PingPin, OUTPUT); 
  digitalWrite(PingPin, LOW);

  Pan.attach(PanPin);
  Pan.write(80);
  SoftwareServo::refresh();

  nokiaLcd.lcd_init();
  delay(500);
} 
 
void loop() 
{
  ScanMap();
}

void ScanMap()
{
  nokiaLcd.lcd_clear(BLUE, 0, 0, 131, 131);
    strcpy(text,"o");
    nokiaLcd.lcd_draw_text(PINK, BLACK, (131-MapXcenter-3), (131-MapYcenter), text);
  for (a=0; a<181; ++a)
  {
    ScanAndDisplay();
  }
  delay(1000);
  nokiaLcd.lcd_clear(BLUE, 0, 0, 131, 131);
    strcpy(text,"o");
    nokiaLcd.lcd_draw_text(PINK, BLACK, (131-MapXcenter-3), (131-MapYcenter), text);
  for (a=180; a>0; --a)
  {
    ScanAndDisplay();
  }
  delay(1000);
}

void ScanAndDisplay()
{
    Pan.write(a);
    SoftwareServo::refresh();
    USValue[a] = Read_Ping_Sensor();
    if (USValue[a]<200)
    { 
        byte pos=57;
        if (USValue[a]<100)
        {
          strcpy(text,"   ");
          nokiaLcd.lcd_draw_text(CYAN, BLACK, pos, 115, text);
          pos=63;
        }
        itoa(USValue[a], byteString, 10);
        strcpy(text, byteString);
        nokiaLcd.lcd_draw_text(CYAN, BLACK, pos, 115, text);
      // multiply the angle° of the servo by 0.01745 etc to convert to radians - a is the angle of the servo ( 90° is to twist result sideways for display)
      x=131-(MapXcenter+USValue[a]*(sin((a-90)*0.0174532925)));
      y=131-(MapYcenter+USValue[a]*(cos((a-90)*0.0174532925)));
      nokiaLcd.LCD_put_pixel(CYAN, x, y);
    }
}  

// Read Sensors
int Read_Ping_Sensor() {
  //trigger the sensor
  int Ping = 0;
  pinMode(PingPin, OUTPUT);
  digitalWrite(PingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(PingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(PingPin, LOW);
  //receive the echo
  pinMode(PingPin, INPUT);
  digitalWrite(PingPin, HIGH); // turn on pull up resistor
  Ping = pulseIn(PingPin, HIGH);
  return Ping/29/2;
}

Ro-Bot-X - that's pretty slick!

I am working on a similar project but it's for my robot

Well like I said mine is for a robot too. Only I plan to get a bluetooth connection and let my PC be the actual brains, thus the Arduino will only be sending data to and receiving commands from my PC.

And I noticed how fast you scanner is. Like you said the sharp sensor in much slower. I believe 36ms is the min period you can receive readings from it though (not 39ms). Still that is slow. I'm currently moving in steps of 2 degrees and taking 5 readings at each degree to calculate the average. So it takes 90365 = 16200ms = 16.2 secs (!!) to scan 180 degrees, which isn't very satisfying :frowning:

Besides your readings also look cleaner than mine. I get some really weird readings near the edges of the objects. Perhaps there is something wrong with my sensor. According to this guy the sharp sensor should give more precise readings than sonars. So something is definately wrong?!

Anyway very cool project. I believe I saw the robot before on the LMR site. Is that correct?

And may I ask what kind of encoders you're using?

Regards

Aniss

The problem with sonar is the target's surface

Well it isn't JUST soft surfaces that are problematic. There are several problems with sonars that mess up the readings.

Again I'll link to this thread where a guy has tested various sensors. Generally his conclusion is that the GP2Y0A02YK0F Sharp sensor is by far the most precise, allthough sharp sensors have their limitations too.

I guess the clever thing to do would be using both and let each one compensate for the other's short comings and "blind angles" :-?

Well, I read your thread some time ago and I didn't remember exactly all the details...

Over this weekend I'll do some more work on the robot. I'll finish up the connecting cable from the head to the Roboduino board and I'll test up the Sharp sensors. I'll let you know how that will end up. On the SoR forum, the Admin has his ERP do a 3D scanusing one Sharp sensor. He scans about 90 degrees in front of the robot stepping 5 degrees at a time. Also the tilt servo moves up 5 degrees after each scan. This way the robot is able to detect clifs or objects in front of him. The 3D scan will not work properly with the ultrasonic sensor because the sound will be bounced away from the sensor. However, if there is an object present, it will be detected.

About the encoders. I bought a pair of Faulhaber motors from Electronic Goldmine. These motors have internal quadrature encoders with Hall sensors. They will give a low to high transition per channel per motor rotation, that will end up being 141 clicks per output shaft rotation. I am using one hardware change interrupt per motor (channel A of each encoder) and try to determine the direction by reading the second channel, but for some reason it does not work properly. It may need a Schmidt trigger or a special encoder counter IC. I will just assume direction and use a pin change interrupt for the second channel so I get 4 times 141 clicks per rotation. If you have any idea how to make it work, please let me know.

My robot gets more and more complex and I feel the need to separate the tasks as some of them interfere with others. So I decided to modularize the robot's brain. So far I have the Roboduino and the Motor controller board talking I2C. I need another board and some shields... Instead of going that route, I decided to design a universal module board, some sort of mixture between the Roboduino, and a proto shield. My board is going to have all the Arduino pins on one side with power buses (3 pin headers), the ISP and FTDI pins at the top, the power connectors at the bottom and a special I3C connector on the other side. Also, at the bottom there will be a small prototyping area for customisation. This will allow me to add various parts to each board, like an H-Bridge on the motor controller board, a switching regulator on the servo controller board so the servos will run on 6V (the battery is 9.6V because of the motors), a serial EEPROM (or better a SDcard interface) on the brain board (for map storage purpose), a small amp for the speech board and of course the voltage level shifter for the Nokia LCD somewhere in there. Then I can easily stack the boards and let them talk I2C. Ohh, lots of work, can't wait for the 5 boards to arrive... solder... program the modules... then just say: Robot, fetch me a beer! (Sweet dreams...) ::slight_smile:

You got my attention, Subscribed!

I'm currently moving in steps of 2 degrees and taking 5 readings at each degree to calculate the average. So it takes 90365 = 16200ms = 16.2 secs (!!) to scan 180 degrees, which isn't very satisfying

Aniss: what if you only did one reading at each division but averaged them over 5 passes?

what if you only did one reading at each division but averaged them over 5 passes?

Do you mean calculating the average from readings taken at 5 different angles? Sounds kinda messy...but hey I might as well try it and see what heppens :wink:

Ro-Bot-X:

Sorry I can't be of much help with your encoder. The only encoder I ever used was this homemade one.

Anyway your project is awesome and I'll be following it with great curiosity in the future...

:slight_smile:

Do you mean calculating the average from readings taken at 5 different angles? Sounds kinda messy...but hey I might as well try it and see what heppens

no, no, more like scan a 90 degree sector taking (and plotting) one reading from each of the 45 2 degree angles. Then do it again averaging the new reading with the old one.

I'm thinking of something like the old-timey wartime radar that took a noticeable time to do a sweep.

I dunno. By the time I'll be scanning the same point the 2nd time the robot will have moved quite a bit so I'm not sure it's that easy. However you did give me a couple of new ideas there, so thanks anyway..

Though..I think I'll end up skipping the IR sensor entirely and going for a sonar. Even if the IR sensor is more accurate SPEED will be a major issue once the robot starts moving..