산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

레이저 트리거 슬롯카 랩 타이머: GLCD 디스플레이로 정밀 랩타임 측정

부품 및 소모품

아두이노 메가 2560 (Arduino Mega 2560) 1개
KY-008 레이저 모듈 (650nm, 5V) 1개
레이저 수신 센서 모듈 (KY-008과 짝) 1개
그래픽 LCD (GLCD, KS0108 컨트롤러, 128×64) 1개
브레드보드/퍼프보드, 점퍼 와이어, 전원 공급 1세트

소프트웨어

프로젝트 개요

슬롯카(전동 미니카) 트랙에 레이저 게이트를 설치해 랩타임을 초/밀리초 단위로 측정하는 타이머입니다. 레이저 빔이 차단되면(차량 통과) 랩 완료로 인식해 현재 랩타임, 이전 랩타임, 베스트 랩타임, 총 랩 수를 GLCD에 실시간 표시합니다. 디바운스 로직으로 노이즈 방지, 전원 투자입 후 50ms 대기해 오작동 방지.

레이저 트리거 슬롯카 랩 타이머: GLCD 디스플레이로 정밀 랩타임 측정

하드웨어 연결

KY-008 레이저 모듈 (3핀: -, +, S)

레이저 수신 센서 (3핀: GND, VCC, SIGNAL)

GLCD (KS0108, 20핀)

데이터 라인 8비트(D0~D7) + 제어선(RS, RW, EN, CS1, CS2, RST, VEE 대비조절, 백라이트) 필요. 아두이노 메가의 다수 GPIO 활용 권장. 커넥터 제작해 탈착식으로 만들면 편리.

레이저 트리거 슬롯카 랩 타이머: GLCD 디스플레이로 정밀 랩타임 측정

가장 어려운 부분: 레이저와 센서를 트랙 양쪽에 정확히 정렬해 빔이 차체 하부를 통과하도록 맞추는 것. 높이가 안 맞으면 감지 실패.

전체 펌웨어 코드 (주석 보강)

/* 
 * 슬롯카 랩 타이머 - 레이저 게이트 방식
 * 작성자: Tal Ofer
 */

#include <openGLCD.h>

// 랩 타임 변수들
unsigned long currentRunStartMillis = 0;  // 현재 랩 시작 시각
unsigned long lastRunInMillis = 0;        // 이전 랩 타임
unsigned long bestRunInMillis = 0;        // 베스트 랩 타임
int currentLap = 0;                       // 현재 랩 번호
unsigned long savedMillis = 0;            // 연산용 임시 저장

// GLCD 텍스트 영역 정의
gText t1;  // 랩 수 + 현재 랩타임 (큰 폰트)
gText t2;  // 이전 랩타임 (작은 폰트)
gText t3;  // 베스트 랩타임 (작은 폰트, 흰색)

// 디스플레이용 분리 변수
int sec_val, milli_val;

// 레이저 게이트 센서
const int gateSensorPin = 2;
int gateSensorState = HIGH;
int lastGateSensorState = HIGH;
unsigned long lastDebounceTime = 0;
const int debounceDelay = 50;  // ms

void setup() {
    pinMode(gateSensorPin, INPUT);
    delay(50);  // 센서/레이저 안정화 대기
    
    // GLCD 초기화
    GLCD.Init(NON_INVERTED);
    
    // 텍스트 영역 정의
    t1.DefineArea(textAreaTOP, lcdnums14x24);  // 상단 큰 숫자 폰트
    t2.DefineArea(0, GLCD.CenterY, 8, 2, fixednums7x15);  // 하단 좌
    t3.DefineArea(GLCD.CenterX, GLCD.CenterY, 8, 2, fixednums7x15); // 하단 우
    t3.SetFontColor(WHITE);
    t3.ClearArea();
    
    // 고정 라벨 출력
    GLCD.SelectFont(System5x7);
    GLCD.CursorTo(1, 4); GLCD.print("LAST");
    GLCD.CursorTo(11, 4); GLCD.print("BEST");
    
    // 변수 초기화
    currentRunStartMillis = lastRunInMillis = bestRunInMillis = 0;
    currentLap = 0;
}

void loop() {
    int reading = digitalRead(gateSensorPin);
    
    // 디바운스: 상태 변화 시 타이머 리셋
    if (reading != lastGateSensorState) {
        lastDebounceTime = millis();
    }
    
    // 디바운스 지연 후 상태 확정
    if ((millis() - lastDebounceTime) > debounceDelay) {
        if (reading != gateSensorState) {
            gateSensorState = reading;
            
            // 빔 차단됨 (LOW) = 차량 통과
            if (gateSensorState == LOW) {
                savedMillis = millis();  // 같은 시각 기준 연산
                
                if (currentLap > 0) {  // 첫 랩이 아니면
                    lastRunInMillis = savedMillis - currentRunStartMillis;
                    // 베스트 갱신
                    if (lastRunInMillis < bestRunInMillis || bestRunInMillis == 0) {
                        bestRunInMillis = lastRunInMillis;
                    }
                }
                
                // 새 랩 시작
                currentRunStartMillis = savedMillis;
                currentLap++;
            }
        }
    }
    lastGateSensorState = reading;
    
    // --- 디스플레이 업데이트 ---
    
    // 랩 카운트 (큰 폰트 영역)
    t1.CursorTo(0, 0);
    t1.Printf(F("%02d"), currentLap);
    
    // 현재 랩 진행 시간
    savedMillis = millis();
    if (currentLap > 0) {
        calcResultFromMillis(savedMillis - currentRunStartMillis, &sec_val, &milli_val);
    } else {
        calcResultFromMillis(0, &sec_val, &milli_val);
    }
    
    // 현재 랩타임 (큰 폰트, 초.밀리초)
    t1.CursorTo(3, 0);
    t1.Printf(F("%02d.%03d"), sec_val, milli_val);
    
    // 이전 랩타임 (작은 폰트, 좌측)
    calcResultFromMillis(lastRunInMillis, &sec_val, &milli_val);
    t2.CursorTo(1, 1);
    t2.Printf(F("%02d.%03d"), sec_val, milli_val);
    
    // 베스트 랩타임 (작은 폰트, 우측, 흰색)
    calcResultFromMillis(bestRunInMillis, &sec_val, &milli_val);
    t3.CursorTo(1, 1);
    t3.Printf(F("%02d.%03d"), sec_val, milli_val);
}

// 밀리초 → 초, 밀리초 분리
void calcResultFromMillis(unsigned long value, int *sec_val, int *milli_val) {
    *sec_val = int(value / 1000);
    *milli_val = value - *sec_val * 1000;
}

코드 핵심 포인트

확장 아이디어

제조공정

  1. 알루미늄 레이저 마킹 전문 가이드: 정밀도, 내구성, 산업 적용 사례
  2. 레이저 마킹 종합 가이드: 유형, 이점, 적용 분야 총정리
  3. 파이버 레이저 마킹: 현대 산업을 위한 정밀도, 속도, 다용도성
  4. 레이저 포인터: 설계, 제조, 안전성 개요
  5. 롤러코스터: 눈썰매에서 강철 거인으로
  6. 반도체 레이저: 현대 기술을 위한 정밀 광원
  7. 고체 레이저: 기술, 응용, 미래 트렌드
  8. 모래시계: 역사, 장인정신, 현대적 매력
  9. RetroPie에 Kuman 3.5″ TFT 디스플레이 설치하기 - 단계별 가이드
  10. 알피봇(Rpibot): 임베디드 시스템 학습용 저비용 확장형 모바일 로봇