Brake light for PPM remote and vesc

Hi All

I decided to buid a system that light a red back light to make night and day eskate trip safer.

This system flash red light all the time (in order to be seen in the night) and light full red light when you brake (in order that your friend following you not collapse in your back when you brake).

I have seen this post (Brake lights and Turn signals *Finally* for ANY ESC! ), but buying 150$ system fully adaptable for many system and with many light was not really acceptable for me, so I’ve build this 10$ system that is suitable for PPM remote command.

To summup this project, the cost is ridiculously low (10$), the size is very tiny 2X3 cm and fully supplied by Vesc 3 wire for remote control (5V-200mA).

PART LIST :

CIRCUIT : Consumption of 200mA when light is ON, soi t is enought for vesq 5 V supply to give current for radio receptor, digispark, Led light and output amplifier CIRCUIT_CLC

SOFTWARE : For digispark library installation i have follow this tutorial :

For the software I have been mostly inspirated by

Finally i have just add some modification to make the brake light flash when the skate is NOT braking, and when the eskate brake the brake light stops flashing and fully light.

Here the code :

#define THROTTLE_SIGNAL_IN 0 // INTERRUPT 0 = DIGITAL PIN 2 - use the interrupt number in attachInterrupt #define THROTTLE_SIGNAL_IN_PIN 2 // INTERRUPT 0 = DIGITAL PIN 2 - use the PIN number in digitalRead #define BRAKE_SIGNAL_OUT 1 #define NEUTRAL_THROTTLE 1500 // this is the duration in microseconds of neutral throttle on an electric RC Car #define PERIOD_BLINK 1000 // #define DURATION_BLINK 200 //

volatile int nThrottleIn = NEUTRAL_THROTTLE; // volatile, we set this in the Interrupt and read it in loop so it must be declared volatile volatile unsigned long ulStartPeriod = 0; // set in the interrupt volatile boolean bNewThrottleSignal = false; // set in the interrupt and read in the loop volatile boolean b_ActivateBlinkBrake = true; // Active blink brake light functionality volatile boolean b_EnableBlinkBrake = false; // Brake light show brake info in priority volatile unsigned long u_Cpt_Interrupt = 0; volatile boolean b_BrakeLightValue = false;

// we could use nThrottleIn = 0 in loop instead of a separate variable, but using bNewThrottleSignal to indicate we have a new signal // is clearer for this first example

