[아두이노] RC카 장애물 감지시 방향 전환 기초

IOT/아두이노|2019. 2. 22. 11:52

[아두이노] RC카 장애물 감지시 방향 전환 기초



초음파레이더의 원리는 지난 시간에 기초 실험으로 살펴 보았습니다. 하다보니깐 RC카 자율주행할 때 초음파 센서로 장애물 감지을 할 경우가 문득 떠오르더군요. 그래서 초음파레이더 만들기 소스를 그대로 이용하여 몇부분만 추가하여 코딩을 완성했습니다. 그냥 갑자기 떠오른 생각이라서 코딩은 깔끔하지 않네요. 막 떠오르는데로 코딩한거니 그 점을 감안해서 코딩을 보시기 바랍니다.

1. 회로도 구성


  • 준비물 : 서보모터 2개, 초음파센서 1개, 아두이노우노
  • 내용 :45~ 125도 서보모터를 회전시키면서 초음파센서로 거리를 측정부분은 그대로 유지한 상태에서 RC카 앞바퀴 방향 제어용 서보모터를 추가하자.


머리속에서 각 부품을 실제 RC카에 배치를 상상해 보세요. 첫번째 초음파센서가 서보모터에 부착되어 있고 두번째 서보모터는 RC카 앞바퀴에 연결되었다고 상상 해보세요.

3. 코딩


  • 사용함수 : attach(사용핀), write(각도), pulseIn(입력핀, HIGH), Serial.begin(9600), Serial.print(출력값),Serial.println(출력값)
  • 내용 : 간단히 서보모터가 회전은 45~125도 범위를 잡고 전방의 장애물 탐지를 초음파센서가 담당하게 코딩하고 앞바퀴담당 서보모터는 거리 50이하 일때 전방 90도 기준으로 좌측에 장애물 발견시 우측으로 우측 장애물 발견시 좌측으로 회전시키는 코딩을 한다.

설계

앞바퀴 방향 제어를 하기 위해서 서보모터를 제어해야겠죠.

그래서 서보모터 객체를 하나 더 선언합니다.

Servo servo2;

그리고 핀을 10번을 사용하기 위해서 연결합니다.

int servoPin2 = 10;
servo2.attach(servoPin2); //angle (0~180)

