Joystick to blink led for 15 seconds

Hi all, first post here after spending many hours searching for a solution.

What I am trying to achieve: I want to replace all the electrics of my motorcycle (old bike) to be controlled by an Arduino. On the handlebar, I will have a joystick with the following output:

Left = Left turn signal
Right = Right turn signal
Up = HighBeam
Down = Lowbeam
Push = Horn

The particular problem I have is that I want the turn light to blink for 15 seconds on a single touch of the joystick (not sustained touch, kind of a toggle function). I either can make it last the 15 seconds on without blinking or I can make it blink without staying on the 15 seconds.

This is my code only for the left turn signal, this one makes it blink but I don’t know how to mix the function to make it blink for 15 seconds.

Any help will be appreciated.

Thanks.

const int turnleft = 13;
int turnleftstate = LOW;
const int X_pin = 0;
const int Y_pin = 1;
unsigned long previousMillis = 0;
unsigned long interval = 500;

void setup() {
  
  pinMode(turnleft, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  
  int position_x = analogRead(X_pin);
  int position_y = analogRead(Y_pin);
  unsigned long currentMillis = millis();
  
if (position_y <=500 && currentMillis - previousMillis > interval) {
  previousMillis = currentMillis;
  if (turnleftstate == LOW)
    turnleftstate = HIGH;
  else
    turnleftstate = LOW;
  digitalWrite (turnleft, turnleftstate);
 }

}

You need to have two variables for state. One to record the fact that the joystick had been pushed and you are now within the 15s window, or not. The second to record whether the turn light is on or off at that moment. You will also need two more unsigned long variables to capture the value of millis(). When the state variables change, you update the unsigned longs, so you know when it's time for the state to change again. One unsigned long will capture the time at the start of the 15s period. The other will capture the time at which the turn light was switched on or off.

I like the idea, but I think you should think long and hard about the ergonomics of it. You haven't got time to look at a control and think about manipulating it. I would urge you to look at many different motorcycles and maybe use some of theirs. Secondhand / from a breaker's yard it shouldn't cost a lot, but may save your life.

In terms of indicators, my BMW K1200LT will time out as you suggest after 15 seconds, after travelling about 250 yards, or on turning the handlebars past a defined point.

Thanks Paul. It is working now.

AJL, I am really not concerned about control disposition or ergonomics. I have several bikes, from 1971 to a 2018 K1600B. All have different controls and I have never had a problem. It's not like I am moving the brake pedal.

I also believe the ergonomics and disposition will be fantastic with the joystick. It's very logical if you think about it. I wonder why no manufacturer has come out with something like this.

Thanks for sharing your concern.

Thanks Paul. It is working now.

The best way to show your gratitude is to post the working code, so that others searching the forum in the future can find it and benefit from your solution, instead of...

spending many hours searching for a solution

Here it is.

It’s not finished yet. Currently, it handles the blinkers, horn and highbeam… I am a slow learner with limited time… will get there.

const int horn = 10;
const int hornSW = 2;

const int turnleft = 8;
int turnleftstate = LOW;
int turnleftJ = LOW;
int turnleftsec = LOW;

const int turnright = 9;
const int PRUEBA = 12;
int turnrightstate = LOW;
int turnrightJ = LOW;
int turnrightsec = LOW;

int highbeam = 11;
int statehighbeam = LOW;  
int readinghighbeam; 
int previoushighbeam = LOW; 
int highbeamJ;

const int lowbeam = 7;

const int X_pin = 1;
const int Y_pin = 0;
unsigned long previousMillisleft = 0;
unsigned long previousMillisright = 0;
unsigned long interval = 500;
unsigned long previousMillisB = 0;
unsigned long blinkerinterval = 15000;


// ---- --------------------------
 

void setup() {
  
  pinMode(horn, OUTPUT);
  pinMode(hornSW, INPUT_PULLUP);


  pinMode(turnleft, OUTPUT);
  pinMode(turnleftJ, OUTPUT);
  pinMode(turnleftsec,OUTPUT);

  pinMode(turnright, OUTPUT);
  pinMode(turnrightJ, OUTPUT);
  pinMode(turnrightsec,OUTPUT);

  pinMode(highbeam, OUTPUT);

  pinMode(lowbeam, OUTPUT);
 

  Serial.begin(9600);
}

void loop() {
  
  int position_x = analogRead(X_pin);
  int position_y = analogRead(Y_pin);
  unsigned long currentMillisleft = millis();
  unsigned long currentMillisright = millis();

  static unsigned char ledStateleft = LOW; 
  static unsigned char buttonStateleft = LOW;
  static unsigned char lastButtonStateleft = LOW;
  static unsigned long ledCameOnleft = 0;

  static unsigned char ledStateright = LOW; 
  static unsigned char buttonStateright = LOW;
  static unsigned char lastButtonStateright = LOW;
  static unsigned long ledCameOnright = 0;
  
  int switch_status = digitalRead(hornSW);

  //static unsigned char highbeam = LOW;

  //static unsigned char lowbeam = LOW;
    
  Serial.print("Switch:  ");
  Serial.print(digitalRead(hornSW));
  Serial.print("\n");
  Serial.print("X-axis: ");
  Serial.print(analogRead(X_pin));
  Serial.print("\n");
  Serial.print("Y-axis: ");
  
  Serial.println(analogRead(Y_pin));
  Serial.print("\n\n");
  delay(1);


// ================Start LOWBEAM ============= 






//================ End LOWBEAM =========
//================ Start HIGHBEAM ==========


  
if (position_x >=900) {
  highbeamJ = HIGH;
  
}
  else {
  highbeamJ = LOW;
  
  }

  readinghighbeam = highbeamJ;
  if (readinghighbeam == HIGH && previoushighbeam == LOW) {
    statehighbeam = !statehighbeam;
  }

  digitalWrite(highbeam, statehighbeam);
  Serial.println(readinghighbeam);
  previoushighbeam = readinghighbeam;

  

// ==============End HIGBEAM ============
// ========= Start HORN =================

if (switch_status == 0){
  digitalWrite (horn, HIGH);

 }
 else {
  digitalWrite (horn, LOW);
}

//========= End HORN ===================



//=========== Loop RIGHT Turn signal
// -------- Joystick prende turnlefJ 

if (position_y <=100) {
  turnrightJ = HIGH;
  ledStateleft = LOW;
  ledCameOnleft = millis();
  digitalWrite (turnleft, LOW);

 }
 else {
  turnrightJ = LOW;
 }

// ----------End joystick

 // ---------- 5 sec on
 // If the LED has been on for at least 5 seconds then turn it off.
  if(ledStateright == HIGH)
  {
    if(millis()-ledCameOnright > blinkerinterval)
    {
      digitalWrite(turnrightsec,LOW);
      ledStateright = LOW;
      digitalWrite (turnleftJ, LOW); //
    }
  }

  // If the button's state has changed, then turn the LED on IF it is not on already.
  buttonStateright = turnrightJ;
  if(buttonStateright != lastButtonStateright)
  {
    lastButtonStateright = buttonStateright;
    if((buttonStateright == LOW) && (ledStateright == LOW))
    {
      turnrightsec = HIGH;
      ledStateright = HIGH;
      ledCameOnright = millis();
    }
  }

  // --------- End 5 sec on

 if (ledStateright == HIGH) {
  if (currentMillisright - previousMillisright > interval) {
   previousMillisright = currentMillisright;
  if (turnrightstate == LOW)
    turnrightstate = HIGH;
  else
    turnrightstate = LOW;
  digitalWrite (turnright, turnrightstate);
 }
 }
 //============ End RIGHT Turn Signal

//=========== Loop LEFT Turn signal
// -------- Joystick prende turnlefJ 

if (position_y >=970) {
  turnleftJ = HIGH;
  ledStateright = LOW;
  ledCameOnright = millis();
  digitalWrite (turnright, LOW);
 }
 else {
  turnleftJ = LOW;
 }

// ----------End joystick

 // ---------- 5 sec on
 // If the LED has been on for at least 5 seconds then turn it off.
  if(ledStateleft == HIGH)
  {
    if(millis()-ledCameOnleft > blinkerinterval)
    {
      digitalWrite(turnleftsec,LOW);
      ledStateleft = LOW;
    }
  }

  // If the button's state has changed, then turn the LED on IF it is not on already.
  buttonStateleft = turnleftJ;
  if(buttonStateleft != lastButtonStateleft)
  {
    lastButtonStateleft = buttonStateleft;
    if((buttonStateleft == LOW) && (ledStateleft == LOW))
    {
      turnleftsec = HIGH;
      ledStateleft = HIGH;
      ledCameOnleft = millis();
    }
  }

  // --------- End 5 sec on

 if (ledStateleft == HIGH) {
  if (currentMillisleft - previousMillisleft > interval) {
   previousMillisleft = currentMillisleft;
  if (turnleftstate == LOW)
    turnleftstate = HIGH;
  else
    turnleftstate = LOW;
  digitalWrite (turnleft, turnleftstate);
 }
 }
 //============ End Left Turn Signal

  
 }

Well done for getting this far. +1 karma for posting your code. Your code seems quite complicated, but that's normal for a beginner. It takes experience & skill to spot opportunities to simplify code. But as an example, signalling left and signalling right are identical operations, except for the joystick direction and the output pin. And the two operations never run at the same time (unless you want a hazard signal, but even then, you don't want your hazard signals to blink out of sync). So most of the code lines, variables etc that control left signalling and right signalling are duplicated in your code, where they could be shared.

Thanks Paul. I really appreciate it.

For sure there has to much better ways of building this code... I am just afraid beak it.

For me the most important flaw is that if I cancel right turn with left turn (or viceversa) I break the sequence of previousmillis and it might end up the 15 second period leaving the let on HIGH. Well, I am guessing that is the reason.

I am just afraid beak it.

There is no risk. Just take a backup of your sketch now (save as... and give a new name). Then you can amend and if you do break it, just go back to the previous saved version.