[아두이노] 시각장애인을 위한 스마트 지팡이 원리 이해

IOT/아두이노|2019. 8. 14. 11:11

[아두이노] 시각장애인을 위한 스마트 지팡이 원리 이해



지난 시간에 진동모터에 대해 살펴보았습니다. 진동모터는 촉각을 느끼는 출력 부품입니다. 즉, 어떤 상황이 발생했을 때 그 상황에 대해 진동으로 인간에게 알릴 수 있습니다. 일상에서 진동모터는 어디에서 사용 할까요. 바로 스마트폰의 진동모드입니다. 스마트폰의 진동으로 전화나 문자가 왔을을 쉽게 알 수 있습니다. 또다른 응용사례가 뭐가 있을까요. 구글 검색을 통해 살펴보니 시각장애인을 위한 스마트 지팡이가 있더군요. 이 주제를 한번 가상시뮬레이터로 테스트 해보고 싶어지더군요. 참고로 제가 새로운 뭔가를 하루만에 창조하고 실험까지 하기는 시간적 여유가 없기 때문에 기존에 구현한 주제를 가지고 한번 가상시뮬레이터로 모방 실험을 통해 진동모터를 이해하는 시간을 갖고자 합니다.

1. 진동모터의 응용 사례 구글 검색



진동모터에 대한 응용 예제로 위 출처에 가시면 각 대학교 학생들이 만든 공모전 작품들에 대한 소개가 잘 나와 있습니다. 자세한 내용과 코딩은 읽지 않았습니다. 그 이유는 상상코딩에 방해가 되기 때문에 저만의 코딩을 할 수 없을 것 같아서 어떻게 스마트 지팡이를 구성했는지만 간단히 이미지를 참조하여 가상시뮬레이터에서 표현가능한 부품만을 이용하여 재구성해 보았습니다.

쉽게말해서, 이미지만 보고 한번 모방 표현을 해 보았는데 어떻게 했는지 본격적으로 살펴 볼까요. 참고로 스마트지팡이의 이미지는 출처에 가셔서 직접 보시기 바랍니다.

2. 스마트 지팡이 모방 재구성 이미지



  • 조도센서 : 보행 주변 조명 상태 확인
  • LED : 어두울 때 조명을 켜서 보행자을 알림등으로 활용
  • 초음파센서 : 3개의 초음파 센서로 벽감지 초음파센서는 전방에 벽을 확인하고 보행 초음파센서는 보행자의 보폭에 따른 장애- 물을 감지하고 바닥 초음파센서는 계단과 같은 하단의 장애물을 감지한다.
  • 진동모터 : 초음파센서를 통해 장애물이 감지되면 진동으로 장애물 감지를 알림

3. 스마트 지팡이 회로도


  • 준비물 : 초음파센서 3개, 조도센서 1개, 1k옴 2개, 220옴 1개, 진동모터 1개, 아두이노우노
  • 내용 : 진동모터는 3번핀, 초음파센서는 5,6,7번핀, LED은 13번핀, 조도센서 A0핀에 연결하시오.

구글 검색을 통해 재해석한 표현입니다. 실험에 사용한 주제는 원작은 위 링크 출처의 자료의 이미지를 모방한 실험으로 제작품은 아닙니다. 가상시뮬레이터에서 원리를 실험하는게 목적인 post 입니다.


상단 초음파센서는 벽(장애물) 감지이고 중앙 초음파센서는 보행(장애물) 감지이고 하단 초음파센서는 바닥(장애물) 감지합니다. 장애물이 감지되면 진동모터가 작동하여 진동으로 보행자에게 알린다. 조도센서는 스마트지팡이의 조명을 담당하면 주변이 어두울 때 지팡이에 조명이 켜지고 보행자을 식별할 수 있게 한다.

2. 코딩


설계 :

  • 조도센서를 통해서 LED 조명을 제어한다.
  • 3개의 초음파센서를 통해 3가지 장애물 진동 패턴을 다르게 한다.