앞바퀴 장애물 방향전환 조건문을 만듭니다.(하나의 패턴으로 자율주행 첫단추로 접근하는 시작 코딩)

  if(m_distance<=50 && m_angle>90) {    
    servo2.write(45);
    delay(50);   
  }
  else if (m_distance<=50 && m_angle<90){
    servo2.write(125);
    delay(50);   
  }
  else {
    servo2.write(90);
    delay(50);   
  }
  if(m_distance<=50 && m_angle>90) {    

if조건문

  • 첫번째 조건식 : "장애물(벽) 거리가 50cm 이하이고 각도가 90도 보다 큰가?" (왼쪽장애물확인)
    그러면 왼쪽 장애물이 너무 가까우니깐 오른쪽으로 핸들을 꺽어야 겠죠.
  • 두번째 조건식 : "그게 아니면 장애물(벽) 거리가 50cm 이하이고 각도가 90도보다 작은가?"(오른쪽장애물확인)
    그러면 오른쪽 장애물이 너무 가까우니깐 왼쪽으로 핸들을 꺽어야 겠죠.
  • 거짓이면 : 그냥 앞바퀴 방향각 90도로 정중앙 정면을 향하게 한다.

즉, 조건식으로 50cm이하일때 현재 방향에 따른 핸들의 방향을 결정하게 됩니다. 50cm이하에 장애물이 없으면 그냥 정면으로 계속 진행하도록 로직을 짜봤습니다.
여기서 핸들 각도를 변수로 빼면 중복되는 코딩이 3번 반복되는데 이걸 하나로 줄일 수 있겠지만 우선은 동작을 좀 더 직관적으로 이해할 수 있도록 하기 위해서 수정은 안했습니다.

초음파레이더 소스와 위에 방향전환 로직을 합쳐서 전체코딩을 을 살펴보면

#include <Servo.h>

Servo servo1;
Servo servo2;
int servoPin1 = 9;
int servoPin2 = 10;
int m_distance=0;
int m_angle=45;
int m_chk=0;

void setup() {
  Serial.begin(9600);
  servo1.attach(servoPin1); //angle (0~180)
  servo2.attach(servoPin2); //angle (0~180)
}

void loop() {
  
  //초음파센서 몸체 회전
  servo1.write(m_angle);
  delay(50);
  
  m_distance=CalDistance(7);  //초음파센서로 거리계산함수   
  Serial.print("d : ");
  Serial.println(m_distance);
  
  //앞바퀴 장애물 방향전환
  if(m_distance<=50 && m_angle>90) {    
    servo2.write(45);
    delay(50);   
  }
  else if (m_distance<=50 && m_angle<90){
    servo2.write(125);
    delay(50);   
  }
  else {
    servo2.write(90);
    delay(50);   
  }
  
  //초음파센서 회전각
  if(m_chk==0){
    if(m_angle<125)m_angle+=1;
    else m_chk=1;
  }
  else{
    if(m_angle>45)m_angle-=1;
    else m_chk=0;
  }
  
}

int CalDistance (int Pin){  //초음파센서(3핀) 예제를 그대로 외부함수로 빼냄
  pinMode(Pin,OUTPUT); //출력모드로  사용
  digitalWrite(Pin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(Pin,HIGH); 
  delayMicroseconds(10); 
  digitalWrite(Pin,LOW); 
  
  pinMode(Pin,INPUT);    //입력모드로 사용
  int duration = pulseIn(Pin, HIGH);
  
  int distance = duration / 57.5;  //가상시뮬레이션의 오차율을 줄이기 위해 이걸로 테스트 함.

  return distance; //거리값 리턴
}

5. 결과


설계과정은 이번에 생략하고 결과만 시뮬레이터로 돌려 보는 장면만 보여 드립니다. 지난시간에 회로도 만드는 과정을 해봤으니 구지 중복해서 다시 똑같은 것을 찍을 필요는 없고 서보모터만 하나 추가했기 때문에 결과만으로 충분해서 회로도 배치과정은 생략했네요.

마무리


오늘은 아두이노 RC카에 주행에 관한 첫 단추인 방향전환에서 하나의 패턴을 기초 패턴으로 로직을 만들었습니다. 이걸로 주행이 가능하지 않습니다. 단지 이렇게 코딩해 놓고 조금씩 패턴을 늘리고 로직을 늘려가야 합니다.

여기서는 단적으로 왼쪽 장애물 감지시 레드존에 들어가고 바로 오른쪽으로 45도 회전을 시켜서 그린존으로 탈출하는 코딩입니다. 어떤 문제가 있을까요 바로 현재 RC카의 주행 속력에 대한 장애물과의 거리별로 방향전환 각도를 가변적으로 해야합니다. 그래야 매끄렇게 회전이 됩니다. 그리고 또 문제는 가령 전방 직선도로로 달릴때 통과 할 수 공간이 충분하지만 가력 왼쪽이나 오른쪽 방향에 장애물이나 벽과의 거리가 50 이하면 그냥 방향핸들을 반대 방향으로 꺽어버리는 문제가 방생합니다. 즉, 전방에 안전거리 확보가 확인되면 그상태로 주행하고 안전거리가 미확인시 좌우측에 위험거리가 감지되면 방향을 전환하더록 로직을 수정해야겠죠.

이렇게 주행에서의 문제들을 하나씩 찾아내고 그걸 해결하는 패턴들을 하나씩 만들어 내야합니다. 그래야 자율주행이 가능해지는 것이죠. 다른 방식으로 장애물 감지되면 그상태에서 주행이 정지되고 안전거리 확보 패턴로직 주행을 하고 다시 안전거리가 확보되면 주행을 다시 시작하는 방식으로도 변경할 수 있겠죠.

코딩을 쉽게 하기 위해서는 실제 장난감 자동차를 방에서 손으로 밀면서 주행을 시켜보세요 그리고 관찰하면 이런 상황일때 이걸 어떻게 어떻게 빠져나올지 손으로 자동차를 움직이시고 그 움직을 잘 기억했다가 그 움직이는 동작 패턴을 코딩화 하시면 됩니다.

암튼 집에 굴러다니는 장단감을 가지고 한번 손으로 밀면서 띠따! 빵빵! 하면서 가지고 노세요. 그리고 나서 그 움직임을 기역했다가 코딩을 상상해보세요.


댓글()

[아두이노] 초음파레이더 만들기(기본동작제어)

IOT/아두이노|2019. 2. 21. 10:16

[아두이노] 초음파레이더 만들기(기본동작제어)



이번시간에 초음파레이더를 기본동작 원리를 실험하는 시간을 갖도록 하겠습니다. 가장 많이 검색되는 주제이기도 하죠. 현재 초음파센서가 없는 관계로 실제 구동 장면은 추가하고 싶었는데 아쉽게 못 보여 드리네요. 그래도 가상시물레이터에서 충분히 표현이 되니깐 실제 만드는 것은 그리 어렵지 않을꺼에요. 물론 거리계산에 따른 오차율 보정 작업이 필요하지만요. 오늘은 서보모터를 회전시키면서 초음파센서로 거리를 측정하고 그 값을 아두이노 IDE 시리얼모니터로 거리 값이 동시에 출력되게 표현 함으로 초음파레이더의 기본 원리를 배워보도록 하죠.

1. 초음파센서 복습


제 블로그에서 정리할 때 함수로 표현했었습니다. 초음파센서로 거리를 측정하는 로직을 따로 외부함수로 만든 것을 그대로 인용해서 적용하겠습니다.int distance = duration / 57.5; 이것은 가상시뮬레이터에 대충 거리를 보정한 값이고 실제로는 공식을 해보고 거리값의 오차가 있으면 약간씩 값을 바꾸면서 거리값을 보정하시면 됩니다.

  • 공식 : ((float)(340 * duration) / 10000) / 2; (340은 초음기종에 따라 달라질 수 있는점 참고)
int CalDistance (int Pin){  //초음파센서(3핀) 예제를 그대로 외부함수로 빼냄
  
  pinMode(Pin,OUTPUT); //출력모드로  사용
  digitalWrite(Pin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(Pin,HIGH); 
  delayMicroseconds(10); 
  digitalWrite(Pin,LOW); 
  
  
  pinMode(Pin,INPUT);    //입력모드로 사용
  int duration = pulseIn(Pin, HIGH);
  
  int distance = duration / 57.5;  //가상시뮬레이션의 오차율을 줄이기 위해 이걸로 테스트 함.

  return distance; //거리값 리턴
}

이렇게 함수로 만들어 놓으면 나중에 초음파센서를 사용할 때 이 함수를 복사하시면 되겠죠. 이건 3핀 초음파센서여서 사실 4핀 초음파센서에서는 TRIG, ECHO핀이 따로 존재하기 때문에 setup()함수에서 각 핀을 선언해주시면 되기 때문에 CallDistance()함수에서 핀의 출력/입력모드를 선언할 필요가 없습니다. 가상시뮬레이터에서는 3핀이여서 어쩔 수 없이 추가된 것이기 때문에 실제로 1200원 짜리 4핀 초음파센서를 사용하시면 핀모드 선언을 지워주셔서 함수를 사용하시면 됩니다.
쏘는것은 TRIG, 받는 것은 ECHO 핀인 것만 기억하시면 쉽게 변경되시겠지요. 즉, 3핀 초음파센서에서 출력모드일 때 TRIG이고 입력모드일 때 ECHO라고 생각하시면 됩니다.

2. 서보모터 복습


#include <Servo.h>
 
 Servo servo;
 int servoPin = 9;
 
 servo.attach(servoPin); //angle (0~180)
 servo.write(m_angle);
 delay(50);
 
 m_angle+=1; or m_angle= m_angle+1;

9번핀을 servo모터의 출력핀으로 연결하고 servo.write()로 각도(angle)만큼 이동하는데 마지막 라인의 m_angle은 +1씩 증가합니다. 즉 0도에서 1도씩 계속 servo모터를 회전하게 되는 것이죠. 딜레이시간은 1도여서 아주 짧게 0.05초를 줬습니다.

3. 회로도 구성


  • 준비물 : 서보모터 1개, 초음파센서 1개, 아두이노우노
  • 내용 : 0~180도 서보모터를 회전시키면서 초음파센서로 거리를 측정해보자.


가장 간단한 회로도 입니다. 대충 회로도를 보시고 해당 위치의 핀에 선을 연결하시면 됩니다.

4. 코딩


  • 사용함수 : attach(사용핀), write(각도), pulseIn(입력핀, HIGH), Serial.begin(9600), Serial.print(출력값),Serial.println(출력값)
  • 내용 : 간단히 0~180의 범위를 1도씩 회전하면서 초음파로 거리를 측정하여 아두이노시리얼모니터에 거리값을 출력한다.

설계는 위의 1, 2에서 복습 차원의 코딩을 그대로 사용했습니다. 중요한 것은 0에서 180도 까지 1도씩 회전시키고 다시 180에서 0도까지 1도씩 회전하는 것이죠.

설계

(1) 제어 변수를 만든다.

Servo servo; 
int servoPin = 9;

int m_distance=0;
int m_angle=0;
int m_chk=0;
  • servo : 서보클래스 객체 선언
  • servoPin : 서보모터 제어하는 핀번호
  • m_distance : 거리 계산값(초음파센서로 거리측정동작을 수행하는 CalDistance()함수로 구한 값이 저장)
  • m_angle : 서보모터의 회전각(write()함수로 서보모터를 실제 회전)
  • m_chk : 회전 방향 상태값(초기값 0은 0에서 180도로 회전을 뜻하고 1은 180도에서 0도로 회전을 뜻한다.)

(2) m_chk 변수가 회전 방향 상태를 나타내고 제어하는 방법

if(m_chk==0){
    if(m_angle<180)m_angle+=1;
    else m_chk=1;
  }
  else{
    if(m_angle>0)m_angle-=1;
    else m_chk=0;
  }

if 조건문으로 m_chk변수의 초기값이 0이다 m_angle(각)도 0도이다. 조건식이 m_chk==0 으로 m_chk가 0과 같은가 아닌가로 물어본다. 두가지 패턴으로 분리되는 순간이다. 0가 같다면 참인문장이 1이면 거짓문장이 수행 되겠죠. m_chk변수가 초기값으로 0임으로 참이 된다. 그 안에 다시 if문으로 m_angle(각)이 180도보다 작은가가 조건식이 걸려있다. 180도보다 작으면 m_angle+=1;로 m_angle=m_angle=+1과 같은 문장이다. 즉, m_angle(각)은 1도ㅀ 증가하게 된다. 그런데 만약에 m_angle(각)가 180도 이상이 되면 else 이하 문장이 수행됩니다. m_chk=1로 회전 방향 상태값이 바뀌게 됩니다. 그러면 다음 루프때 if 조건문 m_chk가 0이 아니기 때문에 else 이하 문장이 수행되고 반대로 m_angle 변수가 0보다 크냐고 붇고 크면은 m_angle-=1로 -1도로 감소하게 된다. 위 코딩하고는 반대 동작을 수행하는 것이죠.

다시 종합해서 설명하자면 m_chk변수 기준으로 0이면 m_angle 값이 180도가 될때까지 1씩 증가하고 180도가 되면은 m_chk변수를 1로 변경하고 m_chk변수가 1이면 m_angle 값이 0도가 될때까지 -1씩 감소하게 된다. 그리고 0도가가 되면 m_chk변수를 0으로 변경한다. 이렇게 무한 반복하게 되는 로직입니다.

(3) 결과는 아두이노 IDE 시리얼모니터로 출력

Serial.begin(9600);

Serial.print("d : ");
Serial.println(m_distance);

begin(9600)은 setup()함수에 선언하고 나머지 모니터 출력은 print(출력값)와 printIn(출력값)함수가 있는데 print()은 출력값을 출력하고 새로운 라인으로 넘어가지 않고 현재 라인에 머문다. printIn()은 출력값을 출력한뒤에 새로운 라인으로 넘어가라는 의미 입니다. 문서 장성할 때 키보드 Enter 명령으로 생각하시면 됩니다. C언어에서는 '\n'로 생각하시면 됩니다.

Serial.print("d : ");
Serial.println(110);

결과 => d : 110

대충 의미를 이해하셨겠죠.

코딩을 하면

#include <Servo.h>

Servo servo; 
int servoPin = 9;
int m_distance=0;
int m_angle=0;
int m_chk=0;

void setup() {
  Serial.begin(9600);
  servo.attach(servoPin); //angle (0~180)
}

void loop() {
  servo.write(m_angle);
  delay(50);
  
  m_distance=CalDistance(7);  //초음파센서로 거리계산함수   
  Serial.print("d : ");
  Serial.println(m_distance);
    
  if(m_chk==0){
    if(m_angle<180)m_angle+=1;
    else m_chk=1;
  }
  else{
    if(m_angle>0)m_angle-=1;
    else m_chk=0;
  }
}

int CalDistance (int Pin){  //초음파센서(3핀) 예제를 그대로 외부함수로 빼냄
  pinMode(Pin,OUTPUT); //출력모드로  사용
  digitalWrite(Pin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(Pin,HIGH); 
  delayMicroseconds(10); 
  digitalWrite(Pin,LOW); 
  
  
  pinMode(Pin,INPUT);    //입력모드로 사용
  int duration = pulseIn(Pin, HIGH);
  
  int distance = duration / 57.5;  //가상시뮬레이션의 오차율을 줄이기 위해 이걸로 테스트 함.

  return distance; //거리값 리턴
}

5. 결과


가상시뮬레터에서 실험 결과는 깔끔하게 나왔는데 실제 표현에서는 보정 작업이 꼭 필요 합니다.

그리고, 원래 실제로 초음파레이더를 만든다면 그래픽작업으로 레이더를 만들어 레이더에 검색된 물체를 현재회전각과 거리값으로 (x,y)의 좌표를 구할 수 있고 그걸 그래픽작업한 모니터에 원하는 형태로 그래픽모양을 출력하면 좀 더 그럴싸해 지겠죠.

여기에서는 단지 아두이노 IDE 시리얼모니터에 거리값만 출력했습니다. 그게 기본 초음파레이더의 정보입니다. 서보모터의 각도와 거리만 있으면 측정된 물체의 (x,y) 좌표를 구할 수 있고 그것을 프로세싱이나 스크래치로 이미지화 하면 보기가 더 좋겠지만 핵심은 그게 아니로 회전과 거리 측정을 동시에 수행한다는 것에 있습니다. 이미지 시각화를 단지 보여주는 부수적인 효과일뿐이죠. 동영상을 보시고 서보모터가 회전하면서 시리얼모니터에 초음파 센서의 거리가 측정되어 출력되는 걸 잘 보시고 상상을 해보세요. 서보모터에 초음파센서가 부착되어 회전되는데 그 회전하는 각도에 정면의 물체와의 거리를 측정하는 모습을요. 그러면 아마 대충은 이해가 되실 꺼에요.

마무리


간단히 초음파레이더의 기본 로직만 설명했습니다. 그리고, 오늘 포스팅한 코딩은 사실 정교한 제어라고 할 수 없습니다. 왜냐면 서보모터 종류에 따라 좀 다르게 회전이 되는 경우가 있습니다. 참고로 코딩에서 servo.attach(servoPin, Min, Max)로 범위를 설정하고 servo2.writeMicroseconds(각도시간값)으로 제어하시면 더 정교하게 제어가 가능할꺼에요. 실제로 테스트 할때는 위 방식대로 해보다가 안되면 이 방식으로 바꿔서 서보모터의 각도를 제어하시면 됩니다. 4핀이였으면은 현실 4핀 서보모터랑 동일해서 더 편했을텐데 3핀 초음파센서여서 약간 코딩이 아쉽습니다.

추가로 스크래치나 프로세싱 프로그램을 다룰 수 있는 분이라면 그걸 통해서 초음파레이더에 그래픽처리를 통해 실제 레이더처럼 표현이 가능할 꺼에요. 프로세싱을 제대로 공부한적이 없고 잠깐 맛보기로 함수만 몇개 써본게 전부라 프로세싱 프로그램을 사용하여 레이더 그래픽효과를 다음편에 추가해서 보여주고 싶긴 하는데 할까 말까 고민되네요. 잠깐 프로세싱에서 레이더 표현 그래픽 함수 몇개만 공부해서 로직을 짜면 되기는 한데 프로세싱을 새로 설치하고 공부하기가 좀 귀찮아서 생략할지 아니면 표현을 할지 고민을 해 봐야 겠네요.

오늘의 포스팅의 내용은 서모모터회전을 하면서 초음파센서로 거리를 측정한다 이것만 머리속에 넣으시면 됩니다.


댓글()

[아두이노] 초음파줄자 응용

IOT/아두이노|2019. 2. 9. 12:46

[아두이노] 초음파줄자 응용




초음파센서로 줄자를 만들려면 대충 이런식으로 A, B의 벽까지의 거리를 측정하면 쉽게 줄자가 만들어 질 수 있겠죠.
이걸 표현하기 위해서 실험을 하고자 합니다.

1. 회로도 구성


  • 준비물 : 초음파센서3핀 2개, 스위치버턴 1개, 아두이노우노, 뻥판
  • 내용 : 벽과 벽사이의 거리를 측정하는 줄자를 구현해보자.

스위치를 누르면 아두이노우노 본체를 기준으로 양쪽 두지점의 벽과 벽사이 거리를 측정하도록 하기 위해서 회로도를 우선 아두이노우노 기준으로 양쪽 방향으로 초음파센서를 배치하여 회로도를 구성하였습니다.


2. 코딩


  • 거리계산 : ((float)(340 * 초음파거리시간값) / 10000) / 2;
  • 두지점거리계산식 : 아두이노우노를 10cm로 가정할경우
    total=v1+v2+10; => v1(A초음파), v2(B초음파), 10(아두이노우노본체크기)
  • 내용 : 스위치를 누르면 A,B 초음파 거리를 측정하고 그 결과를 시리얼모니터에 출력한다.

우선 스위치버턴은 복습차원으로 내부풀업저항을 이용합니다. 그래서 pinMode은 INPUT_PULLUP으로 선언합니다. 그리고 스위치 버턴값을 읽기 위해서 digitalRead(핀번호) 함수를 사용합니다. 지난 스위치버턴 포스팅에서 이미 소개했으며 복습차원으로 스위치 버턴을 사용하였습니다.

void setup() {
  Serial.begin(9600);
  pinMode(5,INPUT_PULLUP);
}
void loop() {  
  if(digitalRead(5)==0){
    float v1=UltrasonicDistance(6);
    float v2=UltrasonicDistance(7);
    float total=v1+v2+10;
    Serial.println(total);
    delay(500);
  }  
}

float UltrasonicDistance(int m_pin){
  pinMode(m_pin,OUTPUT); 
  digitalWrite(m_pin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(m_pin,HIGH); 
  delayMicroseconds(10); 
  digitalWrite(m_pin,LOW); 
  
  pinMode(m_pin,INPUT);    
  float duration = pulseIn(m_pin, HIGH);  
  return duration / 57.5;  
}

여기서 2개의 초음파 거리측정을 해야하는데 그러면 두번의 중복 코딩이 발생합니다. 지난시간에 배웠던 C언어문법 외부함수로 재정의하여 뺐습니다.

복습하자면

float 초음파거리(int A){
 return 거리식;
}

초음파거리함수에 인자는 핀번호입니다. 함수 앞에 float는 변수 선언에서 설명한 자료형입니다. 즉, 함수 앞에서 자료형이 표현되었다는 것은 return의 명령어로 자료형(float)으로 반환한다는 의미입니다. 여기서는 좀 더 정확한 거리계산을 위해서 실수형으로 거리 계산된 값을 반환하겠다는 의미인거죠. 만약 정수형(int, long)으로 반환하겠다면 앞에 정수자료형을 선언하시면 됩니다.

loop()함수에서 사용할때는

<
v1=초음파거리(6)

이렇게 하면 6번핀의 초음파센서가 거리계산을 한뒤에 그 값을 반환하여 v1에 저장하게 됩니다.
v1 6번핀에 연결된 초음파센서 거리값이 저장됩니다.

초음파거리 계산식을 외부함수로 재정의함으로써 중복코딩을 줄이게 됩니다.
loop()안에는 아두이노 전원이 공급되고 반복되는 작업 명령들이 수행됩니다. 가독성을 위해서는 될 수 있으면 loop()함수에 선언되는 코딩들은 최소화 해야합니다. 그래야 가독성이 좋고 나중에 수정하기도 편합니다.

코딩 순서는

  1. 스위치버턴을 누르면 거리를 계산한다.
    pinMode(5,INPUT_PULLUP); //선언
    if(digitalRead(5){ //동작
    거리계산;
    }
  2. A, B초음파 거리 계산측정한다.
    float v1=UltrasonicDistance(6); //A 초음파거리계산
    float v2=UltrasonicDistance(7); //B 초음파거리계산
  3. 최종거리 계산한다.
    float total=v1+v2+10;
  4. 시리얼모니터에 그 결과를 출력한다.
    Serial.begin(9600); //선언
    Serial.println(total); //출력

3. 결과



마무리


코딩은 우선 어떤 명령을 내릴지 한글로 메모장에다가 순서를 정하여 글로 써보세요. 그리고 그 명령에 대해 사용할 함수들은 각 부품을 다룰때 쓰던 함수들을 그대로 사용하시면 됩니다. 어렵게 생각하실 필요없이 각 부품을 소개할때 거기에 사용한 함수들 2~3개를 기억했다가 그 함수의 의미를 이해하고 그것을 응용해서 표현하시면 됩니다.

정교한 초음파센서를 이용해서 건축현장에서 건물안에 길이를 측정할 때 유용하겠죠.

또 초음파로 어떤것을 표현할 수 있을까요. 상상의 나래를 펼쳐 보세요.


댓글()

[아두이노] 거리경보장치 응용

IOT/아두이노|2019. 2. 7. 18:50

[아두이노] 거리경보장치 응용



예전에 실험한 내용인데 초음파 응용편으로 소개할까 합니다. 거리경보장치는 실생활에 가장 유사한것이 자동차 후진 주차할때 경보장치를 연상하시면 될꺼에요. 뒤에 장애물과의 거리가 위험할때 나는 경보음을 생각하시면 아마 이해가 빠를꺼에요.

1. 회로도 구성


  • 준비물 : 초음파센서3핀 1개, led 2개, 저항 220옴 2개, 피에조부저 1개, 아두이노우노, 뻥판
  • 내용 : 장애물과의 거리가 50cm미만일때 경보음과 Red Led에 불이 들어오고 위험을 알리고, 50cm이상일때 Green Led에 불이 들어오고 안전상태를 표현합니다.


2. 코딩


  • Led : 선언-pinMode(핀번호, OUTPUT) 제어-digitalWrite(핀번호,상태값); 로 상태값 1(5V) or 0(0V)

  • 피에조부조 : 제어-tone(출력핀,음계,음길이), noTone(출력핀)으로 음과 음사이를 끊어줌

  • 초음파센서 : 선언pinMode(핀번호, 입/출력모드), delayMicroseconds(시간값)으로 마이크로초로 잡게 딜레이 시킴, pulseIn(7, HIGH)로 초음파가 장애물에 부딪치고 되돌아온 거리시간값을 입력받음

  • 거리계산 : ((float)(340 * 초음파거리시간값) / 10000) / 2;


코딩 설계는

  1. 초음파센서 거리 측정한다.
  2. Led 2개로 안전/위험 상태를 나타낸다.
  3. 피에조부조에서 위험거리일때 경보음이 울리게 한다.

1번 코딩 :
지난시간의 초음파 거리측정 코딩을 그대로 적용한다. 하지만 안전/위험 상태를 기준을 50cm로 설정한다면 어떻게 코딩해야할까요. 지난시간에 배웠던 문법 if문 조건이 참/거짓으로 나뉘면 쉽겠죠.

  • 거리측정은 7번핀에서 pulseIn(7, HIGH)로 거리시간값을 ((float)(340 * 초음파거리시간값) / 10000) / 2 로 거리가 구함
  • if(거리<50) {처리문1; } else {처리문2;}

2번 코딩 :
led 2개로 led은 위험, green은 안전으로 1번 코딩에서 50cm미만일때 red led 켜고, 50cm이상일때 green led 켜면 되겠죠.

if(거리<50){
    digitalWrite(11, HIGH);  
    digitalWrite(10, LOW);  
}
else
{
   digitalWrite(11, LOW);  
   digitalWrite(10, HIGH);  
}

참쉽죠

3번 코딩 :
경보음은 피에조부저에서 tone(), noTone()함수를 어떤 음계로 음의길이를 어느정도 할지는 자유입니다. 그런데 어디에 코딩할까. 50cm이하 일때 경보음을 울려야 겠죠.

if(거리<50){
    tone(12,523,1000/8);     // 도음으로 8분음표(음길이)
    delay(1000/4*1.30);             
    noTone(12);            
}
else
{
}

이렇게 해서 코딩은 간단히 해결되었습니다. 쪼개서 보면 별거 없습니다. 처음 기준이 되는 부품이 어떤 상태가 되면 다른 부품이 그 상태를 기준으로 어떻게 변화되는지만 글로 한번 설계해보시고 그걸 코딩으로 표현하시면 됩니다.

초음파센서로 거리가 50cm미만이면 위험상태(red led 켜고, 피에조부저 경보음)와 안전상태(green led 켜기)를 표현한 것 뿐이죠. 그런데 이걸 다 합쳐진 코딩을 보면 복잡해 보일 수 있습니다. 하지만 부품 한개 한개의 제어한 것들을 합치니깐 복잡해 보일뿐 부품을 개별적으로 생각하시면 아주 간단한 코딩입니다.

종합해서 코딩하면은

void setup() {  
  pinMode(11, OUTPUT);
  pinMode(10, OUTPUT);
}
void loop() {   
  pinMode(7,OUTPUT); //7번핀 출력모드로
  digitalWrite(7, LOW); 
  delayMicroseconds(2); 
  digitalWrite(7,HIGH); 
  delayMicroseconds(10); 
  digitalWrite(7,LOW); 
  
  pinMode(7,INPUT);    //7번핀 입력모드로
  float duration = pulseIn(7, HIGH);
  float distance = duration / 57.5;  
  

  if(distance < 50){    //50cm 미만 경보발동

    digitalWrite(11, HIGH);  
    digitalWrite(10, LOW);  

    tone(12,523,1000/8);     // 도음으로 8분음표(음길이)
    delay(1000/4*1.30);             
    noTone(12);            

  } else{                   //50cm 이상 안정거리
    digitalWrite(11, LOW);  
    digitalWrite(10, HIGH); 
  } 
}  

3. 결과



마무리


led, 피에조부저, 초음파센서를 각각 이전 시간에 배웠고 그걸 합쳐서 하나의 경보장치를 만들어 보았습니다.
또, 어떤것들이 있을까요 한번 상상의 나래를 펼쳐보세요.

초음파센서가 은근 재밌는 소재라 또다른 응용편을 다음에 소개 할께요.


댓글()

[아두이노] 초음파센서 제어

IOT/아두이노|2019. 2. 6. 11:01

[아두이노] 초음파센서 제어



오늘은 재밌는 소재로 거리를 측정할 수 있는 초음파센서를 사용하여 실험하는 내용을 다뤄 보겠습니다. 실제 초음파센서를 구매하시면 4핀으로 구성되어 있는데 가상시뮬레이터에서는 초음파센서가 3핀으로 되어서 어떻게 코딩해야하나 혼동 되실 수 있지만 원리는 동일하니깐 어렵게 생각하실 필요는 없습니다.

1. 초음파센서



초음파센서를 부품을 실제 구입하면 1200원정도 하는 초급 초음파센서를 구매하실수 있을꺼에요. 핀은 총 4핀으로 전원(+,-) 2핀, 입력핀, 출력핀으로 구성되어 있습니다. 하지만 가상시뮬레이터에서는 3핀으로 구성되어 있으면 입력/출력을 한핀에서 다 제어해야 합니다.

가상 시뮬레이터 코딩은 이 한핀을 어떻게 제어할지만 생각하시고 표현하시면 됩니다.

2. 초음파센서 계산 공식


  • 공식 : 기본 340 (위 1200원짜리 4핀 초음파센서 초음파속도입니다.)
    거리 = ((초음파속도 * 센서시간값) / 10000) / 2

            ((float)(340 * duration) / 10000) / 2;  
    

초음파속도 : 실제 사용하는 초음파센서 부품의 초음파속도입니다. 즉 초음파센서마다 초음파속도는 다르고 부품을 구매하실때 제공되는 정보를 잘 확인하시면 정교한 계산을 하실 수 있을꺼에요.

센서시간값 : 초음파센서에서 초음파가 나가고 앞에 장애물에 부딪치고 되돌아오는데 까지 걸리는 시간값입니다. 왕복시간값이라고 생각하시면 됩니다. 그래서 마지막에 나누기 2를 함으로써 초음파센서의 위치에서 장애물까지의 거리가 나오게 되는 것이죠.

3. 초음파센서 코딩

  digitalWrite(7, LOW); 
  delayMicroseconds(2); 
  digitalWrite(7,HIGH); 
  delayMicroseconds(10); 
  digitalWrite(7,LOW); 
   
  float duration = pulseIn(6, HIGH);
    
  float distance = ((float)(340 * duration) / 10000) / 2;  
    

7번핀이 출력모드이고 6번핀은 입력모드입니다. 7번핀으로 초음파를 쏘고 되돌아오는 초음파를 6번핀에서 읽게 됩니다. 그 값은 시간값이고 초음파공식에 대입하여 계산하게 됩니다.

  1. 초음파를 쏘기 전 초음파출력핀을 LOW(0)으로 한다. => 초기단계
  2. 딜레이 delayMicroseconds()함수는 시간을 마이크로초로 딜레이 시킬 때 사용. => 대기시간단계
  3. 초음파출력핀을 HIGH(5V)으로 한다. => 초음파를 출력 시작
  4. 딜레이 delayMicroseconds()함수로 대기한다. => 초음파를 쏘는 시간이다.
  5. 초음파출력핀을 LOW(5V)으로 한다. => 초음파 출력 중지

쉽게 말해서 초기상태는 초음파 출력핀 0V 상태로 2마이크로초로 초기상태로 뒀다가 7번핀을 통해 10마이크로초동안 초음파를 쏘고 난뒤에 초음파 출력핀 0V으로 10마이크로초동안만 초음파를 쏜 신호값을 거리계산에 사용한다는 점만 이해하시면 된다.

pulseIn(입력핀, HIGH)함수 : 펄스 신호의 길이를 잴 때 사용합니다. 초음파 되돌아 왔을때 HIGH->LOW가 되는 시점까지의 시간값을 반환하는 함수입니다. 좀 어려울 수 있습니다.
그냥 저 함수로 초음파 거리 시간값을 읽어오는 구나 정도만 처음에 이해하시면 됩니다.

정 모르겠다면 통으로 저 코딩을 외우시면 됩니다. 초음파센서를 사용할때 저 코딩으로 제어하는 구나 정도만 이해하시면 됩니다.

4. 회로도 구성


  • 준비물 : 초음파센서3핀 1개, 아두이노우노

5. 코딩


void setup() {
  Serial.begin(9600);
}
void loop() {   
  pinMode(7,OUTPUT); //출력모드  초음파 출력
  digitalWrite(7, LOW); 
  delayMicroseconds(2); 
  digitalWrite(7,HIGH); 
  delayMicroseconds(10); 
  digitalWrite(7,LOW); 
  
  pinMode(7,INPUT);    //입력모드로 초음파 입력
  float duration = pulseIn(7, HIGH); //초음파 거리 시간값 읽기
  float distance = duration / 57.5;  // ((float)(340 * duration) / 10000) / 2;   

  Serial.println(distance);   
} 

핀의 입력/출력모드 setup()함수에 선언된다고 했는데 여기서는 loop()함수에서 선언하였습니다. 왜 그렇게 했을까요. 그것은 바로 7번핀을 입력모드와 출력모드를 둘 다 사용해야 하기 때문에 계속 핀모드를 변경해야 합니다. 그래서 loop()함수에 선언된거죠.

초음파를 출력하기전에 7번핀을 출력모드로 선언했다가 다시 7번핀을 pulseIn()함수로 입력을 받을때에는 그 앞에 7번핀을 입력모드로 선언해야겠죠. 이런식으로 해서 7번핀으로 입력/출력모드 제어가 가능해 지는 것이죠.

 float distance = duration / 57.5;  // ((float)(340 * duration) / 10000) / 2;   

이식은 공식에서 최대한 줄이고 가상시뮬레이터에서 좀 더 거리가 비슷하게 나타내기 위해서 근사값 57.5로 표현했습니다. 실제로 하실때는 정식 공식을 사용하세요. 가상시뮬레이터에서는 정식 공식으로 대입하면 오차 거리가 좀 크게 나서 일부러 공식을 줄이고 줄인 공식에서 숫자를 앞뒤로 근사값들을 임의로 정해서 여러차례 실험한 뒤에 가장 오차가 적게 나오는 값이 57.5여서 이렇게 식을 만들었습니다.

실제로 하실때에는 정식 공식을 사용하시고 정식 공식을 써도 오차 거리가 발생할때에 그 부품에 맞게 근사값들을 잡아서 오차 거리를 줄이시면 아마 될꺼에요.

시리얼모니터 출력

지난시간에 사용했지만 복습차원으로 다시 설명하자면

아두이노 IDE 시리얼모니터를 사용하기 위해서

void setup()
{
 Serial.begin(9600);
}
void loop(){
Serial.println(distance);   
}

setup()함수에서 시리얼 통신을 시작한다고 선언(Serial.begin) 하고 loop()함수에서 시리얼모니터로 출력(Serial.println) 합니다.

Serial.println(출력값);   

이정도만 우선 알아두세요.

6. 결과

마무리


실제로 한다면 4핀 코딩을 해야하는데 아래와 같이 실험하시면 됩니다.

void setup() {
  Serial.begin(9600);
  pinMode(7,OUTPUT); //출력모드
  pinMode(6,INPUT);    //입력모드
}
void loop() {    
  digitalWrite(7, LOW); 
  delayMicroseconds(2); 
  digitalWrite(7,HIGH); 
  delayMicroseconds(10); 
  digitalWrite(7,LOW); 
   
  float duration = pulseIn(6, HIGH);
  float distance = duration / 57.5;  // ((float)(340 * duration) / 10000) / 2;  

  Serial.println(distance);   
}  

이 초음파센서 하나로 어떤곳에 사용하면 좋을까요 한번 상상의 나래를 펼쳐보세요. 초음파센서가 거리를 측정할 수 있는 재밌는 부품이여서 거리를 측정할 수 있으면 할 수 있는 것들이 참 많습니다. 한번 생각해 보세요.


댓글()