코드 검색

제29/31과: Car-7 리모컨을 사용하여 SunFounder 스마트 카 제어하기 | Robojax

제29/31과: Car-7 리모컨을 사용하여 SunFounder 스마트 카 제어하기 | Robojax

이번 강의에서는 적외선(IR) 리모컨을 사용하여 SunFounder 스마트 카를 원격 조종 차량으로 변환합니다. 유선 연결이나 스마트폰 앱에 의존하는 대신, 표준 IR 리모컨의 버튼을 매핑하여 차량의 움직임(전진, 후진, 회전, 심지어 대각선 주행)을 제어하고, 주행 중 속도도 조절하는 방법을 배우게 됩니다. 이 프로젝트는 모터 제어와 IR 통신의 기초를 학습한 후에 진행하기에 완벽한 다음 단계로, 두 가지를 하나의 인터랙티브 시스템으로 결합합니다.

여기서 얻을 수 있는 실질적인 가치는 로봇 플랫폼을 위한 견고하고 사용자 친화적인 제어 인터페이스를 만드는 방법을 이해하는 데 있습니다. 배우게 될 원리는 다음과 같은 다양한 프로젝트에 직접 적용할 수 있습니다:

  • 소형 배달 로봇과 같은 홈 자동화 작업을 위한 원격 조종 로봇 구축.
  • 교육용 로봇 경진대회를 위한 프로그래밍 가능한 차량 제작.
  • 카메라 슬라이더나 팬-틸트 메커니즘용 맞춤형 리모컨 개발.
  • 더 크고 복잡한 자동화 시스템을 위한 사용자 인터페이스 프로토타이핑.

하드웨어 및 부품

이 프로젝트는 SunFounder 3-in-1 Arduino 키트를 기반으로 합니다. 따라 하려면 아래 나열된 부품이 필요합니다. 배선은 이전 강의에서 배운 내용을 확장한 것으로 간단합니다.

  • SunFounder 3-in-1 Arduino 키트: 스마트 카 섀시, 모터 드라이버 보드, Arduino 보드가 포함됩니다.
  • 적외선 리모컨: 키트에 포함된 표준 리모컨입니다.
  • IR 수신기 모듈: 리모컨의 신호를 디코딩하는 센서입니다.
  • LED 및 330옴 저항: 키가 눌렸는지 확인하는 시각적 표시기로 사용됩니다. (영상 04:08 참조)
  • 점퍼 와이어: 브레드보드에서 필요한 연결을 만드는 데 사용됩니다.

배선 가이드

car_9_lesson_29_wriing_for_IR

코드를 살펴보기 전에 하드웨어가 올바르게 연결되었는지 확인하겠습니다. IR 수신기와 모터 드라이버의 배선은 이 시리즈의 이전 강의와 일치합니다. 프로젝트를 더 인터랙티브하게 만들기 위해 시각적 피드백 표시기로 핀 13에 외부 LED도 연결합니다.

연결에 대한 단계별 가이드는 다음과 같습니다:

  1. IR 수신기: IR 수신기에는 세 개의 핀이 있습니다. 양극 핀은 브레드보드의 5V 레일에 연결합니다. 접지 핀은 GND 레일에 연결합니다. 마지막 핀인 신호 핀은 Arduino 보드의 디지털 핀 11에 연결합니다. (영상 05:29 참조)
  2. 외부 LED: 330옴 저항의 한쪽 다리를 Arduino의 디지털 핀 13에 연결합니다. 저항의 다른 쪽 다리를 LED의 긴 다리(양극)에 연결합니다. LED의 짧은 다리(음극)는 브레드보드의 GND 레일에 연결해야 합니다. (영상 04:08 참조)
  3. 모터 드라이버: 모터 드라이버의 네 개 핀(A_1B, A_1A, B_1B, B_1A)은 각각 Arduino의 핀 5, 6, 9, 10에 연결됩니다. 이 설정은 이전 강의에서 다루었습니다. (영상 06:44 참조)

이러한 연결에 대한 시각적 참조는 아래 배선도를 참조하세요.

코드 설명

이 프로젝트의 코드는 직관적으로 설계되었습니다. 복잡한 IR 신호 디코딩 작업을 처리하기 위해 IRremote 라이브러리를 사용합니다. 자신의 프로젝트에 맞게 조정할 수 있는 사용자 구성 가능한 부분을 살펴보겠습니다.

스케치 상단에는 핀 정의가 있습니다. 이 예제에서 사용된 핀과 다른 핀에 부품을 연결한 경우 가장 먼저 확인해야 할 부분입니다.