먼저 조도센서를 통해 LED 조명을 제어해 볼까요.

조도센서를 읽기

int cds=analogRead(CDSPin);  

조도센서의 값이 100(임의값)미만이면 LED(조명)가 켜지고 100이상이면 LED(조명)가 꺼진다.

if(어두운지) 조명 켜기;
else 조명끄기;

위 if문을 코딩화 하면 다음과 같습니다.

if(cds<100) digitalWrite(LedPin,HIGH);   
else digitalWrite(LedPin,LOW);  

이제는 3개의 초음파센서를 통해 3가지 장애물 감지와 진동 패턴을 출력 해 볼까요.

가상시뮬레이터의 초음파센서는 3핀입니다. newPing 라이브러리를 이용하면 편한데 가상시뮬레이터에서 제공되지 않고 쓸려면 라이브러리 파일 안에 코딩을 전부 가상시뮬레이터로 복사해야 하기 때문에 수작업 코딩으로 실험했네요.

초음파 센서 읽기(사용자함수로 표현)

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;  
}

3개의 초음파센서이니깐 위 사용자정의함수로 표현하면 loop()함수 안에서는 다음과 같이 3줄로 초음파센서 값을 읽으면 됩니다.

float v1=UltrasonicDistance(5);
float v2=UltrasonicDistance(6);
float v3=UltrasonicDistance(7);

각 초음파센서의 값을 읽었으면 진동을 출력해야 겠죠. 출력하기 전에 출력한 진동 패턴은 다음과 같이 설정 해보았습니다.

  if(v3<20){
    if(state == false){ //처음 장애물 감지때만 진입
          하단 초음파 초기상태;
    }    
    timeState = 200;  //진동 간격
  }
  else if(v2<30){
    if(state == false){      
      중앙 초음파 초기상태;
    }
    timeState = 500; //진동 간격
  }                    
  else if(v1<50) {
    if(state == false){      
      상단 초음파 초기상태;
    }
    timeState = 1000; //진동간격
  }
  else { //장애물 감지 안되면 초기화 시킴
    state = false;  
    digitalWrite(VibrationPin,LOW); 
  } 

위에서 초기상태는 장애물 감지 된 후의 동작이니깐 state 출력 상태로 바꾸고 초기 진동상태값은 true로 하고 이전시간값을 진동 간격만큼 처음 빼줍니다. 그 이유는 처음에는 무조건 진동을 먼저 시작하고 반복되게 하기 위해서 입니다. 참고로, Setup()함수에서는 강제적으로 delay(1000)하면 음수에 대한 오류는 발생하지 않습니다.

    if(state == false){ //처음 장애물 감지때만 진입
      state = true; //진동 출력 상태
      VibrationState=true; //진동모터의 상태
      timeVal = millis()-200; //진동이전값(처음에 무조건 진동해야하기 때문 -200을 함)
    }    

위 내용을 합치면,

  if(v3<20){
    if(state == false){ //처음 장애물 감지때만 진입
      state = true; //진동 출력 상태
      VibrationState=true; //진동모터의 상태
      timeVal = millis()-200; //진동이전값
    }    
    timeState = 200;  //진동 간격
  }
  else if(v2<30){
    if(state == false){      
      state = true;   
      VibrationState=true;
      timeVal = millis()-500;
    }
    timeState = 500;
  }                    
  else if(v1<50) {
    if(state == false){      
      state = true;   
      VibrationState=true;
      timeVal = millis()-1000;
    }
    timeState = 1000;    
  }
  else { 
    state = false;  
    digitalWrite(VibrationPin,LOW); 
  } 

이제 출력 상태를 지정을 했으니 출력을 해볼까요.

  if(state == true){ //출력 상태 확인
    if(millis()-timeVal>=timeState){ //출력 간격 체크
      digitalWrite(VibrationPin,VibrationState); //진동 출력
      VibrationState=!VibrationState; //진동출력상태 반전
      timeVal=millis(); //이전시간값
    }   
  } 

