Inspiration

Inspiration for this project came from a project we worked on in ESE 650 (Learning in Robotics), where we built a SLAM algorithm to map obstacles from sensor data gathered by a robot walking around in the Towne building. We wanted to build a basic hardware component to accompany this using the Arduino kit, a ping sensor, and a step motor.

What it does

Our obstacle mapper rotates around a 180 degree field of view in 30 degree increments, and at each point takes a measurement reading of the distance to the nearest obstacle. These measurements are streamed using a NodeMCU chip to the Blynk app and plotted in real time.

How we built it

Our setup consists of a stepper motor with a ping sensor attached to it. We used a small breadboard and some double sided tape to secure the ping sensor. The stepper motor is attached to a motor controller and the Arduino Uno, while the ping sensor is connected to the NodeMCU and sends data via WiFi to the Blynk app.

Our final bill of materials includes:

  1. Arduino Uno
  2. NodeMCU
  3. 2x breadboard
  4. 28BYJ-48 Stepper Motor
  5. Ping sensor
  6. Motor controller
  7. Jumper Wires

Challenges we ran into

  1. Mounting the ping sensor onto the stepper motor. Since we did not have an axle hub, we had to be innovative with double sided tape and a small breadboard. We wrapped the double sided tape around the axle many times to make the axle thicker. Then we stuck a small breadboard on top of the axle, which was now a large flat surface.
  2. Moving the stepper motor. We wanted to move the stepper motor in small angular increments in order to record obstacles in all directions. We ultimately decided to limit our field of view to 180 degrees with 30 degree increments. To achieve the 30 degree increments, we had to look up the stepper motor specifications online. We found that our specific motor had 2048 steps per revolution. From there we calculated the number of steps per 30 degree increment.
  3. We also attempted to create a plot so we tried streaming the data to a database. We tried to use Firebase to stream data and generate a real-time obstacle map but were not able to get this to work. We also tried sending the data as a JSON to a Flask server that was hosted on Heroku. However, we did not have enough time to complete this.

Accomplishments that we're proud of

Getting the stepper motor to rotate in clean increments and coming up with a creative way to mount the ping sensor onto the stepper motor which has a round axle.

What We Learned

We learned how to use the motor controller and the Arduino stepper library. We also learned how to set up a web server and make GET and POST requests.

What's next for Arduino Obstacle Mapping

The first extension of this project would be to stream data and generate a real-time obstacle plot based on multiple sensor readings. We want to visualize the streamed data using Matplotlib and Python.

Code Snippets

#include <math.h>

#define STEPPER_PIN_1 8
#define STEPPER_PIN_2 9
#define STEPPER_PIN_3 10
#define STEPPER_PIN_4 11
#define trigPin 14
#define echoPin 12

int step_number = 0;
const int stepsPerRevolution = 2048;
const double degrees = 30;
int counter = 0;
int steps = (int) ((degrees/360) * stepsPerRevolution);

double initial_degrees = 180;
int initial_steps = (int) ((initial_degrees/360) * stepsPerRevolution);

const double total_degrees = 180;
int iterations = int(total_degrees / degrees);
int dir = 0;

struct coordinates {
  double x;
  double y;
};


void setup() {
  while(! Serial);

  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);

  pinMode(STEPPER_PIN_1, OUTPUT);
  pinMode(STEPPER_PIN_2, OUTPUT);
  pinMode(STEPPER_PIN_3, OUTPUT);
  pinMode(STEPPER_PIN_4, OUTPUT);

  Serial.begin(9600);

  for (int i=0; i<initial_steps; i++) {
    OneStep(0);
    delay(5);
  }
}

void loop() {
  dir = (dir-1)*(dir-1); 
  for (int t=0; t<iterations; t++) {
    readDist(t);

    for (int i=0; i<steps; i++) {
      OneStep(dir);
      delay(5);
    }

    delay(2000);
  }
}

void OneStep(bool dir) {
    if(dir) {
      switch(step_number) {
        case 0:
          digitalWrite(STEPPER_PIN_1, HIGH);
          digitalWrite(STEPPER_PIN_2, LOW);
          digitalWrite(STEPPER_PIN_3, LOW);
          digitalWrite(STEPPER_PIN_4, LOW);
          break;
        case 1:
          digitalWrite(STEPPER_PIN_1, LOW);
          digitalWrite(STEPPER_PIN_2, HIGH);
          digitalWrite(STEPPER_PIN_3, LOW);
          digitalWrite(STEPPER_PIN_4, LOW);
          break;
        case 2:
          digitalWrite(STEPPER_PIN_1, LOW);
          digitalWrite(STEPPER_PIN_2, LOW);
          digitalWrite(STEPPER_PIN_3, HIGH);
          digitalWrite(STEPPER_PIN_4, LOW);
          break;
        case 3:
          digitalWrite(STEPPER_PIN_1, LOW);
          digitalWrite(STEPPER_PIN_2, LOW);
          digitalWrite(STEPPER_PIN_3, LOW);
          digitalWrite(STEPPER_PIN_4, HIGH);
          break;
        } 
  } else {
      switch(step_number) {
        case 0:
          digitalWrite(STEPPER_PIN_1, LOW);
          digitalWrite(STEPPER_PIN_2, LOW);
          digitalWrite(STEPPER_PIN_3, LOW);
          digitalWrite(STEPPER_PIN_4, HIGH);
          break;
        case 1:
          digitalWrite(STEPPER_PIN_1, LOW);
          digitalWrite(STEPPER_PIN_2, LOW);
          digitalWrite(STEPPER_PIN_3, HIGH);
          digitalWrite(STEPPER_PIN_4, LOW);
          break;
        case 2:
          digitalWrite(STEPPER_PIN_1, LOW);
          digitalWrite(STEPPER_PIN_2, HIGH);
          digitalWrite(STEPPER_PIN_3, LOW);
          digitalWrite(STEPPER_PIN_4, LOW);
          break;
        case 3:
          digitalWrite(STEPPER_PIN_1, HIGH);
          digitalWrite(STEPPER_PIN_2, LOW);
          digitalWrite(STEPPER_PIN_3, LOW);
          digitalWrite(STEPPER_PIN_4, LOW);
      } 
  }

  step_number++;

  if (step_number > 3) {
    step_number = 0;
  }
}

long microsecondsToInches(long microseconds) {
  return microseconds / 74 / 2;
}

long microsecondsToCentimeters(long microseconds) {
  return microseconds / 29 / 2;
}

struct coordinates getPosition(float dist, int step_num) {
  struct coordinates coords;
  coords.x = dist * cos(step_num * M_PI / 180);
  coords.y = dist * sin(step_num * M_PI / 180);
  return coords;
}

void readDist(int t) {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  int duration = pulseIn(echoPin, HIGH);

  long cm = min(int(microsecondsToCentimeters(duration)), 30);

  int angle;
  if (dir) {
    angle = -90 + (t * degrees);
  } else {
    angle = 90 - (t * degrees);
  }

  struct coordinates pose = getPosition(cm, angle);

  Serial.print(cm);
  Serial.print("cm, x: ");
  Serial.print(pose.x);
  Serial.print(", y: ");
  Serial.print(pose.y);
  Serial.print(", angle: ");
  Serial.print(angle);
  Serial.println();
}

Built With

Share this project:

Updates