화요일

[아두이노] 종이컵 분류기

오늘은 지난 시간에 사용한 라인트레이서를 개조해서 종이컵 분류기를 만들어보겠습니다.

준비물은 다음과 같습니다.

1. 지난 시간에 사용한 라인트레이서

2. 초음파 센서 하나 더


종이컵 분류기가 작동하는 방법은 다음과 같습니다.


  • 하얀색 바탕, 검은색 테두리의 직사각형 내에서 움직임
  • 키가 큰 종이컵을 쳐내고, 키가 작은 종이컵을 회피함
  • 혹은 키가 큰 종이컵을 회피하고, 키가 작은 종이컵을 쳐냄
약간의 개조와 코드 수정을 통해 종이컵 분류기를 구현할 수 있습니다.

먼저 초음파 센서를 키가 큰 종이컵 높이에 맞춰 달아줍니다.

그리고 코드를 수정합니다. (끝)

아래는 수정된 코드입니다.

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
#include <Servo.h>

#define SPEED_GO 50   // 직진 속도
#define SPEED_TN 160   // 회전 속도
#define M1  1         // 좌측모터
#define M2  2         // 우측모터
#define SensorLeft    5 // 디지털 3: 좌측센서
#define SensorRight 6 // 디지+털 5: 우측센서
#define TRIG_H    8 // 위쪽 초음파센서
#define ECHO_H  11   
#define TRIG_L  12  // 아래쪽 초음파센서
#define ECHO_L  13

int SL = 0;           // 좌측센서 상태
int SR = 0;           // 우측센서 상태

int deg = 140;   
int a   = 15;       
int DIS = 0;         // 하단
int DIS2 = 0;        // 상단

Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *myMotor1 = AFMS.getMotor(M1);
Adafruit_DCMotor *myMotor2 = AFMS.getMotor(M2);
Servo servo;

void setup() {
  Serial.begin(9600);
  Serial.println("::: Let's Go Line Tracer!! :::");

  pinMode(SensorLeft, OUTPUT);
  pinMode(SensorRight, OUTPUT);
  pinMode(TRIG_H, OUTPUT);
  pinMode(ECHO_H, INPUT);
  pinMode(TRIG_L, OUTPUT);
  pinMode(ECHO_L, INPUT);

  AFMS.begin();
  servo.attach(10);
}

void go_forward(){ // 직진
  myMotor1->setSpeed(SPEED_GO); //50
  myMotor2->setSpeed(SPEED_GO);
  myMotor1->run(FORWARD);
  myMotor2->run(FORWARD);
  Serial.println("go forward");
}

void go_backward(){ // 후진
  myMotor1->setSpeed(100); //50
  myMotor2->setSpeed(100);
  myMotor1->run(BACKWARD);
  myMotor2->run(BACKWARD);
  Serial.println("go backward");
}

void turn_left(){ // 제자리 좌회전
  myMotor1->setSpeed(SPEED_TN);
  myMotor2->setSpeed(SPEED_TN);
  myMotor1->run(BACKWARD);
  myMotor2->run(FORWARD);
  Serial.println("turn left");
}

void turn_left2(){
  myMotor1->setSpeed(30);
  myMotor2->setSpeed(30);
  myMotor1->run(BACKWARD);
  myMotor2->run(FORWARD);
  Serial.println("turn left2");
]

void turn_right(){ // 제자리 우회전
  myMotor1->setSpeed(SPEED_TN);
  myMotor2->setSpeed(SPEED_TN);                                                                                                                                                                                                                                                                                                                                                                                                                                     
  myMotor1->run(FORWARD);
  myMotor2->run(BACKWARD);
  Serial.println("turn right");
}

void turn_right2(){
  myMotor1->setSpeed(30);// 75
  myMotor2->setSpeed(30);
  myMotor1->run(FORWARD);
  myMotor2->run(BACKWARD);
  Serial.println("turn right2");
]

void brake(){ // 정지
  myMotor1->run(RELEASE);
  myMotor2->run(RELEASE);

  Serial.println("brake");
}