위와 같이 코딩함으로 진동을 울린건지 state값을 통해서 진동을 울리게 됩니다. 진동 울리는 간격은 millis()함수를 이용하여 딜레이함수 없이 딜레이 효과를 주었습니다. 왜! 이 원리를 이용했냐면 스마트지팡이에는 진동모터만 있는게 아닙니다. 다른 부품들도 실시간으로 동작을 처리해야 합니다. 그렇기 때문에 millis()함수를 이용하여 delay()효과를 주었네요. 이렇게 표현하면 조도센서에 대한 LED(조명) 변화는 동시에 처리할 수 있습니다.

종합해보면,

int timeState = 0;
boolean state = false;
boolean VibrationState = true;
unsigned long timeVal = 0;


const byte LedPin = 13;
const byte VibrationPin = 3;
const byte CDSPin = A0;

void setup(){
  
  //Serial.begin(9600);  
  pinMode(LedPin,OUTPUT);
  pinMode(VibrationPin,OUTPUT);  
  
  delay(1000);
}
void loop(){
  int cds=analogRead(CDSPin);  
  
  if(cds<100) digitalWrite(LedPin,HIGH);   
  else digitalWrite(LedPin,LOW);  
  
  
  float v1=UltrasonicDistance(5);
  float v2=UltrasonicDistance(6);
  float v3=UltrasonicDistance(7);
  
  
  if(v3<20){
    if(state == false){      
      state = true;
      VibrationState=true;
      timeVal = millis()-200;
    }    
    timeState = 200;  
  }
  else if(v2<30){
    if(state == false){      
      state = true;   
      VibrationState=true;
      timeVal = millis()-500;
    }
    timeState = 500;
  }                    
  else if(v1<50) {
    if(state == false){      
      state = true;   
      VibrationState=true;
      timeVal = millis()-1000;
    }
    timeState = 1000;    
  }
  else { 
    state = false;  
    digitalWrite(VibrationPin,LOW); 
  } 
  
  if(state == true){
    if(millis()-timeVal>=timeState){
      digitalWrite(VibrationPin,VibrationState);      
      VibrationState=!VibrationState;
      timeVal=millis();
    }   
  } 
 }
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;  
}

4. 결과


아래 결과 영상만 보면 좀 이해가 안 될 수 있습니다. 위에 지팡이 이미지를 보고시고 사용된 부품의 위치와 가상시뮬레이터의 부품과 일치시켜서 어느정도 상상을 하면서 보셔야 이해가 될 듯 싶네요.


5. 문제점



문제점은 위 그림에서 보는 것 처럼 보행을 할 때 세부분으로 나눠서 3꼭지점을 지면 바닥에 닿고 나머지 부분은 h(높이)로 반원의 곡선을 그리면서 지팡이를 움직이게 됩니다. 지면에는 딱 세번의 위치를 찍을 뿐 지팡이는 대부분 공중에 떠있게 됩니다. 그래서 지면과의 거리를 측정하는 센서가 추가하여 지면에서 얼마만큼 높이이고 장애물과의 거리가 정확히 위치를 잡아야 하는데 이 부분은 가상시뮬레이터에서 생략했습니다. 그래서 실제 구현한다면 스마트 지팡이의 곡선 움직으로 인한 장애물 측정의 약간 문제가 생길 수 있습니다. 즉, 위 코딩대로 라면 하단 초음파 센서가 곡선을 그릴 때 중간 장애물을 하닥 근접 장애물로 인식한 진동음으로 울릴 수 있으며 지팡이가 포물선으로 움직이기 때문에 각도의 변화가 일어나기 때문에 그 각도에 대한 계산 부분이 코딩에 담겨져 있지 않습니다. 그래서 정확한 측정은 좀 더 코딩을 수학적 계산 부분이 필요합니다. 위 코딩은 단순한 가상시뮬레이터에서의 스마트 지팡이의 단순 원리를 테스트 하기 위한 내용이니 실제 구현시에는 여러가지를 고려하야 정확한 장애물 위치에 대한 진동을 만드셔야 합니다.

