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

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 Motor) 제어

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

[아두이노] 진동모터(Vibration Motor) 제어



오늘은 가상시뮬레이터에 제공되는 부품 중 한가지 진동모터 부분을 빼먹은 것 같아서 진동모터에 대해서 이야기를 하고자 합니다. 진동모터는 모터에서 진동을 일으키는 모터입니다. DC모터는 모터가 회전하는 반면에 진동모터는 회전이 아닌 진동입니다. 제어하는 방식은 DC모터와 동일하며 전류가 공급되면 진동이 발생하고 전류의 세기에 따라서 진동의 세기가 달라집니다. 따로 알아야 할 부분은 없으면 가볍게 진동모터에 대해서 이야기 하고자 합니다.

1. 진동모터(Vibration Motor)


진동모터는 모터의 진동을 발생하는 부품입니다. 진동을 발생은 인간에게 촉감으로 느끼게 하는는 부품이라고 할 수 있습니다. 대표적인 예로 스마트폰은 전화나 문자가 올 때 사운드(음악소리)로 기본적으로 알립니다. 여기서 진동모드로 바꾸면 사운드가 아닌 스마트폰의 진동으로 전화나 문자가 온 걸 알려주게 됩니다. 이처럼 소리가 아닌 진동으로 인간에게 특정한 상황을 알릴 수 있습니다. 즉, 진동응 인간이 촉감으로 느낄 수 있는 출력부품으로 어떤 상황을 진동으로 감지할 수 있게 하는 출력부품이라고 생각하시면 됩니다.

그리고 진동모터는 상상하실 때 이렇게 생각하시면 됩니다. LED, 스피커 등과 같은 다양한 출력 부품들의 표현들을 진동모터로 대신하여 표현 할 수 있기 때문에 진동모터로 순순하게 상상하실 필요 없이 기존의 다양한 출력 부품들을 진동모터로 대체하고 응용상상을 하시면 됩니다.

가상시뮬레이터에서 제공되는 진동모터는 5V 입니다. 일반적인 DC모터를 제어하던 방식과 비슷합니다.


실제 실험에 사용하는 진동모터는 소형진동모터로 모터의 종류에 따라서 필요 전압이 다릅니다. 아두이노우노는 3.3V와 5V를 공급해줍니다. 아두이노우노 핀에서 출력 전압이 5V인데 만약 3V대 진동모터라면 아래와 같이 저항을 붙여 줘야 겠지요.


여러분들이 구매하신 진동모터가 몇V인지를 꼭 확인하시고 회로도를 구성하시면 됩니다.

참고로 아두이노우노는 PWM 핀은 아날로그 출력을 0~255(0~5V)을 출력 제어할 수 있습니다. 즉, 아날로그 출력값에 따라서 진동의 세기를 조절 할 수 있습니다. 위 두개의 의 그림을 보시면 5V일 때 진동모터는 진동 이미지로 3개의 띠를 보여주지만 저항이 붙은 진동모터는 2개의 띠가 희미하게 보이실 꺼에요. 이처럼 V값에 따라서 진동의 세기가 달라집니다.

진동모터를 구매하실 때 진동모터 사양을 꼭 확인하시기 바랍니다. 소형진동모터는 대개 약3V정도 인 것 같더군요.


참고로 가상시뮬레이터에 있는 위 그림 형태의 진동모터를 제공합니다. 이것을 가지고 회로도를 구성한다면 아래와 같겠죠.


void setup(){
  pinMode(3, OUTPUT);
}
void loop(){
  analogWrite(3, 255); //진동세기 임의의 값
  delay(1000);
  analogWrite(3, 0);
  delay(1000);
}

이렇게 가상시뮬레이터에서 돌리면 전압이 너무 낮아서 진동하지 않네요. 뭔가 잘못된 건가 하고 실제 구현하신분들의 영상을 보면 정상적으로 동작하더군요. 가상시뮬레이터에서는 진동모터가 5V라서 아두이노 핀에서 출력되는 전압이 낮고 해서 진동이 발생하지 않았습니다. 잘못되었다기 보다는 진동 전압이 낮기 때문에 진동을 가상시뮬레이터에서 발생시키지 못하더군요. 저항을 제거하고 실험하셔도 전압이 낮더군요. 디지털핀에서 제공되는 전압에서는 모터가 가상시뮬레이터에서 반응이 없습니다. 아래 3.3V와 5V에서는 진동이 전상적으로 발생하지만 디지털 핀에서의 전원공급에는 좀 문제가 있습니다. 사실 디지털핀으로 전원을 공급한다는 설계 자체가 좀 문제가 있습니다. 진동모터도 모터의 일정인데 디지털핀에서 모터의 전원을 공급한다는 설정은 좀 그렇죠. 아무리 낮은 전압이라도 모터는 모터이기 때문에 될 수 있으면 디지털 핀같은 곳에서 모터의 전원을 공급하는 설정은 추천하지 않습니다. 제가 post에서 실험한 내용은 단지 예를 든 실험입니다.