void detect_left(){ // 좌측센서 감지여부
  int a, b, c;

  digitalWrite(SensorLeft, HIGH); // 신호+노이즈
  delayMicroseconds(400);
  a = analogRead(A3);

  digitalWrite(SensorLeft, LOW); // 노이즈
  delayMicroseconds(400);
  b = analogRead(A3);

  c = a - b;

  if(c >= -600)
    SL = 1;
  else
    SL = 0;
}

void detect_right(){ // 우측센서 감지여부
  int a, b, c;

  digitalWrite(SensorRight, HIGH); // 신호+노이즈
  delayMicroseconds(400);
  a = analogRead(A5);

  digitalWrite(SensorRight, LOW); // 노이즈
  delayMicroseconds(400);
  b = analogRead(A5);

  c = a - b;

  if(c >=0)
    SR = 1;
  else
    SR = 0;
}

void detect_sonic_L(){ // 하단 초음파센서 감지여부
  servo.write(deg);
  deg = deg - a;
  if(deg <= 40 || deg >= 140){
    a*=-1;
  }
  delay(25);
  make_dist();
  detect_sonic_H(); // 상단에서 걸리는 것이 없냐? 토스
}

void detect_sonic_H(){ // 상단 초음파센서 감지여부
  unsigned long distance;
  digitalWrite(TRIG_H,HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_H,LOW);
  distance = pulseIn(ECHO_H,HIGH)/58.2;
  DIS2 = distance;
}

unsigned long make_dist(){
  unsigned long distance;
  digitalWrite(TRIG_L,HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_L,LOW);
  distance = pulseIn(ECHO_L,HIGH)/58.2;
  DIS = distance;
  return distance;
}

void loop() {
  detect_left();
  detect_right();
  detect_sonic_L();
  response();
}

void response(){
  if (SL == 0 && SR == 0){ // 사각형 내에서
    if (DIS <= 20){ // 낮은 위치 감지
      if (DIS2 <= 10){ // 높은 위치 감지
         if (deg < 85){ // 오른쪽에 장애물 위치
go_backward();
        delay(100);
        turn_left2();
        delay(100);
        go_forward();
        delay(100);
        turn_left();
         }
         else if (deg > 95){ // 왼쪽에 장애물 위치
        go_backward();
        delay(100);
        turn_right2();
        delay(100);
        go_forward();
        delay(100);
        turn_right();
         }
         else if (deg >= 85 && deg <= 95)
        brake();
         }
         else{
go_forward();
         }
      }

      else
         go_forward();
    }

  else if (SL == 1 && SR == 0){ // 사각형에서 이탈
    if (DIS <= 20){
      if (deg < 85)
        turn_left();
      else if (deg > 95)
        turn_right();
      else if (deg >= 85 && deg <= 95)
        brake();
    }
    else
      turn_right();
  }

  else if (SL == 0 && SR == 1){ // 사각형에서 이탈
    if (DIS <= 20){
      if (deg < 85)
        turn_left();
      else if (deg > 95)
        turn_right();
      else if (deg >= 85 && deg <= 95)
        brake();     
    }
    else
      turn_left();
  }

  else{
    go_backward();
    delay(1000);
    turn_left2(); // 동시에 감지되면 뒤로 물러나서 왼쪽으로 턴
   }
}


사실, 구동이나 감지 부분은 이미 만들어 놓았기에 경우의 수를 조금 추가하면 됩니다.

어쨌든 최종적으로 저의 아두이노 로봇(?)은 이런 모양입니다.









무게 중심을 맞추기 위해서 배터리를 가운데에 놓고 보드를 뒤쪽으로,

센서와 포크는 앞쪽으로 놓았는데도 약간씩 헛돌더군요;;

이 부분은 조금 수정해야할 것 같습니다.

이외에도 수정할 부분이 많지만 일단은 여기까지 쓰겠습니다...

[라즈베리파이] 시작하기에 앞서...

새로운 지령이 떨어졌습니다.

색과 모양이 다른 물체를 구별해내야 합니다.

이미지를 처리하게 되면 그에 맞는 고성능(?)의 프로세서가 필요합니다.

라즈베리파이를 사용해보기로 하였습니다. 그래서 이리저리 알아보는데...

일단 HDMI 단자가 있는 모니터가 없어서 랜선으로 연결을 시도해보았습니다...