void setup() { // tell the Arduino we want the function calcInput to be called whenever INT0 (digital pin 2) changes from HIGH to LOW or LOW to HIGH // catching these changes will allow us to calculate how long the input pulse is attachInterrupt(THROTTLE_SIGNAL_IN,calcInput,CHANGE); pinMode(BRAKE_SIGNAL_OUT, OUTPUT); //Serial.begin(9600); }

void loop() { // if a new throttle signal has been measured, lets print the value to serial, if not our code could carry on with some other processing if(bNewThrottleSignal) { //Serial.println(nThrottleIn);

// set this back to false when we have finished // with nThrottleIn, while true, calcInput will not update // nThrottleIn

u_Cpt_Interrupt++;

if(nThrottleIn <NEUTRAL_THROTTLE) { //Throttle BRAKE //Disable Blink light b_EnableBlinkBrake = false;

// Full light on brake output
b_BrakeLightValue = true;
//digitalWrite(BRAKE_SIGNAL_OUT,HIGH);

} else { b_EnableBlinkBrake = true; //Throttle NOT BRAKE b_BrakeLightValue = false; //digitalWrite(BRAKE_SIGNAL_OUT,LOW); } bNewThrottleSignal = false; }

//Manage blink light if(b_ActivateBlinkBrake && b_EnableBlinkBrake) { //Interrupt normally happen every 20ms if(u_Cpt_Interrupt * 20 > PERIOD_BLINK) { b_BrakeLightValue = false; if(u_Cpt_Interrupt * 20 < PERIOD_BLINK + DURATION_BLINK ) { b_BrakeLightValue = true; } else { //Reset cpt for new cycle u_Cpt_Interrupt = 0; } } } else { //Reset cpt for new cycle u_Cpt_Interrupt = 0; }

//Manage Brake Light output if(b_BrakeLightValue) { digitalWrite(BRAKE_SIGNAL_OUT,HIGH); } else { digitalWrite(BRAKE_SIGNAL_OUT,LOW); }

// other processing … }

void calcInput() { // if the pin is high, its the start of an interrupt if(digitalRead(THROTTLE_SIGNAL_IN_PIN) == HIGH) { // get the time using micros - when our code gets really busy this will become inaccurate, but for the current application its // easy to understand and works very well ulStartPeriod = micros(); } else { // if the pin is low, its the falling edge of the pulse so now we can calculate the pulse duration by subtracting the // start time ulStartPeriod from the current time returned by micros() if(ulStartPeriod && (bNewThrottleSignal == false)) { nThrottleIn = (int)(micros() - ulStartPeriod); ulStartPeriod = 0;

  // tell loop we have a new signal on the throttle channel
  // we will not update nThrottleIn until loop sets
  // bNewThrottleSignal back to false
  bNewThrottleSignal = true;
}

} }

4 Likes

I really like this. If I were to make one, is there something special about the BC547 transistor or can it be any NPN transistor?

Hi man, Nothing special about the transistor. For this circuit use pnp transistor that doesn’t drive to much current from microship output. (Almost every pnp smala transistor should be ok)

1 Like

This is awesome! I plan on hooking this up to an xkglow RGB controller for my boards lights. It has a signal wire that when triggered you can set all LEDs to preform a certain pattern (strobe red for example)

Can you post your code in a more readable format? I think when you pasted it here it got a tad messed up and I am stuggling to read it.

Obviously I will be able to simplify your code a bit, as most of the configuration will be done via the app (bluetooth). Would you have any reccomendations for simply triggering a remote wire (Usually 12v) when applying the brakes?

Autoformating on post is not easy to handle for programming…

here the code :

#define THROTTLE_SIGNAL_IN 0
#define THROTTLE_SIGNAL_IN_PIN 2

#define BRAKE_SIGNAL_OUT 1

#define NEUTRAL_THROTTLE 1500

#define PERIOD_BLINK 1000

#define DURATION_BLINK 200

volatile int nThrottleIn = NEUTRAL_THROTTLE;

volatile unsigned long ulStartPeriod = 0;

volatile boolean b_ActivateBlinkBrake = true;

volatile boolean b_EnableBlinkBrake = false;

volatile unsigned long u_Cpt_Interrupt = 0;

volatile boolean b_BrakeLightValue = false;

void setup() {

attachInterrupt(THROTTLE_SIGNAL_IN,calcInput,CHANGE);

pinMode(BRAKE_SIGNAL_OUT, OUTPUT);

}

void loop() {

if(bNewThrottleSignal) {

u_Cpt_Interrupt++;

if(nThrottleIn <NEUTRAL_THROTTLE) {

b_EnableBlinkBrake = false;


b_BrakeLightValue = true;

} else { b_EnableBlinkBrake = true;

b_BrakeLightValue = false;

}

bNewThrottleSignal = false;

}

//Manage blink light

if(b_ActivateBlinkBrake && b_EnableBlinkBrake) {

if(u_Cpt_Interrupt * 20 > PERIOD_BLINK)
{
  b_BrakeLightValue = false;

  if(u_Cpt_Interrupt * 20 < PERIOD_BLINK + DURATION_BLINK )
  {

    b_BrakeLightValue = true;

  }
  else
  {

    u_Cpt_Interrupt = 0;

  }
}

}

else {

 //Reset cpt for new cycle
 u_Cpt_Interrupt = 0;

}

//Manage Brake Light output

if(b_BrakeLightValue) {

digitalWrite(BRAKE_SIGNAL_OUT,HIGH);

} else {

digitalWrite(BRAKE_SIGNAL_OUT,LOW); 

}

}

void calcInput() {

if(digitalRead(THROTTLE_SIGNAL_IN_PIN) == HIGH) {

ulStartPeriod = micros();

} else {

if(ulStartPeriod && (bNewThrottleSignal == false))
{

  nThrottleIn = (int)(micros() - ulStartPeriod);

  ulStartPeriod = 0;

  bNewThrottleSignal = true;

}

}

}

Heuuu … for ppm remote signal, It’s 5V pulse with period around 20ms and duration between 1ms and 2ms.

Neutral throttle is around 1,5 ms pulse duration, Full throttle is around 2ms duration pulse, Full brake is around 1ms pulse duration.