아무튼 아래 그림처럼 가상시뮬레이터에서 이렇게 결과가 나오네요.


전압이 낮은 진동모터였다면 동작을 했겠죠. 위 그림처럼 실험 할 시에 저항은 진동모터 전압에 맞는 저항을 붙여줘야 합니다. 최대 진동을 기본으로 맞추고

analogWrite(3, 255); //진동세기 임의의 값

이렇게 255가 되었을 때 최대 진동이고 0~255사이의 값을 줌으로서 진동의 세기를 조절 할 수 있게 됩니다. 최소 전압도 필요하기 때문에 너무 낮은 값으로 출력하면 진동모터가 동작 안할 수 있습니다. 가상 시뮬레이터는 전압이 5V 진동모터라 아두이노에서 출력되는 전압이 약4.7V에다가 저항에 따라서 1.92V정도 나왔네요. 그래서 진동을 가상시뮬에터에서 발생하지 않지만 실제는 다릅니다.

참고로, 저항없이 바로 PWM(3번)핀에 연결하시면 됩니다. 그럴 경우는

analogWrite(3, 100); //진동세기 임의의 값

진동 세기값으로 실험하는 진동모터의 최대값 수치가 예를 들어 100이라고 가정하면 100이상만 안넘기게만 하면 됩니다. 위 진동모터는 고려해야 부분이 몇가지 있네요.

아래 사진처럼 모듈형태의 진동모터도 제공되고 고려할 부분은 모듈 전압만 확인 하시면 됩니다. 회로도 연결은 간단합니다.

그림 출처 : https://www.aliexpress.com

모듈형태의 진동모터는 제어가 훨씬 편합니다. SIG, VCC, GND 핀으로 구성되어 있고 SIG핀은 아두이노 PWM핀에 연결하여 값만 넣으시면 됩니다.

예) SIG (3번핀) 연결 되었을 경우


void setup(){
  pinMode(3, OUTPUT);
}
void loop(){
  analogWrite(3, 200); //진동세기 임의의 값
  delay(1000);
  analogWrite(3, 0);
  delay(1000);
}

대충 이런식으로 제어를 할 수 있겠죠.

이제는 가상시뮬레이터에서 동작하게끔 변형 시켜서 실험을 해보도록 하겠습니다.

2. 진동모터 회로도


준비물 : NPN트렌지스터, 저항 1k옴 1개, 진동모터 1개, 아두이노우노
내용 : 3번핀을 진동모터 핀으로 이용해 봤네요.



위 그림에서 다이오드와 캐피시터를 달아야 하는데 생략 했네요.

실제는 아래 그림처럼 해도 동작할 꺼에요.


위 처럼 가상시뮬레이터에서 실험하면 움직이지 않습니다. 문제가 있는가 하고 인터넷 실험 영상을 찾아보니깐 동작에는 문제가 없어 보이더군요. 전류를 살펴보니 너무 낮은 전압이라서 동작을 안한 것이더군요. 아무튼 실제로 하실 때는 .트렌지스터 사용하지 않고 간단히 표현하셔도 아마 될 듯 싶네요.

3. 코딩


PWM핀을 이용하는데 analogWirte()함수를 이용하셔도 되지만 그냥 기본 digitalWrite()함수를 이용하셔도 됩니다. 가상시뮬레이터에서는 digitalWrite()함수를 이용했습니다.

void setup()
{  
  pinMode(3, OUTPUT);
}

void loop()
{
  digitalWrite(3, HIGH);
  delay(1000); 
  digitalWrite(3, LOW);
  delay(1000); 
}

4. 결과



위 회로도를 보시면 어디서 많이 본 듯한 회로도이지 않나요. 예전에 DC Motor에서 다뤘던 회로도 입니다.



참고 post의 회로도에 약간 다른 방식으로 디자인 해 봤네요. DC MOTOR편을 보시고 참고하셔서 회로도를 디자인을 하셔도 됩니다.

마무리


위에서 표현한 방식으로 표현하실 필요는 없습니다. 실제로 실험 하실 때는 진동모터의 사양을 보시고 필요 전압이 몇인지에 따라서 아두이노에 직접 연결하실 때 저항을 붙여서 연결하시든지 아니면 그냥 연결하시고 나서 PWM핀에 analogWirte()함수를 이용하여 진동 모터의 세기 전압만 맞추셔도 됩니다.

간단한 진동모터를 좀 복잡하게 설명한 것 같네요. 아무튼 진동모터로 할 수 있는 것들이 뭐가 있는지 한번 여러분들이 찾아보시고 뭘 할 수 있을지 상상해 보세요.

댓글()