연결하는데에도 시간을 좀 잡아먹었습니다...

랜선으로 연결하고 고정아이피를 잡아서 VNC뷰어로 화면에 출력하는 방법을 사용했습니다.

아래 그림은 카메라를 사용한 예시입니다.



다음으로 사물인식을 돌려보았는데... tiny-YOLO만 그나마 시간이 적게 걸리더군요...

https://pjreddie.com/darknet/



다크넷 사이트에 나온 것처럼 하려면 힘들지 않을까요(?)...

아래 동영상도 참조했습니다만...



OpenCV에 대한 공부가 조금 필요할 것 같습니다.

그리고 보드 자체에 쿨러가 따로 없어서 조금만 시간이 지나도 엄청난 열을 뿜어냅니다.

쿨러와 케이스를 사야할 것 같습니다.

어쨌든 좀 더 공부해서 포스팅을 시작하겠습니다.....꾸벅

[끄적임] 메모...2

<산업혁명>
산업혁명 특징: 생산성이 증가, 노동력 대비 생산성 증가, 융합을 통한 새로운 산업 탄생
 
1차 산업혁명: 증기
증기기관의 발명, 열에너지->운동에너지, 수증기의 압력을 피스톤으로 전달, 석탄, 수많은 노동력을 대체, 생산력이 대폭 증가
 
2차 산업혁명: 전기
대량생산, 현재까지도 당시 기술을 사용, 석유 & 전기에너지, 내연기관, 효율적인 자원, 저렴한 가격
 
3차 산업혁명: 부분 자동화
정보화혁명, 자동화혁명, 컴퓨터, Programmable logic control, 단순노동은 컴퓨터가 대체, 알고리즘, 정밀 & 복잡 공정 발달, 반도체 & 고밀도 집적회로 산업 발달
 
4차 사업혁명: 완전 자동화, 초생산 시대, 초연결 시대
사물인터넷, 인공지능, 빅데이터, 로봇기술, 가상현실
홀로그램, 에듀테크, 스마트팩토리, 스마트팜, 스마트시티
기존 일자리를 새로운 일자리로 전환하는 시스템이 중요
 
메이커운동 배경
제조업 문턱이 낮아짐
협력하기 좋아짐
다품종 소량생산 시대, 대량생산 공정의 유연성 증가(개인도 전문 생산력 사용가능)
 
메이커운동 영향
그동안 상품화될 수 없었던 아이디어가 세상에 나올 확률이 커짐
 
교수는 코치, 생겨나는 기술이 너무 많아서 주입식은 불가, 배우는 법을 가르침
산학연계, 기업과의 연계
소프트웨어로 창의적인 것을 만들어야 함
복합문제 해결, 협업 능력, 비판적 사고, 의사 결정 능력, 창의성
데이터 기반의 서비스 비즈니스가 하드웨어 비즈니스를 지배할 것
대학은 산업에 적용이 가능한 기초 공학을 공부
남이 모르는 문제를 찾아서 혁신적으로 해결
 
교육의 방향
재학생과 졸업생의 경계 타파, 온라인 통한 강의 개방, entrepreneurship, 다중대학 네트워크
humanics에 초점, 강의 비용의 절감, 테크놀로지가 교육을 혁신





<몰입>
미하이 칙센트: 플로우
명확한 목표, 빠른 피드백, 적절한 난이도
최적 경험에 빠져 있을 때 큰 행복감을 느낌
시간 개념이 왜곡됨
자아에 대한 의식이 사라짐, 무아지경 ecstasy
몰입 이후 자존감이 상승
주어진 과제가 한 사람이 가진 역량을 최대한 끌어낼 때 몰입을 느낄 확률이 큼
도전하고 노력하여 충분히 해낼 수 있는 과제
메타인지, 내 수준을 이해
목표를 세분화해 계속 도전, 수준을 가늠
몰입하기 위해 점점 난이도를 올리게 되고 실력이 상승됨
 
고도의 집중 상태
산만함: 의식이 무질서, 엔트로피가 높음
수동적일 때, 위기감에 의한 몰입
능동적일 때, 목숨을 걸 정도로 노력해야 함
간화선: 쉴 새 없이 화두에 대해 계속 생각함
자극의 반복
 
