IR SENSOR 수신기와 송신기로 버스 탑승 하차 COUNT해보기 (Arduino, ESP32)

하겅 ·2025년 4월 30일

Capstone

목록 보기
8/14

적외선 송신, 수신으로 COUNT하는 글을 몇 주 전에 포스팅 했는데요 그 이후로 마무리에 적었떤 '하나의 센서를 더 추가해 방향에 따라 탑승과 하차를 판단하는 프로그램'을 진행하겠다 적었습니다 그리고 저번 주 해당 실습을 진행했는데요 문제가 몇 가지 발생했습니다

문제점

  1. 잘 읽히던 데이터가 두 개 연결하고 나니 안 읽힘
  2. 하나의 센서 불이 약해짐

고로 이번 포스팅은 수신기에 대한 이해도 못 한 채로 냅다 회로를 연결한 것이 문제였던 것을 깨달아 적는 포스팅입니다 👍 당연할지도요 저는 소프트웨어 전공이거던요 (ㅎ ㅈㅅ)

일단 수신기의 구조는 아래와 같습니다

  • 맨 왼쪽: S → Signal 핀 (디지털 GPIO 핀과 연결 할 핀 ex. D2, D4)
  • 가운데: + → VCC 핀
  • 오른쪽: - → GND 핀 (ESP32의 GND와 연결)

여기서 실수한 건 바로 S(Signal pin)를 VIN(전원 입력 핀-고전압 IN 경로)에 연결했다는 점입니다 무슨 소리인지 잘 몰라서 조사해 보니 전류 역주입(전류가 들어가면 안 되는 곳에 전류가 주입된 것)이 되어 센서의 내부 회로에 무리를 줬을 가능성이 높은 거라고 하더라고요
따라서 IR 송신기의 S는 디지털 제어용 핀이기 때문에 GPIO 핀에 연결해야 하고 VIN처럼 5V~12V가 흐르는 고전압 전원에 직접 연결하면 안 되는 거지요 그래서!! 회로를 처음부터 다시 연결했습니다

해결 방법

  • S를 GPIO 핀으로 변경
  • 두 개의 센서를 각각 다른 GPIO 핀으로 이동
  • -를 VIN이 아닌 3V3으로 이동