원래는 초음파센서로만 스마트지팡이를 구성하고 장애물을 감지하는데에는 한계가 있습니다. 사실 초음파센서보다는 진짜 제대로 된 스마트 지팡이를 구현한다면 차라리 영상처리를 이용한 장애물 감지 기술을 공부하여 구현해보는 것이 좋습니다. 자율주행차에 대해 요즘 관심이 많고 대학들이 그와 관련된 연구를 하는 곳들이 많습니다. 이런 연구하는 대학에서 영상처리를 공부하는 학생들이 자율주행차보다 자율보행지팡이 쪽으로 연구가 이루어진다면 진짜 제대로 된 스마트 지팡이가 만들어 질거라 생각됩니다.

주변사물을 영상인식으로 통해 그 정보를 소리와 진동으로 알려준다면 제대로 된 보행을 할 수 있을 거라 생각됩니다. 자율주행차와 같은 원리를 자율보행안내 지팡이 연구를 한다면 그 기술은 자율주행차에도 응용 가능하기 때문에 연구의 가치가 있습니다.

마무리


오늘은 진동모터의 응용 사례를 구글 검색으로 통해서 장애인을 위한 스마트 지팡이이라는 아이템을 찾아 가상시뮬레이터에서 간단히 테스트를 해보았습니다. 이미지를 보고 바로 코딩을 하다보니깐 코딩이 별로 마음에 안들고 좀 길어서 보기 안좋습니다. 이미지를 응용하고 코딩을 만드는데 2시간정도 시간이 걸렸네요. 저녁에 실험하다보니 이번 post를 좀 연기할 까 했는데 그래도 완성은 시켰네요. 완성해놓고 보면 별거 없는데 몇가지 상상했던 코딩들 중에 하나를 선택해서 제가 의도한 방향으로 코딩을 하다보니 좀 시간이 길어져 버렸습니다. 하루만에 완성하려고 하니 볼품없는 post가 되었네요. 실제 제작을 해도 원하는 결과는 좀 얻기 힘들거라 생각됩니다. 대충 어떤 의미로 동작하는지 그 의미만 가상시뮬레이터로 실험한 post라고 이해 하셨으면 합니다.

다른 응용사례를 찾지 못했는데 혹시 찾으신다면 여러분들도 저처럼 이렇게 모방 실험을 한번 해보세요. 모방이라도 코딩을 보지 않고 이미지만 보고 응용하여 의미를 이해하고 자신의 상상으로 재해석해서 회로도를 만들어 보세요. 그리고 재해석된 회로도의 표현들을 자신의 상상력을 동원하여 코딩해 보세요. 위 코딩은 초벌 코딩으로 간단히 원리를 실험한 코딩이지만 위 코딩에서 좀 더 개선하면 좋은 코딩이 될거라 생각됩니다. 여러분들은 위 코딩을 그대로 하지 말고 원리만 이해하시고 여러분들 스스로가 여러분만의 코딩으로 재해석하여 코딩을 만들어 보셨으면 합니다.


댓글()

[아두이노] 진동센서(Vibration Sensor) 제어

IOT/아두이노|2019. 8. 13. 09:00

[아두이노] 진동센서(Vibration Sensor) 제어