const int IR_RECEIVE_PIN = 12;  // IR 센서의 핀 번호 정의
const int A_1B = 5;
const int A_1A = 6;
const int B_1B = 9;
const int B_1A = 10;
  • IR_RECEIVE_PIN: 이 상수는 IR 수신기의 신호 핀에 연결된 디지털 핀을 정의합니다. 다른 핀에 연결한 경우 여기의 숫자를 변경하면 됩니다.
  • A_1B, A_1A, B_1B, B_1A: 이 상수는 모터 드라이버의 네 개 제어 핀에 매핑됩니다. 왼쪽 및 오른쪽 모터의 속도와 방향을 제어합니다.

다음으로 차량의 동작을 제어하는 중요한 변수가 있습니다.

int speed = 150;
  • speed: 이 변수는 차량의 초기 속도를 설정합니다. 값의 범위는 0에서 255까지입니다. 이 프로젝트에서는 리모컨의 "+" 및 "-" 키를 사용하여 변경할 수 있습니다. 코드에는 속도가 255를 초과하거나 0 아래로 떨어지지 않도록 하는 로직도 포함되어 있습니다. (영상 09:22 참조)

리모컨의 핵심 로직은 loop() 함수에서 처리됩니다. 키를 누르면 decodeKeyValue() 함수가 원시 IR 코드를 전진의 경우 "2", 속도 증가의 경우 "+"와 같은 간단한 문자열로 변환합니다. 이렇게 하면 이후의 if 문을 매우 쉽게 읽고 수정할 수 있습니다. (영상 07:58 참조)

moveForward(), turnRight(), moveLeft()와 같은 사용자 정의 함수는 모터 제어가 이루어지는 곳입니다. 각 함수는 현재 speed를 인자로 받습니다. 예를 들어, moveForward(speed)는 지정된 속도로 두 모터를 모두 앞으로 구동합니다. "turn"과 "move"의 핵심 차이는 turn은 두 바퀴를 반대 방향으로 회전시켜 차가 제자리에서 회전하게 하고, move는 한 바퀴만 회전시켜 차가 정지된 바퀴를 중심으로 호를 그리며 움직이게 한다는 점입니다. (영상 10:14)

실시간 프로젝트 시연

코드가 업로드되고 차량에 전원이 켜지면 리모컨이 주요 인터페이스가 됩니다. 영상의 시연은 몇 가지 핵심 동작을 보여줍니다:

  • 속도 제어: "+" 키를 누르면 속도가 50씩 증가하고, "-" 키를 누르면 감소합니다. 속도는 모터를 보호하기 위해 최대 255, 최소 0으로 제한됩니다. (영상 11:56)
  • 순간 이동: "2"(전진) 또는 "8"(후진)과 같은 방향 키를 누르면 차량이 1초 동안 움직인 후 자동으로 정지합니다. 이는 코드에 내장된 안전 기능입니다. (영상 13:09)
  • 회전 및 조향: 리모컨의 십자 패턴 키는 조이스틱처럼 작동합니다. "4" 또는 "6"을 누르면 차량이 제자리에서 좌회전 또는 우회전합니다. "1" 또는 "3"과 같은 대각선 키를 누르면 "move left" 또는 "move right"가 수행되는데, 이는 한 바퀴가 고정된 상태에서 더 급격하게 회전하는 동작입니다. (영상 16:42)

차량이 항상 완벽하게 직진하지 않는 것을 눈치챘을 수도 있습니다. 이는 종종 모터의 미세한 차이 또는 차량 조립의 장력 차이로 인해 발생하며, 이러한 키트에서 흔하고 정상적인 특성입니다. (영상 15:14)

챕터

  • [00:00] 스마트 카 IR 리모컨 소개
  • [01:15] 사전 요구 사항 및 필요한 이전 강의
  • [01:56] 프로젝트 문서 개요
  • [02:29] 리모컨 키 기능 이해
  • [03:29] IR 수신기 및 LED 배선 단계별 가이드
  • [05:51] 프로젝트 코드 열기 및 로드
  • [07:41] 코드 설명: 루프, 키 디코딩 및 동작
  • [09:22] 코드의 속도 제한 및 안전 기능
  • [10:08] 모터 이동 함수 설명
  • [11:49] 실시간 시연: 속도 제어 및 LED 깜빡임 테스트
  • [13:27] 실시간 시연: 전진, 후진 및 회전
  • [14:31] 전원 및 이동을 포함한 전체 차량 시연

이미지

Car 9 lesson 29 wiring for IR
Car 9 lesson 29 wiring for IR
896-Lesson 29/31: Car-7 Controlling SunFounder Smart Car using Remote Controller
언어: C++
/*
Lesson 29/31: Car-7 Controlling SunFounder Smart Car using Remote Controller
Get this code and watch video Download and resource page https://robojax.com/RJT612

*/
#include <IRremote.h>

