2017년 8월 21일 월요일

33. 모터쉴드를 이용한 자율 자동차

1. 개요

모터드라이버를 이용한 장애물회피 자율자동차는 32번 주제에서 구현혀 보았습니다. 이번에는 모터드라이버가 개선된 모터쉴드를 이용하여 장애물 회피 자율자동차를 만들어 보겠습니다. 모터쉴드는 DC Motor, Step Motor, Servo Motor를 제어할 수 있으며 전원도 5V,9V
Ext_PWR 등등이 지원됩니다.그리고 아두이노 기판에 모터쉴드를 결합하기 쉽게 되어 있어 편리합니다.

2. 준비물

아두이노

서보모터
모터쉴드(MH Electronics)

점퍼케이블
초음파센서

3. 조립하기

먼저 몸체로 버려진 플라스틱을 적당히 잘라서 준비합니다.(10cmX15cm)
중간정도에 아두이노기판을 글루건으로 부착합니다. 아두이노위에 모터쉴드를 언져 부착합니다.뒷부분에 전원홀더(9V)를 2개 글루건으로 붙이고 이를 플라스틱에 글루건을 이용하여 부착 고정시킵니다.
앞부분에 서보모터를 플라스틱에 글루건을 이용하여 고정하여 부착시킵니다.
노란색 플라스틱 몸체 바닥에 바퀴 2개를 모터와함께 글르건으로 붙입니다.
플라스틱 몸체바닥 앞 중앙에 cast wheel을 부착합니다.

4. 점퍼선 연결하기
왼쪽 바퀴연결선은 DC Motor1에 오른쪽 바퀴는 DC Motor2에 연결합니다.
서보모터는 servo2에 연결합니다.(바퀴하고 서보모터 연결은 모터쉴드 바닥에 표시되어 있어 이를 참고하면 됩니다.

마지막으로 전원연결은 아두이노 연결잭에 연결하고 나머지 전원은 모터쉴드 5V와 연결합니다.
위에서 본 모양

초음파센선연결은 다음 사진을 참고하시기 바랍니다.

5.  code
#include <AFMotor.h>
#include <Servo.h>
#include <NewPing.h>
  
#define TRIG_PIN A4 // Pin A4 on the Motor Drive Shield connected to the ultrasonic sensor
#define ECHO_PIN A5 // Pin A5 on the Motor Drive Shield connected to the ultrasonic sensor
#define MAX_DISTANCE_POSSIBLE 1000 // sets maximum useable sensor measuring distance to 1000cm
#define MAX_SPEED 120 // sets speed of DC traction motors to 120/256 or about 47% of full speed - to reduce power draining.
#define MOTORS_CALIBRATION_OFFSET 3 // this sets offset to allow for differences between the two DC motors
#define COLL_DIST 20 // sets distance at which the Obstacle avoiding Robot stops and reverses to 10cm
#define TURN_DIST COLL_DIST+10 // sets distance at which the Obstacle avoiding Robot looks away from object (not reverse) to 20cm (10+10)
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE_POSSIBLE); // sets up sensor library to use the correct pins to measure distance.
AF_DCMotor leftMotor(1, MOTOR12_1KHZ); // create motor #1 using M1 output on Motor Drive Shield, set to 1kHz PWM frequency
AF_DCMotor rightMotor(2, MOTOR34_1KHZ); // create motor #2, using M2 output, set to 1kHz PWM frequency
Servo neckControllerServoMotor;  // create servo object to control a servo
  
int pos = 0; // this sets up variables for use in the sketch (code)
int maxDist = 0;
int maxAngle = 0;
int maxRight = 0;
int maxLeft = 0;
int maxFront = 0;
int course = 0;
int curDist = 0;
String motorSet = "";
int speedSet = 0;
  
//-------------------------------------------- SETUP LOOP -------------------------------------
void setup() {
  neckControllerServoMotor.attach(9);  // attaches the servo on pin 9 (SERVO_2 on the Motor Drive Shield to the servo object
  neckControllerServoMotor.write(45); // tells the servo to position at 90-degrees ie. facing forward.
  delay(2000); // delay for two seconds
  checkRoute(); // run the CheckRoute routine to find the best Route to begin travel
  motorSet = "FORWARD"; // set the director indicator variable to FORWARD
  neckControllerServoMotor.write(45); // ensure servo is still facing forward
  moveForward(); // run function to make Obstacle avoiding Robot move forward
}
//-------------------------------------------------------------------------------------------------
  
