1) digitalWrite(), digitalRead(), pulseIn() 함수 등의 표준 함수를 사용하여 위 조건을 만족하는 함수, Read_mm_Dist(echoPin, trigPin, Temperature)를 제작한다.
2) 다른 표준 함수는 사용하지만, pulseIn() 표준 함수를 사용하지 않고, 동일한 동작을 하는 자체 MyPulseIn() 함수를 설계하고 이를 기반으로 제시된 함수 Read_mm_Dist2()를 설계한다.
3) Read_mm_Dist()와 Read_mm_Dist2()의 거리 측정 오차가 어느 정도(%)인지 실험을 통해 비교하시오. 다음 관점에서 분석하기 바랍니다.
① 10회 이상의 평균을 이용하여 산출
② micros() 함수의 평균오차와 비교
# 프로그램 설명
1. Echo, Trig 단자들을 각각 7, 8로 define 하고 섭씨 온도를 27도로 정한다. 장애물이 일정 범위에 속할 때 거리를 측정하기 위해 최대 거리 300mm, 최소 거리 50mm로 전역 변수를 사용하여 선언한 후 초기화한다.. 필요한 전역 변수 왕복시간(us), 센서와 장애물 사이의 거리(mm)를 각각 두 개의 함수에서 사용할 수 있도록 2개씩 선언한다.
소리의 이동 속도(mm/us), 두 함수의 거리 측정 오차(mm), 현재 시간과 직전 시간의 차이(us), micros() 함수 평균 오차(us)를 저장할 전역 변수를 선언하고 초기화한다.
MyPulseIn() 함수에서 사용할 unsigned long 형 변수 s(HIGH 펄스 시작 시간), e(HIGH 펄스 종료 시간)를 선언하고 micros() 함수의 평균 오차를 구하기 위해 현재 시간을 구하여 저장할 변수 time을 선언한다.
2. void setup() 부분에서 두 함수의 거리 측정 오차와 micros() 함수의 평균 오차를 출력하기 위하여 시리얼 모니터 전송 속도를 설정하고 Trig 단자를 출력 모드(초음파( 방출), Echo 단자(HIGH 펄스를 잼)를 입력모드로 설정한다. 를 이용하여 소리의 이동 속도(mm/us)를 구하여 변수 sSpeed_mm_us에 저장한다.
3. 1)의 Read_mm_Dist() 함수를 반환형을 long형으로 설정하여 선언한다. 이 때 매개 변수(echoPin, trigPin, Temperature)는는 1)과 2)의 두 가지의 함수 모두 동일하게 사용하므로 전역 변수로 설정하였으므로 매개변수를 따로 지정하지 않았다. Read_mm_Dist() 함수는 pulseIn() 함수를 사용하여 Echo 단자가 HIGH 펄스를 유지하는 시간(us)을 반환받아 duration1에 저장한다. 이때 시간은 왕복 시간이므로 2로 나누어 소리의 이동 속도를 곱하여 거리(mm)를 구한 뒤 distance1에 저장한 후 이를 반환한다.
4. 2)의 자체 함수 MyPulseIn() 함수를 unsigned long형으로 선언한다. digitalRead() 함수를 사용하여 Echo 단자의 신호를 읽어 LOW이면 HIGH가 될 때까지 기다린 후 HIGH가 되면 그때의 시간을 micros() 함수를 이용하여 변수 s에 저장한다. 이후 Echo 단자가 LOW가 될 때까지 기다린 후 LOW가 되면 그 때의 시간을 변수 e에 저장한다. micros() 함수는 us시간을 반환한다. HIGH 펄스 시작 시간(s)과 종료 시간(e)을 이용하여 HIGH 펄스의 시간을 구한 뒤 t에 저장한 후 이를 반환한다. (t = e – s)
5. 2)의 Read_mm_Dist2() 함수를 반환형을 long형으로 설정하여 선언한다. 4.의 자체 함수 MyPulseIn()를 사용하여 Echo 단자가 HIGH 펄스를 유지하는 시간을 반환받아 duration2에 저장한다. 이때 시간은 왕복 시간이므로 2로 나누어 소리의 이동 속도를 곱하여 거리(mm)를 구한 뒤 distance2에 저장한 후 이를 반환한다.
6. void loop() 부분에서 digitalWrite() 함수를 이용하여 Trig 단자의 신호를 LOW로 만들어 오동작을 방지한 후 10us 지연시킨다. 이 후 신호를 HIGH로 만들어 HIGH 펄스를 만든 후 10us 지연시킨 후 신호를 LOW로 만들어 8개의 40KHz 펄스로 구성된 초음파를 방출한다. 초음파가 장애물에 반사되어 돌아오면 HIGH가 Echo 단자에 들어온다. 먼저 1)의 Read_mm_Dist() 함수를 사용하여 센서와 장애물 사이의 거리를 반환받아 long형 변수 dist1에 저장한다. 이후 다시 초음파를 발생시킨 후 2)의 Read_mm_Dist2() 함수를 사용하여 거리를 반환받아 dist2에 저장한다.
7. 두 개의 함수를 사용하여 측정한 거리 dist1과 dist2는 같은 거리에 있는 장애물과의 사이의 거리를 측정하였으므로 한 가지 변수 dist1만 사용하여 이가 최소 범위와 최대 범위 사이에 있을 경우 두 함수의 오차를 변수 avg_dist에 저장하고 cnt를 1 증가한다. 이 때 cnt는 10회 마다 결과를 출력하기 위해 횟수를 세는 변수로 cnt가 10이 되면 cnt를 0으로 초기화하여 다음 10회에 출력할 수 있게 한다. 장애물이 최소 범위와 최대 범위 사이에 고정되어 있으므로 이를 벗어난 거리에 있은 경우의 실행 코드는 작성하지 않았다.
8. cnt가 10인 경우(즉 거리를 10회 측정한 경우)
① 먼저 micros() 함수를 사용하여 현재 시간을 time 변수에 저장하고 이를 출력한 후 1초 후에 현재 시간과 직전 시간의 차이(micros()-time)를 변수 micros_time에 저장한다. 실제로는 1000000(us) 시간 차이가 나야 하지만micros() 함수로 측정시 오차를 계산하기 위하여 측정한 시간(micros_time)을(micros_time) 1000000(us)1000000(us)으로 뺀 값을 avg_micros에 더한다. 이를 10회 반복한 후 10으로 나누면 micros() 함수의 평균 오차(us)가 나온다.
실행결과 431.36, 442.74(us) 등이 나왔다.
② 다음으로 두 함수의 거리 측정 평균 오차를 구하기 위하여 avg_dist(두 함수의 거리 측정 오차)에 저장된 10회 실행한 후 오차들의 합을 10으로 나누어 평균 오차(mm)를 구한다. 실행 결과 1.6, 1.9(mm)등이 나왔다. 실제 거리는 100mm이다.
9. 두 함수의 거리 측정 평균 오차가 1.6mm가 나왔는데 이를 퍼센트(%)로 환산하면 1.6%이다. 또 1000000us 시간 차이가 발생하여야 하는데 micros() 함수를 사용하여 시간을 측정해보았을 때의 오차가 약 430~450us가 발생하였다. 이를 퍼센트(%)로 환산하면 0.04%이다. 두 함수의 거리 측정 오차가 micros() 함수의 오차보다 더 크다.
10. 초음파 센서의 Vcc 단자(보라색 선)를 아두이노 5V, Trig 단자(파란색 선)를 GPIO 8번, Echo 단자(초록색 선)를 GPIO 7번, GND(노란색 선)를 GND에 연결한다.
# 소스
#define ECHO_PIN 7 // Echo 단자
#define TRIG_PIN 8 // Trig 단자
#define TEMPERATURE 27 // 섭씨 온도
int maximumRange = 300; // 최대 범위
int minimumRange = 50; // 최소 범위
long duration1, duration2, distance1, distance2; // 왕복시간, 장애물 사이의 거리
double sSpeed_mm_us; // 소리의 이동 속도
unsigned long s, e, t, time; // 왕복 시간을 구하기 위해 사용되는 변수들
// 거리 측정 오차, 현재 시간과 직전 시간의 차이, micros() 함수 평균 오차
double avg_dist=0, avg_micros=0, micros_time=0;
int cnt=0; // 10회 단위인지 측정하기 위한 변수
void setup() {
Serial.begin(9600);
pinMode(TRIG_PIN, OUTPUT); // Trig 단자 OUTPUT모드로 설정
pinMode(ECHO_PIN, INPUT); // Echo 단자 INPUT모드로 설정
// 소리의 이동 속도 [mm/us]
sSpeed_mm_us = (331.5 + 0.6*TEMPERATURE) * pow(10, 3) / pow(10, 6);
}
long Read_mm_Dist(){ // pulseIn() 함수를 사용하여 거리를 구하는 함수
// 초음파가 발사된 후 반사되어 돌아오는 왕복시간(us)을 반환
duration1 = pulseIn(ECHO_PIN, HIGH);
distance1 = duration1/2 * sSpeed_mm_us; // 초음파 센서와 장애물 사이의 거리 구함
return (distance1); // 거리 반환
}
unsigned long MyPulseIn(){ // pulseIn() 함수와 동일한 동작하는 자체 함수
while(digitalRead(ECHO_PIN)==LOW); // Echo 단자가 HIGH가 될 때까지 기다림
s = micros(); // HIGH가 되면 그 떄의 시간을 s에 저장
while(digitalRead(ECHO_PIN)==HIGH); // Echo 단자가 LOW가 될 때까지 기다림
e = micros(); // LOW가 되면 그 떄의 시간을 s에 저장
t = e-s; // HIGH 펄스 시간 구함
return (t); // 시간 반환
}
long Read_mm_Dist2(){
duration2 = MyPulseIn(); // 초음파가 발사된 후 반사되어 돌아오는 왕복시간(us)을 반환
distance2 = duration2/2 * sSpeed_mm_us; // 초음파 센서와 장애물 사이의 거리 구함
return (distance2); // 거리 반환
}
void loop() {
digitalWrite(TRIG_PIN, LOW); // Trig 신호를 LOW로 만들어 오동작 방지
delayMicroseconds(10); // 10us 지연
digitalWrite(TRIG_PIN, HIGH); // 10us High Pulse 생성
delayMicroseconds(10); // 10us 지연
digitalWrite(TRIG_PIN, LOW); // 센서 모듈이 40KHz의 pulse 8개 출력
long dist1 = Read_mm_Dist(); // Read_mm_Dist 함수 사용하여 거리 측정
digitalWrite(TRIG_PIN, LOW); // Trig 신호를 LOW로 만들어 오동작 방지
delayMicroseconds(10); // 10us 지연
digitalWrite(TRIG_PIN, HIGH); // 10us High 펄스 생성
delayMicroseconds(10); // 10us 지연
digitalWrite(TRIG_PIN, LOW); // 센서 모듈이 40KHz의 펄스 8개 출력
long dist2 = Read_mm_Dist2(); // Read_mm_Dist2 함수 사용하여 거리 측정
if (dist1 >= minimumRange || dist1 <= maximumRange) {
// 거리가 최소~최대 범위인 경우
avg_dist += abs(dist1 - dist2); // 두 함수의 오차 더함
cnt+=1;
}
if(cnt==10){ // 10회 단위로 오차를 시리얼 모니터에 출력
for(int i=0; i<10; i++){
time = micros(); // micros() 함수 이용하여 현재 시간 저장
Serial.println(time); // 현재 시간 시리얼 모니터에 출력
delay(1000); // 1초 동안 지연
// micros()함수로 측정한 현재 시간과 직전 시간의 오차
micros_time = abs(micros()-time);
// 실제 시간 차이(1000000us) 와 micros()함수로 측정한 시간의 오차
avg_micros += (micros_time - 1000000);
}
avg_micros = avg_micros/10.0; // micros()함수의 오차 평균 구함
Serial.print("micros() 함수 평균 오차 : ");
Serial.println(avg_micros); // 시리얼 모니터에 출력
avg_dist = avg_dist/10; // 두 함수의 오차 평균 구함
Serial.print("두 함수의 거리 측정 오차 : ");
Serial.println(avg_dist); // 시리얼 모니터에 출력
cnt=0;
avg_dist=0;
}
}
# 실행 결과 (시리얼 모니터 화면)
- 장애물 사이의 거리가 100mm인 경우
10회 단위마다 현재 시간을 출력하고 micros() 함수 평균 오차(us)와 두 함수의 거리 측정 오차(mm)를 출력하였다.
'전공 공부 > 아두이노프로그래밍' 카테고리의 다른 글
MsTimer2 이용하여 지정한 주파수의 음정을 생성하는 myTone(pin, frequency)과 myNoTone() 함수를 제작 (0) | 2021.01.22 |
---|---|
analogWrite() 함수 이용하여 390Hz의 periodic interrupt를 발생시키는 프로그램 (0) | 2021.01.22 |
스피커를 이용한 연주 (0) | 2021.01.18 |
적외선 센서 (0) | 2021.01.18 |
장애물회피센서, 라인트레이서 (0) | 2021.01.18 |