const int IR_RECEIVE_PIN = 12;  // Define the pin number for the IR Sensor

const int A_1B = 5;
const int A_1A = 6;
const int B_1B = 9;
const int B_1A = 10;


int speed = 150;

void setup() {
  Serial.begin(9600);

  //motor
  pinMode(A_1B, OUTPUT);
  pinMode(A_1A, OUTPUT);
  pinMode(B_1B, OUTPUT);
  pinMode(B_1A, OUTPUT);

  //IR remote
  IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);  // Start the IR receiver // Start the receiver
  Serial.println("REMOTE CONTROL START");

}

void loop() {

  if (IrReceiver.decode()) {
    //    Serial.println(results.value,HEX);
    String key = decodeKeyValue(IrReceiver.decodedIRData.command);
    if (key != "ERROR") {
      Serial.println(key);

      if (key == "+") {
        speed += 50;
      } else if (key == "-") {
        speed -= 50;
      } else if (key == "2") {
        moveForward(speed);
        delay(1000);
      } else if (key == "1") {
        moveLeft(speed);
      } else if (key == "3") {
        moveRight(speed);
      } else if (key == "4") {
        turnLeft(speed);
      } else if (key == "6") {
        turnRight(speed);
      } else if (key == "7") {
        backLeft(speed);
      } else if (key == "9") {
        backRight(speed);
      } else if (key == "8") {
        moveBackward(speed);
        delay(1000);
      }

      if (speed >= 255) {
        speed = 255;
      }
      if (speed <= 0) {
        speed = 0;
      }
      delay(500);
      stopMove();
    }

    IrReceiver.resume();  // Enable receiving of the next value
  }
}

void moveForward(int speed) {
  analogWrite(A_1B, 0);
  analogWrite(A_1A, speed);
  analogWrite(B_1B, speed);
  analogWrite(B_1A, 0);
}

void moveBackward(int speed) {
  analogWrite(A_1B, speed);
  analogWrite(A_1A, 0);
  analogWrite(B_1B, 0);
  analogWrite(B_1A, speed);
}

void turnRight(int speed) {
  analogWrite(A_1B, speed);
  analogWrite(A_1A, 0);
  analogWrite(B_1B, speed);
  analogWrite(B_1A, 0);
}

void turnLeft(int speed) {
  analogWrite(A_1B, 0);
  analogWrite(A_1A, speed);
  analogWrite(B_1B, 0);
  analogWrite(B_1A, speed);
}

void moveLeft(int speed) {
  analogWrite(A_1B, 0);
  analogWrite(A_1A, speed);
  analogWrite(B_1B, 0);
  analogWrite(B_1A, 0);
}

void moveRight(int speed) {
  analogWrite(A_1B, 0);
  analogWrite(A_1A, 0);
  analogWrite(B_1B, speed);
  analogWrite(B_1A, 0);
}

void backLeft(int speed) {
  analogWrite(A_1B, speed);
  analogWrite(A_1A, 0);
  analogWrite(B_1B, 0);
  analogWrite(B_1A, 0);
}

void backRight(int speed) {
  analogWrite(A_1B, 0);
  analogWrite(A_1A, 0);
  analogWrite(B_1B, 0);
  analogWrite(B_1A, speed);
}

void stopMove() {
  analogWrite(A_1B, 0);
  analogWrite(A_1A, 0);
  analogWrite(B_1B, 0);
  analogWrite(B_1A, 0);
}


String decodeKeyValue(long result)
{
  switch(result){
    case 0x16:
      return "0";
    case 0xC:
      return "1"; 
    case 0x18:
      return "2"; 
    case 0x5E:
      return "3"; 
    case 0x8:
      return "4"; 
    case 0x1C:
      return "5"; 
    case 0x5A:
      return "6"; 
    case 0x42:
      return "7"; 
    case 0x52:
      return "8"; 
    case 0x4A:
      return "9"; 
    case 0x9:
      return "+"; 
    case 0x15:
      return "-"; 
    case 0x7:
      return "EQ"; 
    case 0xD:
      return "U/SD";
    case 0x19:
      return "CYCLE";         
    case 0x44:
      return "PLAY/PAUSE";   
    case 0x43:
      return "FORWARD";   
    case 0x40:
      return "BACKWARD";   
    case 0x45:
      return "POWER";   
    case 0x47:
      return "MUTE";   
    case 0x46:
      return "MODE";       
    case 0x0:
      return "ERROR";   
    default :
      return "ERROR";
    }
}

자원 및 참고자료

파일📁

아두이노 라이브러리 (zip)