//---------------------------------------------MAIN LOOP --------------------------------------
void loop() {
  checkForward(); // check that if the Obstacle avoiding Robot is supposed to be moving forward, that the drive motors are set to move forward - this is needed to overcome some issues with only using 4 AA NiMH batteries
  checkRoute(); // set ultrasonic sensor to scan for any possible obstacles
}
//-------------------------------------------------------------------------------------------------
void checkRoute() {
  int curLeft = 0;
  int curFront = 0;
  int curRight = 0;
  int curDist = 0;
  neckControllerServoMotor.write(144); // set servo to face left 54-degrees from forward
  delay(120); // wait 120milliseconds for servo to reach position
   for (pos = 90; pos >= 36; pos -= 18) // loop to sweep the servo (& sensor) from 144-degrees left to 36-degrees right at 18-degree intervals.
  {
    neckControllerServoMotor.write(pos);  // tell servo to go to position in variable 'pos'
    delay(90); // wait 90ms for servo to get to position
    checkForward(); // check the Obstacle avoiding Robot is still moving forward
    curDist = readPing(); // get the current distance to any object in front of sensor
    if (curDist < COLL_DIST) { // if the current distance to object is less than the collision distance
      checkCourse(); // run the checkCourse function
      break; // jump out of this loop
    }
    if (curDist < TURN_DIST) { // if current distance is less than the turn distance
      changeRoute(); // run the changeRoute function
    }
    if (curDist > curDist) {
      maxAngle = pos;
    }
    if (pos > 90 && curDist > curLeft) {
      curLeft = curDist;
    }
    if (pos == 90 && curDist > curFront) {
      curFront = curDist;
    }
    if (pos < 90 && curDist > curRight) {
      curRight = curDist;
    }
  }
  maxLeft = curLeft;
  maxRight = curRight;
  maxFront = curFront;
}
//-------------------------------------------------------------------------------------------------
void setCourse() { // set direction for travel based on a very basic distance map, simply which direction has the greatest distance to and object - turning right or left?
  if (maxAngle < 90) {
    turnRight();
  }
  if (maxAngle > 90) {
    turnLeft();
  }
  maxLeft = 0;
  maxRight = 0;
  maxFront = 0;
}
//-------------------------------------------------------------------------------------------------
void checkCourse() { // we're about to hit something so move backwards, stop, find where the empty Route is.
  moveBackward();
  delay(500);
  moveStop();
  setCourse();
}
//-------------------------------------------------------------------------------------------------
void changeRoute() {
  if (pos < 90) {
    lookLeft(); // when current position of sensor is less than 90-degrees, it means the object is on the right hand side so look left
  }
  if (pos > 90) {
    lookRight(); // when current position of sensor is greater than 90-degrees, it means the object is on the left hand side so look right
  }
}
//-------------------------------------------------------------------------------------------------
  
int readPing() { // read the ultrasonic sensor distance
  delay(70);
  unsigned int uS = sonar.ping();
  int cm = uS / US_ROUNDTRIP_CM;
  return cm;
}
//-------------------------------------------------------------------------------------------------
void checkForward() {
  if (motorSet == "FORWARD") {
    leftMotor.run(FORWARD);  // ensure motors are going forward
    rightMotor.run(FORWARD);
  }
}
//-------------------------------------------------------------------------------------------------
void checkBackward() {
  if (motorSet == "BACKWARD") {
    leftMotor.run(BACKWARD);  // ensure motors are going backward
    rightMotor.run(BACKWARD);
  }
}
//-------------------------------------------------------------------------------------------------
  
// In some cases, the Motor Drive Shield may just stop if the supply voltage is too low (due to using only four NiMH AA cells).
// The above functions simply remind the Shield that if it's supposed to go forward, then ensure it is going forward and vice versa.
  
//-------------------------------------------------------------------------------------------------
void moveStop() {
  leftMotor.run(RELEASE);  // stop the motors.
  rightMotor.run(RELEASE);
}
//-------------------------------------------------------------------------------------------------
void moveForward() {
  motorSet = "FORWARD";
  leftMotor.run(FORWARD);      // turn it on going forward
  rightMotor.run(FORWARD);      // turn it on going forward
  for (speedSet = 0; speedSet < MAX_SPEED; speedSet += 2) // slowly bring the speed up to avoid loading down the batteries too quickly
  {
    leftMotor.setSpeed(speedSet + MOTORS_CALIBRATION_OFFSET);
    rightMotor.setSpeed(speedSet);
    delay(5);
  }
}
//-------------------------------------------------------------------------------------------------
void moveBackward() {
  motorSet = "BACKWARD";
  leftMotor.run(BACKWARD);      // turn it on going forward
  rightMotor.run(BACKWARD);     // turn it on going forward
  for (speedSet = 0; speedSet < MAX_SPEED; speedSet += 2) // slowly bring the speed up to avoid loading down the batteries too quickly
  {
    leftMotor.setSpeed(speedSet + MOTORS_CALIBRATION_OFFSET);
    rightMotor.setSpeed(speedSet);
    delay(5);
  }
}
//-------------------------------------------------------------------------------------------------
void turnRight() {
  motorSet = "RIGHT";
  leftMotor.run(FORWARD);      // turn motor 1 forward
  rightMotor.run(BACKWARD);     // turn motor 2 backward
  delay(400); // run motors this way for 400ms
  motorSet = "FORWARD";
  leftMotor.run(FORWARD);      // set both motors back to forward
  rightMotor.run(FORWARD);
}
//-------------------------------------------------------------------------------------------------
void turnLeft() {
  motorSet = "LEFT";
  leftMotor.run(BACKWARD);     // turn motor 1 backward
  rightMotor.run(FORWARD);      // turn motor 2 forward
  delay(400); // run motors this way for 400ms
  motorSet = "FORWARD";
  leftMotor.run(FORWARD);      // turn it on going forward
  rightMotor.run(FORWARD);      // turn it on going forward
}
//-------------------------------------------------------------------------------------------------
void lookRight() {
  rightMotor.run(BACKWARD);  // looking right? set right motor backwards for 400ms
  delay(400);
  rightMotor.run(FORWARD);
}
//-------------------------------------------------------------------------------------------------
void lookLeft() {
  leftMotor.run(BACKWARD);  // looking left? set left motor backwards for 400ms
  delay(400);
  leftMotor.run(FORWARD);
}
//-------------------------------------------------------------------------------------------------

6. 작동 동영상


라벨:

0개의 덧글:

댓글 쓰기

에 가입 댓글 [Atom]

<< 홈