본문 바로가기
아두이노

자동차 RPM 인디게이터

by 구루가 되고픈 2021. 5. 29.

레이싱 게임이나 경주용 차량에는 기어변속 구간을 알려주는 RPM 인디게이터라는게 있습니다.

어느분의 요청으로 제작을 하게 되었는데, 간단히 소개합니다.

먼저 차량에서 RPM 정보를 가져와야 하는데, 이것은 기존에 차량용 대시보드 제작때 사용했던 ODB2 아답터를 사용합니다.

 

차량정보를 시리얼정보로 출력해주는 어답터

 

RPM정보를 아두이노로 받게되면 이를 LED에 출력해서 변속 시점을 알려주면 되는데요.

제작하고자 하는 인디게이터를 LED 60발로 제작할 계획이어서 neopixel strip을 사용할 예정입니다.

 

아두이노 마이크로 프로에 조도센서와 배선을 연결

 

아두이노 micro pro와 조도센서(오른쪽에 살짝 있는) 2개와 네오픽셀 스트립으로 하드웨어 구성을 끝납니다.

조도센서는 낮과 밤에 운전시에 밝은 LED불빛이 방해가 될 수 있기 때문에 LED밝기를 조절하기 위해서 포토다이오드를 달아 주었습니다.

먼저 구현을 하기 위해 브레드 보드에 간단히 회로를 구성하고 코드를 짭니다.

RPM이 올라가면 차례로 LED가 켜지고 일정 RPM이상이 되면 LED전체가 빨간색 불이 들어오면서 변속 시점을 알려 주면 됩니다.

 

순차 점멸 후 고RPM에서 전체 빨간색 점등

 

0에서 5000RPM까지 올릴때 LED동작을 테스트해보니 잘 됩니다.

 

 

차량에 연결하여 테스트

 

실차에 설치해서 테스트 했을때도 잘 됩니다.

차량에 예쁘게만 설치한다면 재밌는 가젯이 될거 같습니다.

 

코드는 별다르게 어려운 코드가 없어서 참고로만 올립니다.

 

#include <OBD2UART.h>
#include <Adafruit_NeoPixel.h>
#define LED_PIN 15  // 제어선 번호
#define LED_COUNT 60  // LED개수
#define GEAR_SHIFT 3000
#define PHOTO_PIN A0
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
COBD obd;

int rpm;            // 자동차 RPM
int led_end;        // RPM에 따라 불이 들어오는 LED 개수
int light;          // 포토센서 측정값
int brtn = 100;     // LED 기본밝기 100으로 설정 (최대 255)

// LED 색상 설정 {LED번호, RED, GREEN, BLUE}
int color[60][4] = {{0, 0, 0, 255},
                    {1, 0, 0, 255},
                    {2, 0, 0, 245},
                    {3, 0, 0, 235},
                    {4, 0, 0, 225},
                    {5, 0, 0, 215},
                    {6, 0, 0, 205},
                    {7, 0, 0, 195},
                    {8, 0, 0, 185},
                    {9, 0, 0, 175},
                    {10, 0, 5, 165},
                    {11, 0, 15, 155},
                    {12, 0, 25, 145},
                    {13, 0, 35, 135},
                    {14, 0, 45, 125},
                    {15, 0, 55, 115},
                    {16, 0, 65, 105},
                    {17, 0, 75, 95},
                    {18, 0, 85, 85},
                    {19, 0, 95, 75},
                    {20, 0, 105, 65},
                    {21, 0, 115, 55},
                    {22, 0, 125, 45},
                    {23, 0, 135, 35},
                    {24, 0, 145, 25},
                    {25, 0, 155, 15},
                    {26, 0, 165, 5},
                    {27, 0, 175, 0},
                    {28, 0, 185, 0},
                    {29, 0, 195, 0},
                    {30, 0, 205, 0},
                    {31, 0, 195, 0},
                    {32, 0, 185, 0},
                    {33, 0, 175, 0},
                    {34, 0, 165, 0},
                    {35, 5, 155, 0},
                    {36, 15, 145, 0},
                    {37, 25, 135, 0},
                    {38, 35, 125, 0},
                    {39, 45, 115, 0},
                    {40, 55, 105, 0},
                    {41, 65, 95, 0},
                    {42, 75, 85, 0},
                    {43, 85, 75, 0},
                    {44, 95, 65, 0},
                    {45, 105, 45, 0},
                    {46, 115, 35, 0},
                    {47, 125, 25, 0},
                    {48, 135, 15, 0},
                    {49, 145, 5, 0},
                    {50, 155, 0, 0},
                    {51, 165, 0, 0},
                    {52, 175, 0, 0},
                    {53, 185, 0, 0},
                    {54, 195, 0, 0},
                    {55, 205, 0, 0},
                    {56, 215, 0, 0},
                    {57, 225, 0, 0},
                    {58, 235, 0, 0},
                    {59, 245, 0, 0}};

void setup()
{
  Serial.begin(9600);
  strip.begin();                   // 네오픽셀 제어 시작
  strip.setBrightness(brtn);       // 밝기 세팅
  welcome();                       // 웰컴 세리모니
  
  obd.begin();                     // obd아답터 연결
  while (!obd.init());   
}

void loop()
{
  // RPM, 포토센서 값 측정
  obd.readPID(PID_RPM, rpm);
  light = analogRead(PHOTO_PIN);

  // 포토센터 측정값이 따라 LED 밝기 세팅 (포토센서는 밝을수록 측정값이 낮음)
  if (light < 300)
    brtn = 205;
  else if (light >= 300 && light < 700)
    brtn = 100;
  else
    brtn = 50;
    
  strip.setBrightness(brtn);

  //rpm에 따라 LED를 켜야할 개수 구하기
  led_end = map(rpm, 0, GEAR_SHIFT, 0, LED_COUNT);

  // rpm이 기어변속 세팅값보다 큰 경우 gearShiftAlert을 실행
  // 그렇지 않은 경우는 showrpm을 실행
  if (rpm > GEAR_SHIFT)
    gearShiftAlert();
  else
    showRPM();

  // 동작 모니터용으로 시리얼 포트로 값 내보내기
  Serial.print(rpm);
  Serial.print(" / ");
  Serial.println(light);
}

// RPM이 변속구간을 넘어가는 경우에 스트립 전체가 빨간색으로 깜빡임
void gearShiftAlert()
{
  strip.setBrightness(brtn+50);    // 밝기를 50 높임
  
  for(int i=0; i<LED_COUNT; i++)
    strip.setPixelColor(i, 255, 0, 0);
  strip.show();
}

// 변속구간 이내 일때 RPM에 따라 LED켜기
void showRPM()
{
  for (int i=0; i<led_end; i++)
  {
    strip.setPixelColor(color[i][0], color[i][1], color[i][2], color[i][3]);
  }

  // 불이 켜지지 않는 LED는 검정으로 세팅 (불을 안 켜도록)
  for (int i=led_end; i<LED_COUNT; i++)
  {
    strip.setPixelColor(i, 0, 0, 0);
  }
  strip.show();
}
// 시동시 웰컴 세레모니
void welcome()
{
  for(long firstPixelHue = 0; firstPixelHue < 5*65536; firstPixelHue += 256) {
    for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
      int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
    }
    strip.show(); // Update strip with new contents
  }
}