(피그마로 그린 거라 사용한 핀 번호만 작성해 뒀습니다)

  • 수신기1 (SENSOR Receiver 1)
    • DO → D23 (GPIO23)
    • GND → GND (ESP32's)
    • VCC → 3V3 (3.3V)
  • 송신기1 (IR SENSOR 1)
    • S → D22 (GPIO22)
    • plus → 3V3
    • minus → GND (ESP32's)
  • 수신기2 (SENSOR Receiver 2)
    • DO → D19 (GPIO19)
    • GND → GND (ESP32's)
    • VCC → 3V3 (3.3V)
  • 송신기2 (IR SENSOR 2)
    • S → D18 (GPIO18)
    • plus → 3V3
    • minus → GND (ESP32's)

코드

enum FlowState {
  IDLE,
  WAITING_FOR_2,
  WAITING_FOR_1
};

FlowState currentState = IDLE;

enum은 상수 집합에 이름을 부여하는 자료형으로, 내부적으로 IDLE = 0, WAITING_FOR_2 = 1, WAITING_FOR_1 = 2의 값이 부여되어 있는 것을 저희가 더 직관적으로 읽을 수 있도록 설정했습니다

// 상태 변화 감지
  if (currentState == IDLE) {
    if (sensorState1 == LOW && sensor1PrevState == HIGH) {
      currentState = WAITING_FOR_2;
      Serial.println("1번 감지됨 → 2번 대기 중 (탑승 흐름 시작)");
    } else if (sensorState2 == LOW && sensor2PrevState == HIGH) {
      currentState = WAITING_FOR_1;
      Serial.println("2번 감지됨 → 1번 대기 중 (하차 흐름 시작)");
    }
  }

저희 프로젝트에서는 적외선 앞을 지나간 상태를 체크합니다 따라서 LOW(0)값을 읽어야 하기 때문에 첫 번째 조건으로 현재 상태의 값이 0이라면을 적었습니다
두 번째 if문은 1번 센서의 값이 변화했는지 확인합니다 현재가 LOW이고, 이전 값이 HIGH였다면 적외선 앞을 지나간 것으로 값을 부여하고 최종적으로 현재 상태2번이 감지되길 기다리는 상태의 상수를 부여합니다
그리고 else if문에서 2번이 감지 된 경우 다음으로 1번이 오는 것을 기다리도록 설정했습니다 그러지 않으면 1 → (2 → 1) 처럼 탑승했다 하차했다 값이 왔다갔다 하게 돼버립니다
따라서 WAITING_FOR_N을 통해 탑승과 하차 흐름의 시작을 알리도록 설정한 게 됩니다

  else if (currentState == WAITING_FOR_2) {
    if (sensorState2 == LOW && sensor2PrevState == HIGH) {
      count++;
      Serial.println("🛫 탑승 완료 (1 → 2)");
      Serial.print("👥 현재 인원 수: ");
      Serial.println(count);
      currentState = IDLE;
    }
    // 잘못된 흐름 방지: 1번 → 다시 1번 → 무시
  }

첫 번째 현재 상태가 WAITING_FOR_2인 경우, 1번이 인식되어 2번을 기다리는 상태이고 2번 센서의 상태가 0, 2번의 이전 상태가 1일 때 (값에 변화가 있다면) 탑승객 수를 증가합니다
그리고 여기서 중요한 것 최종 현재 상태를 0으로 되돌리고 if문을 탈출하는 것!!입니다 currentState = IDLE;를 통해 다시 0으로 되돌림으로써 흐름을 끊는 것입니다 즉 탑승과 하차의 흐름을 기다리는 상태가 되는 것입니다



  else if (currentState == WAITING_FOR_1) {
    if (sensorState1 == LOW && sensor1PrevState == HIGH) {
      count--;
      Serial.println("🛬 하차 완료 (2 → 1)");
      Serial.print("👥 현재 인원 수: ");
      Serial.println(count);
      currentState = IDLE;
    }
    // 잘못된 흐름 방지: 2번 → 다시 2번 → 무시
  }

  // 상태 저장
  sensor1PrevState = sensorState1;
  sensor2PrevState = sensorState2;

탑승 코드와 마찬가지로 1번 센서의 값이 0이고 1번 센서의 이전 값이 1이라면 하차한 만큼의 탑승객 수를 감소합니다 아래 코드는 위에서 설명한 것과 동일합니다
그리고 마지막으로 센서1과 2의 이전 상태를 현재 상태로 바꿔 줌으로써 loop()의 한 번의 반복이 끝납니다



👍 시리얼 모니터 출력 화면

<

이렇게 센서 두 개를 통해 1번 센서를 지나고 2번 센서를 지났다면 탑승으로, 반대로 2번 센서를 지나고 1번 센서를 지났다면 하차로 인식하는 프로그램을 작성해 봤습니다 이제 인식된 값을 시리얼 모니터만 아니라 JSON으로 바꿔 Node-RED로 전송해 데이터를 받아야 합니다 다음 포스팅 때 적어보도록 하겠습니다

최종 코드

#define txPin1 18   // 송신기 2 (IR LED)
#define txPin2 22   // 송신기 1 (IR LED)
#define rxPin1 19   // 수신기 2 (DO)
#define rxPin2 23   // 수신기 1 (DO)

int sensorState1 = 0;
int sensorState2 = 0;
int sensor1PrevState = HIGH;
int sensor2PrevState = HIGH;

int count = 0;

enum FlowState {
  IDLE,
  WAITING_FOR_2,
  WAITING_FOR_1
};

FlowState currentState = IDLE;

void setup() {
  Serial.begin(115200);
  pinMode(txPin1, OUTPUT);
  pinMode(txPin2, OUTPUT);
  pinMode(rxPin1, INPUT);
  pinMode(rxPin2, INPUT);
}

void loop() {
  digitalWrite(txPin1, HIGH);
  digitalWrite(txPin2, HIGH);

  sensorState1 = digitalRead(rxPin2); // 센서1 (DO23)
  sensorState2 = digitalRead(rxPin1); // 센서2 (DO19)

  // 상태 변화 감지
  if (currentState == IDLE) {
    if (sensorState1 == LOW && sensor1PrevState == HIGH) {
      currentState = WAITING_FOR_2;
      Serial.println("1번 감지됨 → 2번 대기 중 (탑승 흐름 시작)");
    } else if (sensorState2 == LOW && sensor2PrevState == HIGH) {
      currentState = WAITING_FOR_1;
      Serial.println("2번 감지됨 → 1번 대기 중 (하차 흐름 시작)");
    }
  }

  else if (currentState == WAITING_FOR_2) {
    if (sensorState2 == LOW && sensor2PrevState == HIGH) {
      count++;
      Serial.println("🛫 탑승 완료 (1 → 2)");
      Serial.print("👥 현재 인원 수: ");
      Serial.println(count);
      currentState = IDLE;
    }
    // 잘못된 흐름 방지: 1번 → 다시 1번 → 무시
  }

  else if (currentState == WAITING_FOR_1) {
    if (sensorState1 == LOW && sensor1PrevState == HIGH) {
      count--;
      Serial.println("🛬 하차 완료 (2 → 1)");
      Serial.print("👥 현재 인원 수: ");
      Serial.println(count);
      currentState = IDLE;
    }
    // 잘못된 흐름 방지: 2번 → 다시 2번 → 무시
  }

  // 상태 저장
  sensor1PrevState = sensorState1;
  sensor2PrevState = sensorState2;

  delay(100);
}
profile
건강합시다

0개의 댓글