창의성: 항상 그 주제에 대해 생각해야 함
창조형 인적자원의 필요성 증대
 

 
 

<글쓰기>
일방적이고 주관적인 생각을 객관적이고 논리적으로 재구성해야 함
OREO MAP opinion, reason, example, opinion/offer
 
놀이에서 즐거움을 찾는다.
나의 즐거움을 쓴다.
나의 즐거움이 남에게 도움이 되게 한다.
최악을 각오하고 최상을 희망한다.
 
잘 쓴 책을 많이 읽기
계속 꾸준히 쓰기
 
창의성?
문제점 메모
생각의 재료를 늘려라
생각을 충돌시켜라
아이디어 메모
글로 구체화
 
비망록
블록 현상
또박또박 써라, 다시 생각하는 것

[끄적임] 메모...1

4차 산업혁명 - 4차 산업혁명이란 무엇인가?
 
EBS 다큐프라임 - 4차 산업혁명, 교육패러다임의 대전환 1- 대학의 변신
 
EBS 다큐프라임 - 4차 산업혁명, 교육패러다임의 대전환 2- 칸막이를 없애라
 
당신이 알아야 할 4차 산업혁명
 
1인 제작의시대_메이커
 
KBS 미래기획 2030 4차산업혁명 대학에서 길을 찾다 1- 미래는 어떤 인재를 원하는가
 
KBS 미래기획 2030 4차 산업혁명 대학에서 길을 찾다 2- 36.5도의 과학, 삶의 질을 높이다
 
당신은 어떤 메이커인가요? / YTN 사이언스
 
노트쓰기로 당신의 천재성을 끌어내세요
 
150년 하버드 글쓰기 비법
 
3년 동안 메모를 하며 내게 일어난 변화는?
 
글쓰기가 두려운 당신이 반드시 들어야 할 대답
 
나를 지켜내는 힘! 매일 아침 써봤니
 
Think ‘different’ - 스티브 잡스
 
EBS 특별기획 통찰 E79 170131 몰입과 창의성
 
[TED] 몰입 미하이 칙센트미하이
 
행복과 공부를 모두 잡는 방법, '몰입'

[아두이노] 라인트레이서 제작

지금까지 다룬 센서들을 이용해 라인트레이서를 만들어 보겠습니다.

아래의 준비물이 필요합니다.

1. IR 센서 2개



2. 초음파센서 1개



3. 서보모터 1개



4. DC모터 2개



5. 바퀴 2개



6. 회전바퀴 1개



7. 나무판 (혹은 아무거나 몸체가 될만한 것)


8. 18650배터리 2개



9. 배터리 케이스 2구



라인트레이서가 작동하는 환경은 다음과 같습니다.


  • 하얀색 바탕, 검은색 차선 사이를 움직임
  • 차선 사이에 종이컵 장애물이 있음
  • 코스의 마지막에 벽이 있음




라인트레이서는 검은 차선 사이를 움직이며 종이컵을 회피해야 하고

마지막에 벽을 만나면 동작을 멈추어야합니다.

라인트레이서의 동작을 제어하기 위해 필요한 함수를 정의합니다.


<구동계>

go_forward() : "직진"; 왼쪽과 오른쪽의 DC모터 속도를 정하고 앞으로 가도록 합니다.

turn_left() : "제자리 좌회전"; 왼쪽 모터는 뒤로, 오른쪽 모터는 앞으로 가도록 합니다.

turn_right() : "제자리 우회전"; 왼쪽 모터는 앞으로, 오른쪽 모터는 뒤로 가도록 합니다.

brake() : "정지"; 왼쪽과 오른쪽의 DC모터를 정지시킵니다.


<센서류>

detect_left() : 좌측 검은선의 감지 함수입니다. 센서가 검은색 물체를 보게되면 값이 변합니다.

이 때의 변화지점을 기준으로 0과 1을 지정해 감지 여부를 정합니다.

IR센서는 주변 환경에 영향을 받으므로 측정되는 값은 신호와 노이즈가 섞인 형태입니다.