지난시간에 다룬 진동모터는 진동을 외부로 출력하는 부품인데 반대로 진동을 감지하여 내부로 입력을 받는 진동센서 부품이 있습니다. 진동에 대한 전기 신호를 만들어 내는데 디지털 신호와 아날로그 신호로 만들어 냅니다. 아무튼 진동을 감지 할수 있는 이 센서는 참 재밌는 부품입니다. 만약에 이 진동센서를 특정위치에 부착하면 그 대상물에 진동이 발생했을 때 진동센서로 진동을 감지하여 전기 신호로 만들어 낼 수 있습니다. 가령 대상물에 누가 건들거나 또는 대상물 주변에 진동이 발생하는 상황에서 아두이노에서 그에 대한 특정한 명령을 내릴 수 있습니다. 즉, 진동 감지 원리를 이용하여 도난방지나 침입 방지를 위한 경보기와 같은 곳에서 응용할 수 있습니다. 예를 들면은 차량에 누가 터지하거나 충격을 주게 되면 차량에서 경보음이이 울리는 것으 많이 보셨을 꺼에요. 그런 것들을 연상하시면 될 듯 싶네요.

이제 진동센서를 알아봅시다.

1. 진동센서(Vibration Sensor)


진동센서는 진동을 감지하는 센서로 진동에 대해 디지털 신호 or 아날로그 신호를 만들어 냅니다. 진동센서는 3핀으로 VCC, GND, D0핀으로 구성된 모듈이 있는가 하면 아래 그림처럼 VCC, GND, D0, A0핀으로 구성된 모듈이 있습니다. 아래 그림을 보시면 진동에 대한 값을 십자모양의 가변저항으로 조절 할 수 있습니다.


진동센서는 2가지 형태로 출력 신호를 만들어 냅니다. 첫번째로 디지털 출력으로 0 or 1의 값을 만들어 내는데 진동센서에 대해 조사하니 초기상태값이 HIGH 상태이고 진동이 발생하면 LOW 상태가 된다고 나와 있습니다. 즉, 진동이 발생하면 진동센서는 LOW가 되고 아두이노우노에서 진동(LOW)에 대한 처리 동작을 설계하면 됩니다. 두가지 상태만 존재하기 때문에 스위치 역할을 수행하는 주제에 알맞습니다. 두번째로 아날로그 출력으로 0~1023의 값을 만들어 내겠죠. 디지털 출력는 진동에 대한 두가지 상태만 존재하기 때문이 때문에 두가지 상황만 만들어 낼 수 있지만 아날로그 출력은 진동의 강도값으로 진동의 신호를 만들어 내기 때문에 이 신호의 범위값을 나누면 여러 상황을 만들어 낼 수 있고 처리동작도 여러개의 형태로 처리동작을 만들어 낼 수 있습니다. 두가지 방식 중 여러분들이 설계하는 목적에 맞게 디지털로 읽을지 아날로그를 읽을지만 잘 정하고 알맞게 사용하시면 도비니다.

진동센서의 값을 읽는 방법은 다음과 같습니다.

  • 디지털 입력 : digitalRead(D0)
  • 아날로그 입력 : analogRead(A0)

위 함수를 통해서 읽은 값에 대한 처리 동작만 간단히 코딩하면 되기 때문에 진동센서는 어려운 부품이 아닙니다.

2. 진동센서 회로도


준비물 : 진동센서, LED 1개, 저항 220옴 1개, 아두이노우노
내용 : 진동센서의 D0핀을 7번에 연결하고 LED 핀은 12번에 연결하시오.



위 그림은 진동의 상태를 LED로 출력하기 위한 회로도 입니다.

3. 코딩


설계 : 진동이 발생하면 LED에 불이 들어오게 한다.

if(진동감지) LED 켜기;
else LED 끄기;

딱 두줄이면 됩니다. 실험에서는 디지털 입력을 받기 때문에 아래와 같습니다.

if(digitalRead(디지털핀)==LOW) digitalWrite(LED핀, HIGH);
else digitalWrite(LED핀, LOW);

종합해 보면,

const byte StatePin = 12;
const byte VibrationPin = 7;

void setup(){
 pinMode(StatePin, OUTPUT);
 pinMode(VibrationPin, INPUT); 
}

void loop(){
 if(digitalRead(VibrationPin)==LOW) digitalWrite(state, HIGH);
 else digitalWrite(state, LOW);
}

