This is an old revision of the document!
Student: Radu Octavian, 333CC
Proiectul presupune realizarea unei masinute controlate prin intermediul unui accelerometru, avand la baza comunicarea a doua placute Arduino cu ajutorul a doua module bluetooth, care masoara distante cu ajutorul unui senzor cu ultrasunet.
Acest proiect are scopul de a integra cunostiintele dobandite la laboratoarele de PM. De asemenea, poate fi util in masurarea de distante in locuri inaccesibile utilizatorilor.
Mod de functionare : Prin folosirea accelerometrului se realizeaza calculul directiei de mers a masinutei. Aceste date sunt trimise prin intermediul Bluetooth, masinuta trimitand inapoi valoarea distantei pe care o masoara pana la cel mai apropiat obstacol in directia de mers. Aceasta distanta este afisata pe un ecran OLED conectat la placuta Arduino care serveste ca si telecomanda.
Schema bloc:
Schema masina:
Schema telecomanda:
Mediu de dezvoltare: Arduino IDE
Librarii folosite:
Cod telecomanda:
#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C
#define GY_ADDRESS 0x68
constexpr int16_t X_THRESHOLD = 10000;
constexpr int16_t Y_THRESHOLD = 8000;
constexpr unsigned char MODE_STATIONARY = 30;
constexpr unsigned char MODE_FORWARD = 0;
constexpr unsigned char MODE_BACKWARD = 1;
constexpr unsigned char MODE_LEFT = 2;
constexpr unsigned char MODE_RIGHT = 3;
Adafruit_SSD1306 display(OLED_RESET);
int currentMode = 30;
int16_t accelerometer_x, accelerometer_y, accelerometer_z; // variables for accelerometer raw data
int16_t gyro_x, gyro_y, gyro_z; // variables for gyro raw data
int16_t temperature; // variables for temperature data
float distance;
char tmp_str[7]; // temporary variable used in convert function
char* convert_int16_to_str(int16_t i) { // converts int16 to string. Moreover, resulting strings will have the same length in the debug monitor.
sprintf(tmp_str, "%6d", i);
return tmp_str;
}
void setup() {
Serial.begin (38400);
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
Wire.begin();
Wire.beginTransmission(GY_ADDRESS);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission(true);
}
bool below_X() {
return -X_THRESHOLD > accelerometer_x;
}
bool above_X() {
return X_THRESHOLD < accelerometer_x;
}
bool between_X() {
return -X_THRESHOLD < accelerometer_x && accelerometer_x < X_THRESHOLD;
}
bool below_Y() {
return -Y_THRESHOLD > accelerometer_y;
}
bool above_Y() {
return Y_THRESHOLD < accelerometer_y;
}
bool between_Y() {
return -Y_THRESHOLD < accelerometer_y && accelerometer_y < Y_THRESHOLD;
}
int calculateMode() {
if (between_X() && between_Y())
return MODE_STATIONARY;
if (between_X() && below_Y())
return MODE_FORWARD;
if (between_X() && above_Y())
return MODE_BACKWARD;
if (above_X() && between_Y())
return MODE_LEFT;
if (below_X() && between_Y())
return MODE_RIGHT;
return MODE_STATIONARY;
}
void loop() {
display.setTextSize(1);
display.setTextColor(WHITE);
display.clearDisplay();
display.setCursor(10, 0);
display.println("Obstacole ahead in");
display.setCursor(50, 20);
display.print(distance);
display.println(" cm");
display.display();
display.clearDisplay();
Wire.beginTransmission(GY_ADDRESS);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) [MPU-6000 and MPU-6050 Register Map and Descriptions Revision 4.2, p.40]
Wire.endTransmission(false); // the parameter indicates that the Arduino will send a restart. As a result, the connection is kept active.
Wire.requestFrom(GY_ADDRESS, 7*2, true); // request a total of 7*2=14 registers
Wire.endTransmission(true);
// "Wire.read()<<8 | Wire.read();" means two registers are read and stored in the same variable
accelerometer_x = Wire.read()<<8 | Wire.read(); // reading registers: 0x3B (ACCEL_XOUT_H) and 0x3C (ACCEL_XOUT_L)
accelerometer_y = Wire.read()<<8 | Wire.read(); // reading registers: 0x3D (ACCEL_YOUT_H) and 0x3E (ACCEL_YOUT_L)
accelerometer_z = Wire.read()<<8 | Wire.read(); // reading registers: 0x3F (ACCEL_ZOUT_H) and 0x40 (ACCEL_ZOUT_L)
temperature = Wire.read()<<8 | Wire.read(); // reading registers: 0x41 (TEMP_OUT_H) and 0x42 (TEMP_OUT_L)
gyro_x = Wire.read()<<8 | Wire.read(); // reading registers: 0x43 (GYRO_XOUT_H) and 0x44 (GYRO_XOUT_L)
gyro_y = Wire.read()<<8 | Wire.read(); // reading registers: 0x45 (GYRO_YOUT_H) and 0x46 (GYRO_YOUT_L)
gyro_z = Wire.read()<<8 | Wire.read(); // reading registers: 0x47 (GYRO_ZOUT_H) and 0x48 (GYRO_ZOUT_L)
// uncomment this for debugging - better understanding of gyroscope
// Serial.print("aX = "); Serial.print(convert_int16_to_str(accelerometer_x));
// Serial.print(" | aY = "); Serial.print(convert_int16_to_str(accelerometer_y));
// Serial.print(" | aZ = "); Serial.print(convert_int16_to_str(accelerometer_z));
// // the following equation was taken from the documentation [MPU-6000/MPU-6050 Register Map and Description, p.30]
// Serial.print(" | tmp = "); Serial.print(temperature/340.00+36.53);
// Serial.print(" | gX = "); Serial.print(convert_int16_to_str(gyro_x));
// Serial.print(" | gY = "); Serial.print(convert_int16_to_str(gyro_y));
// Serial.print(" | gZ = "); Serial.print(convert_int16_to_str(gyro_z));
// Serial.println();
int mode = calculateMode();
if(mode != currentMode){
currentMode = mode;
}
Serial.println(currentMode);
Serial.flush();
while (!Serial.available()){
// busy waiting for distance from ultrasonic sensor
}
distance = Serial.parseFloat();
}
Cod masinuta:
#include <SoftwareSerial.h>
#include <AFMotor.h>
#define TRIG A1
#define ECHO A0
#define Speed 170
#define motor 10
#define spoint 103
#define STOP_DISTANCE 12
constexpr unsigned char MODE_STATIONARY = 30;
constexpr unsigned char MODE_FORWARD = 0;
constexpr unsigned char MODE_BACKWARD = 1;
constexpr unsigned char MODE_LEFT = 2;
constexpr unsigned char MODE_RIGHT = 3;
int mode = MODE_STATIONARY;
unsigned long previousMillis = 0;
AF_DCMotor M1(1);
AF_DCMotor M2(2);
AF_DCMotor M3(3);
AF_DCMotor M4(4);
void setup() {
Serial.begin(38400);
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
M1.setSpeed(Speed);
M2.setSpeed(Speed);
M3.setSpeed(Speed);
M4.setSpeed(Speed);
M1.run(RELEASE);
M2.run(RELEASE);
M3.run(RELEASE);
M4.run(RELEASE);
}
void loop() {
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(5);
digitalWrite(TRIG, LOW);
float t = pulseIn(ECHO, HIGH);
float distance = t*0.017015;
while (!Serial.available()){
//busy waiting for gyro direction mode
}
mode = Serial.parseInt();
Serial.println(distance);
Serial.flush();
if(distance < STOP_DISTANCE && mode == MODE_FORWARD)
mode = MODE_STATIONARY;
if (mode == MODE_STATIONARY) {
M1.run(RELEASE);
M2.run(RELEASE);
M3.run(RELEASE);
M4.run(RELEASE);
} else if (mode == MODE_FORWARD) {
M1.run(FORWARD);
M2.run(FORWARD);
M3.run(FORWARD);
M4.run(FORWARD);
} else if (mode == MODE_BACKWARD){
M1.run(BACKWARD);
M2.run(BACKWARD);
M3.run(BACKWARD);
M4.run(BACKWARD);
} else if (mode == MODE_LEFT){
M1.run(BACKWARD);
M2.run(FORWARD);
M3.run(FORWARD);
M4.run(BACKWARD);
} else if (mode == MODE_RIGHT){
M1.run(FORWARD);
M2.run(BACKWARD);
M3.run(BACKWARD);
M4.run(FORWARD);
}
}