(신호+노이즈) - (노이즈) 구조로 작동하도록 해 신호만을 계산합니다.

detect_right() : 우측 검은선의 감지 함수입니다. detect_left()와 동일합니다.

make_dist() : 초음파로 측정되는 값을 cm로 변환하는 함수입니다.

detect_sonic() : 서보모터가 움직이는 함수입니다.

20도에서 160도 사이를 반복적으로 움직이도록 하고 make_dist() 함수를 사용하도록 합니다.


<동작 경우의 수>

response() : 센서의 값들을 모아서 각 경우에 맞게 분류해줍니다.

차선 사이를 지나면서 장애물을 피하고 벽을 보면 멈추도록 경우를 나누어 줍니다.


아래는 제가 작성한 코드입니다.


#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
#include <Servo.h>

#define SPEED_GO 50   // 직진 속도
#define SPEED_TN 75   // 회전 속도
#define M1  1         // 좌측모터
#define M2  2         // 우측모터
#define SensorLeft  5 // 디지털 3: 좌측센서
#define SensorRight 6 // 디지털 5: 우측센서
#define TRIG  11      // 디지털 11
#define ECHO  12      // 디지털 12

int SL = 0;           // 좌측센서 상태
int SR = 0;           // 우측센서 상태

int deg = 160;        // 초기 각도
int a   = 15;         // 서보모터 속도
int DIS = 0;          // 거리

Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *myMotor1 = AFMS.getMotor(M1);
Adafruit_DCMotor *myMotor2 = AFMS.getMotor(M2);
Servo servo;

void setup() {
  Serial.begin(9600);
  Serial.println("::: Let's Go Line Tracer!! :::");

  pinMode(SensorLeft, OUTPUT);
  pinMode(SensorRight, OUTPUT);
  pinMode(TRIG, OUTPUT);
  pinMode(ECHO, INPUT);

  AFMS.begin();
  servo.attach(10);
}

void go_forward(){ // 직진
  myMotor1->setSpeed(SPEED_GO);
  myMotor2->setSpeed(SPEED_GO);
  myMotor1->run(FORWARD);
  myMotor2->run(FORWARD);
  Serial.println("go forward");
}

void turn_left(){ // 제자리 좌회전
  myMotor1->setSpeed(SPEED_TN);
  myMotor2->setSpeed(SPEED_TN);
  myMotor1->run(BACKWARD);
  myMotor2->run(FORWARD);
  //delay(100);
  Serial.println("turn left"); 
}

void turn_right(){ // 제자리 우회전
  myMotor1->setSpeed(SPEED_TN);
  myMotor2->setSpeed(SPEED_TN);                                                                                     
  myMotor1->run(FORWARD);
  myMotor2->run(BACKWARD);
  //delay(100);
  Serial.println("turn right"); 
}

void brake(){ // 정지
  myMotor1->run(RELEASE);
  myMotor2->run(RELEASE);
  Serial.println("brake");
}

void detect_left(){ // 좌측센서 감지여부
  int a, b, c;
 
  digitalWrite(SensorLeft, HIGH); // 신호+노이즈
  delayMicroseconds(400);
  a = analogRead(A3);
 
  digitalWrite(SensorLeft, LOW); // 노이즈
  delayMicroseconds(400);
  b = analogRead(A3);

  c = a - b;

  if(c <= 140)
    SL = 1;
  else
    SL = 0;
}

void detect_right(){ // 우측센서 감지여부
  int a, b, c;
 
  digitalWrite(SensorRight, HIGH); // 신호+노이즈
  delayMicroseconds(400);
  a = analogRead(A5);
 
  digitalWrite(SensorRight, LOW); // 노이즈
  delayMicroseconds(400);
  b = analogRead(A5);

  c = a - b;

  if(c <= 140)
    SR = 1;
  else
    SR = 0;
}

void detect_sonic(){ // 초음파센서 감지여부
  servo.write(deg);
  deg = deg - a;
  if(deg <= 20 || deg >= 160){
    a*=-1;
  }
  delay(25);
  make_dist();
}

unsigned long make_dist(){
  unsigned long distance;
  digitalWrite(TRIG,HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG,LOW);
  distance = pulseIn(ECHO,HIGH)/58.2;
  DIS = distance;
  return distance;
}