진동감지에 대한 간단히 코딩입니다. 실제 부품이 없어서 결과는 알 수 없지만 유사한 실험을 한다면 기울기센서로 대신 가상시뮬레이터에서 실험하시면 됩니다.



기울기 센서에서 기울기가 발생하면 LED에 불이 들어오는 실험이 있으닊나 진동센서를 기울기 센서로 감안하여 대신 실험을 할 수 있습니다.

4. 경보기 응용


진동센서와 피에조부저 같은 사운드 출력 센서를 이용하면 진동이 발생하면 소리로 결과를 출력 할 수 있습니다. 경보장치로 활용하면 좋습니다. 보안이 필요한 대상에 대해서 진동이 발생하면 경보음이 울리게 설정 할 수 있습니다.

1) 진동센서 경보기 회로도


준비물 : 진동센서, LED 1개, 저항 220옴 1개, 아두이노우노
내용 : 진동센서의 D0핀을 7번에 연결하고 LED 핀은 12번에 연결하시오.



피에조부저만 6번에 추가로 연결하시면 됩니다.

2) 코딩


위 진동센서 회로도에서 피에조부저만 추가로 부착되었기 때문에 소리에 대한 부분만 표현하시면 됩니다.

  • 피에조부저 : tone(핀번호, 주파수, 출력시간), noTone(핀번호), delay(시간값)

간단히 한음의 소리를 울리게 표현을 하면 아래와 같습니다.

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

이 코딩을 어디에 넣어야 할까요? 바로 진동이 발생하는 시점에 경보음이 울리게 하면 됩니다.

종합해보면,

const byte StatePin = 12;
const byte VibrationPin = 7;
const byte SoundPin = 6;

void setup(){
 pinMode(StatePin, OUTPUT);
 pinMode(VibrationPin, INPUT); 
}

void loop(){
 if(digitalRead(VibrationPin)==LOW) {
   digitalWrite(state, HIGH);
   tone(SoundPin,523,1000/8);     // 도음으로 8분음표(음길이)
   delay(1000/4*1.30);             
   noTone(SoundPin);         
 }
 else digitalWrite(state, LOW);
}

유사한 예제로는 아래 거리경보장치 실험을 참조하시면 됩니다. 초음파센서로 거리값으로 경보음이 울리는 예제인데 여기서 진동센서의 역할을 초음파센서가 대신한 걸로 상상하시면 됩니다.



마무리


진동센서에 대해서 간단히 살펴보고 응용 예제로 진동센서로 경보장치를 상상해 보았습니다. 이것 말고도 다양한 것을 상상 할 수 있습니다. 위에서는 디지털 입력을 다뤘지만 진동에 대한 아날로그 입력을 받을 수 있다면 진동의 강도에 따라서 다양한 명령을 내릴 수 있습니다. 디지털 입력의 경우는 진동 하냐/안하냐 두가지 상태지만 아날로그는 진동의 범위에 따라 내리는 명령을 다양하게 내릴 수 있어 진동의 강도에 따른 섬세한 제어가 가능하다는 걸 알아 두세요.

아두이노는 재밌는 부품이 많습니다. 진동을 발생하는 진동모터가 있는가 하면 진동을 감지하는 진동센서가 있습니다. 여러분들도 특정 부품에 대해 조사하고 실험을 할 때 어떤 A동작을 수행하는 부품이 있다면 반대의 B동작의 부품이 없는지 같이 찾아서 공부하시면 아두이노 공부에 많은 도움이 됩니다. 공부하실 때 같은 동작을 하는 부품을 찾거나 반대 동작하는 부품을 같이 찾아서 공부를 꼭 해주세요. 못찾으면 어쩔 수 없지만 찾으시면 따블로 공부 효과를 얻을 수 있기 때문에 꼭 제가 말한 방식으로 아두이노를 공부해 주세요. 그래야 나중에 뭔가를 표현하고 싶을 때 도움이 많이 됩니다.

댓글()