void loop() {
  detect_left();
  detect_right();
  detect_sonic();
  response();
}

void response(){
  if (SL == 0 && SR == 0){ // 센서 X
    if (DIS <= 20){
      if (deg < 85) // 왼쪽 장애물 (센서 X, 레이더 O)
        turn_left();
      else if (deg > 95) // 오른쪽 장애물 (센서 X, 레이더 O)
        turn_right();
      else if (deg >= 85 && deg <= 95)
        brake();
    }
    else
      go_forward();
  }

  else if (SL == 1 && SR == 0){ // 왼쪽 센서 O
    if (DIS <= 20){
      if (deg < 85) // 왼쪽 장애물 (센서 O, 레이더 O)
        turn_left();
      else if (deg > 95) // 오른쪽 장애물 (센서 O, 레이더 O)
        turn_right();
      else if (deg >= 85 && deg <= 95)
        brake();
    }
    else
      turn_right();
  }
 
  else if (SL == 0 && SR == 1){ // 오른쪽 센서 O
    if (DIS <= 20){
      if (deg < 85) // 왼쪽 장애물 (센서 O, 레이더 O)
        turn_left();
      else if (deg > 95) // 오른쪽 장애물 (센서 O, 레이더 O)
        turn_right();
      else if (deg >= 85 && deg <= 95)
        brake();       
    }
    else
      turn_left();
  }

  else
    brake(); 
}


실행 결과... 차선을 잘 따라가고 장애물은 잘 피하나, 벽을 만났을 때 멈추지를 못하네요;;

다음 시간에 이 부분을 조금 더 손봐야할 듯 하네요...

[아두이노] 모터쉴드 사용하기

오늘은 모터쉴드를 사용해보겠습니다.

아래의 준비물이 필요합니다.

1. Motor Shield v2.0



2. DC모터



3. 일자 드라이버


여러 개의 모터를 사용해야 할 때 모터쉴드를 사용합니다.

제가 사용할 모터쉴드는 Motor Shield v2.0 입니다.

Motor Shield v2.0는 4개의 DC모터와 2개의 서보모터를 연결할 수 있습니다.

모터쉴드를 아두이노와 결합해줍니다.

모터쉴드의 보드 표면에 M1~4로 표기가 되어 있습니다.

M1에 DC모터의 두 선을 연결해줍니다.

그리고 아래의 코드를 입력해줍니다.


#include <Adafruit_MotorShield.h>

Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *myMotor1 = AFMS.getMotor(M1);

void setup() {
  AFMS.begin();
}

void loop(){
  myMotor1->setSpeed(100);
  myMotor1->run(FORWARD);
}


컴파일하고 업로드 하여 DC모터의 동작을 살펴봅니다.

AFMS.getMotor(M1)의 M1 대신에 M2~4를 넣어 다른 단자를 제어할 수 있습니다.

setSpeed(100)의 숫자를 달리해 모터의 속도를 조절할 수 있습니다.

run(FORWARD)의 명령을 달리해 모터의 움직임을 조절할 수 있습니다.

EX) FORWARD, BACKWARD, RELEASE...

[아두이노] IR센서 사용하기

오늘은 IR센서를 사용해보겠습니다.

아래의 준비물이 필요합니다.

1. IR센서 TCRT5000




2. 저항 5.1k




3. 저항 150




* 저항은 다음 표를 보고 구분하시면 됩니다.




이제 IR센서를 사용하기 위해서는 저항과 함께 회로를 구성해야합니다.

아래의 회로도에 맞게 소자와 도선을 배치해줍니다.





Digital in은 6번에, Signal은 아날로그 3번에 연결합니다.

저는 이렇게 연결했습니다.




이제 아래의 코드를 입력해주세요.

void setup() {
  Serial.begin(9600);
  pinMode(6,OUTPUT);
}

void loop() {
  digitalWrite(6,HIGH);
  delay(100);
  Serial.println(analogRead(A3));
}

컴파일하고 업로드해줍니다.




IR센서에 손가락을 가져다 대면 그래프의 값이 치솟습니다.

탐지거리는 최대 약 5cm 정도인 것 같네요.