Help writing a simple program to use with a gear shifter for racing games

I need some help writing a simple program for a games console controller I have built.

SOME BACKGROUND INFO ON MY PROJECT

It is a gear changer for racing games.

It has 8 buttons on it (for gears 1-7 and reverse).

For reference only it looks a bit like this:

It will link to a steering wheel that currently has two simple buttons, one for 'gear up' ( going up a gear) and another for 'gear down' ( going down a gear). e.g If I was in 2nd gear and wanted to go into 7th gear I would have to press the 'gear up' button 5 times.

So the new controller I have built will have 8 buttons going in to the arduino and two outputs from the arduino that will be wired to each of the 2 buttons on the steering wheel.

THE PART I NEED HELP WITH

So I need help writing a program for Ardunio that will be able to work out something like this:

  1. Firstly it would need to work out what the current gear is (it will always start at 0 for neutral). 0
  2. Then when a gear is selected on the controller (e.g 5th gear) it would need to work out if it needed to go up or down gears. UP
  3. Then it would need to workout how many gears it would need to move. 5
  4. Then it would need to send the correct number of pulses to the correct output. 5 pulses to the 'Gear UP' output
  5. Then it would need to update the variable that holds what gear it is now in. 5

I hope that makes sense and I hope you can help.

That sounds reasonably straight forward and I don't see any reason why you couldn't develop that yourself. You can always ask for advice here if you get stuck on a problem. If you really want somebody to do the work for you, you should be asking in the Gigs and Collaborations section. Note that most people would expect to be paid for working for you.

Dead simple, just needs a little thought and time (yours that is :)).

When you have something post it if there's a problem.


Rob

Is this for PC or console?

The shifter you have, up shift switch / down shift switch is called a sequential shifter. Does it use a switch to select neutral or do you have to shift down to neutral? The racing games I play use a switch to select neutral when using a sequential shifter.

I'm not looking for someone to program it for me, i'm just looking for some pointers in the right direction.

Its a H-Pattern shifter for a console. Using arduino to convert the selected gear to a series of gear up or gear down messages, replacing the paddle shifters.

I had a go at coding it but i'm getting errors, I will post it up to see if you can spot where i'm going wrong and if I am even on the right lines??

I have replaced the two outputs with LEDS to make it easier to test and put in a delay between blinks so I can see the blinks. I guess these will need to be removed or severely reduced for the final program.

// set pin numbers:
const int buttonPin1 = 2;     
const int buttonPin2 = 3;
const int buttonPin3 = 4;
const int buttonPin4 = 5;
const int buttonPin5 = 6;
const int buttonPin6 = 7;

const int ledPin1 =  13;      
const int ledPin2 =  12;

// variables will change:
int buttonState1 = 0;         
int buttonState2 = 0;  
int buttonState3 = 0;  
int buttonState4 = 0;  
int buttonState5 = 0;  
int buttonState6 = 0;  
int gearnumber = 0; 
int geardifference = 0;
int gearup = 0; 
int geardown = 0;

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin1, OUTPUT);      
  pinMode(ledPin2, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin1, INPUT);  
  pinMode(buttonPin2, INPUT); 
  pinMode(buttonPin3, INPUT);
  pinMode(buttonPin4, INPUT);
  pinMode(buttonPin5, INPUT);
  pinMode(buttonPin6, INPUT);  
}

void loop(){
  // read the state of the pushbutton value:
  buttonState1 = digitalRead(buttonPin1);
  buttonState2 = digitalRead(buttonPin2);
  buttonState3 = digitalRead(buttonPin3);
  buttonState4 = digitalRead(buttonPin4);
  buttonState5 = digitalRead(buttonPin5);
  buttonState6 = digitalRead(buttonPin6);


  if (buttonState1 == HIGH) {  
          if (gearnumber > 1) {
                 gearup = gearnumber - 1
                         gearupchanger(gearup, 1);
          }   
          if (gearnumber < 1) {
                 geardown = 1 - gearnumber
                         geardownchanger(geardown, 1);
          }
  } 
  if (buttonState2 == HIGH) {     
          if (gearnumber > 2) {
                 gearup = gearnumber - 2
                         gearupchanger(gearup, 2);
          }
          if (gearnumber < 2) {
                 geardown = 2 - gearnumber
                         geardownchanger(geardown, 2);
          }
  } 
  if (buttonState3 == HIGH) {     
          if (gearnumber > 3) {
                 gearup = gearnumber - 3
                         gearupchanger(gearup, 3);
          }
          if (gearnumber < 3) {
                 geardown = 3 - gearnumber
                         geardownchanger(geardown, 3);
          }
  } 
  if (buttonState4 == HIGH) {     
          if (gearnumber > 4) {
                 gearup = gearnumber - 4
                         gearupchanger(gearup, 4);
          }
          if (gearnumber < 4) {
                 geardown = 4 - gearnumber
                         geardownchanger(geardown, 4);
          }
  } 
  if (buttonState5 == HIGH) {     
          if (gearnumber > 5) {
                 gearup = gearnumber - 5
                         gearupchanger(gearup, 5);
          }
          if (gearnumber < 5) {
                 geardown = 5 - gearnumber
                         geardownchanger(geardown, 5);
          }
  } 
  if (buttonState6 == HIGH) {     
          if (gearnumber > 6) {
                 gearup = gearnumber - 6
                         gearupchanger(gearup, 6);
          }
          if (gearnumber < 6) {
                 geardown = 6 - gearnumber
                         geardownchanger(geardown, 6);
          }
  } 
}

  void gearupchanger(int numChanges, int gear){
    for(int i=0; i<numChanges; i++){
      digitalWrite(ledPin1, HIGH);
      delay(1000);
      digitalWrite(ledPin1, LOW);
      delay(1000);
    }
        gearnumber = gear
  }

  void geardownchanger(int numChanges, int gear){
    for(int i=0; i<numChanges; i++){
      digitalWrite(ledPin2, HIGH);
      delay(1000);
      digitalWrite(ledPin2, LOW);
      delay(1000);
    }
        gearnumber = gear
  }
  if (gearnumber < 3) {
                 geardown = 3 - gearnumber
                         geardownchanger(geardown, 3);
          }

You're missing semi colons in all the places like the above.

Should be.

  if (gearnumber < 3) {
                 geardown = 3 - gearnumber;
                 geardownchanger(geardown, 3);
          }

The reason I asked if you have a switch for neutral is that would be an easy way to always make sure the state of your Arduino and the state of the game matched. You could go neutral then find the gear you want. Might be clumsy in actual game play though.

Thanks that sorted out the errors.

I'm 99% there now, I just need to look in more depth at how the consoles handle reverse gear and neutral.

Here is the code, incase anyone else is interested:

const int buttonPin1 = 2;     
const int buttonPin2 = 3;
const int buttonPin3 = 4;
const int buttonPin4 = 5;
const int buttonPin5 = 6;
const int buttonPin6 = 7;
const int buttonPin7 = 8;
const int buttonPin8 = 9;
const int ledPin1 =  13;      
const int ledPin2 =  12;
int buttonState1 = 0;         
int buttonState2 = 0;  
int buttonState3 = 0;  
int buttonState4 = 0;  
int buttonState5 = 0;  
int buttonState6 = 0;  
int buttonState7 = 0; 
int buttonState8 = 0; 
int gearnumber = 0; 
int geardifference = 0;
int gearup = 0; 
int geardown = 0;

void setup() {
  pinMode(ledPin1, OUTPUT);      
  pinMode(ledPin2, OUTPUT);
  pinMode(buttonPin1, INPUT);  
  pinMode(buttonPin2, INPUT); 
  pinMode(buttonPin3, INPUT);
  pinMode(buttonPin4, INPUT);
  pinMode(buttonPin5, INPUT);
  pinMode(buttonPin6, INPUT);  
  pinMode(buttonPin7, INPUT); 
  pinMode(buttonPin8, INPUT); 
}
void loop(){
  buttonState1 = digitalRead(buttonPin1);
  buttonState2 = digitalRead(buttonPin2);
  buttonState3 = digitalRead(buttonPin3);
  buttonState4 = digitalRead(buttonPin4);
  buttonState5 = digitalRead(buttonPin5);
  buttonState6 = digitalRead(buttonPin6);
  buttonState7 = digitalRead(buttonPin7);
  buttonState8 = digitalRead(buttonPin8);

  if (buttonState1 == HIGH) {  
          if (gearnumber > 1) {
                 geardown = gearnumber - 1;
                         geardownchanger(geardown, 1);
          }   
          if (gearnumber < 1) {
                 gearup = 1 - gearnumber;
                         gearupchanger(gearup, 1);
          }
  } 
  if (buttonState2 == HIGH) {     
          if (gearnumber > 2) {
                 geardown = gearnumber - 2;
                         geardownchanger(geardown, 2);
          }
          if (gearnumber < 2) {
                 gearup = 2 - gearnumber;
                         gearupchanger(gearup, 2);
          }
  } 
  if (buttonState3 == HIGH) {     
          if (gearnumber > 3) {
                 geardown = gearnumber - 3;
                         geardownchanger(geardown, 3);
          }
          if (gearnumber < 3) {
                 gearup = 3 - gearnumber;
                         gearupchanger(gearup, 3);
          }
  } 
  if (buttonState4 == HIGH) {     
          if (gearnumber > 4) {
                 geardown = gearnumber - 4;
                         geardownchanger(geardown, 4);
          }
          if (gearnumber < 4) {
                 gearup = 4 - gearnumber;
                         gearupchanger(gearup, 4);
          }
  } 
  if (buttonState5 == HIGH) {     
          if (gearnumber > 5) {
                 geardown = gearnumber - 5;
                         geardownchanger(geardown, 5);
          }
          if (gearnumber < 5) {
                 gearup = 5 - gearnumber;
                         gearupchanger(gearup, 5);
          }
  } 
  if (buttonState6 == HIGH) {     
          if (gearnumber > 6) {
                 geardown = gearnumber - 6;
                         geardownchanger(geardown, 6);
          }
          if (gearnumber < 6) {
                 gearup = 6 - gearnumber;
                         gearupchanger(gearup, 6);
          }
  } 
  if (buttonState7 == HIGH) {     
          if (gearnumber > 7) {
                 geardown = gearnumber - 7;
                         geardownchanger(geardown, 7);
          }
          if (gearnumber < 7) {
                 gearup = 7 - gearnumber;
                         gearupchanger(gearup, 7);
          }
  } 
  if (buttonState8 == HIGH) {     
          if (gearnumber > 8) {
                 geardown = gearnumber - 8;
                         geardownchanger(geardown, 8);
          }
          if (gearnumber < 8) {
                 gearup = 8 - gearnumber;
                         gearupchanger(gearup, 8);
          }
  } 
}

  void gearupchanger(int numChanges, int gear){
    for(int i=0; i<numChanges; i++){
      digitalWrite(ledPin1, HIGH);
      delay(1000);
      digitalWrite(ledPin1, LOW);
      delay(1000);
    }
        gearnumber = gear;
  }
  void geardownchanger(int numChanges, int gear){
    for(int i=0; i<numChanges; i++){
      digitalWrite(ledPin2, HIGH);
      delay(1000);
      digitalWrite(ledPin2, LOW);
      delay(1000);
    }
        gearnumber = gear;
  }

Lots of variables with the same name and a number on the end almost always indicates that an array could/should be used to make the code simpler. Why use 8 variables when an array with 8 levels and a for loop could have been used ? Something like this perhaps.

for (int button = 1; button < 9; button++)
{
  if (buttonState[button] == HIGH) 
  {  
    if (gearnumber >  button) 
    {
      geardown = gearnumber - button;
      geardownchanger(geardown, button);
    }
  }
}

You will need to adapt this for your own requirements but I am sure that you can see the principle.

Thanks for the tip, i'm new to arrays, I will take a look and update me code once i've figured it out.

Thanks for the help, i'm learning lots.

Here's a refactored version

int buttonPin [8] = {
  2,3,4,5,6,7,8,9};

const int ledPin1 =  13;      
const int ledPin2 =  12;

int currentGear = 0;

void setup() {
  pinMode(ledPin1, OUTPUT);      
  pinMode(ledPin2, OUTPUT);
  for (int i = 0; i < 8; i++)
    pinMode(buttonPin[i], INPUT);  
}

void loop(){
  int butPressed = currentGear;

  for (int i = 0; i < 8; i++) {
    if (digitalRead(buttonPin[i]) == HIGH) {
      butPressed = i + 1;
      break;
    }
  }
  if (currentGear < butPressed)
    gearupchanger(butPressed - currentGear);

  if (currentGear > butPressed)
    geardownchanger(currentGear - butPressed);

  currentGear = butPressed;

}

void gearupchanger(int numChanges){
  for(int i=0; i<numChanges; i++){
    digitalWrite(ledPin1, HIGH);
    delay(1000);
    digitalWrite(ledPin1, LOW);
    delay(1000);
  }
}
void geardownchanger(int numChanges){
  for(int i=0; i<numChanges; i++){
    digitalWrite(ledPin2, HIGH);
    delay(1000);
    digitalWrite(ledPin2, LOW);
    delay(1000);
  }
}

It compiles but I can verify it does exactly what you want. However I'm just trying to show what UKHeliBob said, use arrays and loops, there's still room for improvement but this is the sort of thing you should (arguably) aim for, look for repetitive code, hard-coded numbers etc and see if a loop, an array and variables based on the loop counter are a better way to go.

EDIT: Not bebouncing here, that will cause problems, a poor man's way to do that is to add a 50mS delay in the loop if there's nothing else that needs doing.


Rob

Thanks Rob, just tested it and it all works fine. And I now understand arrays.

I just need to sort out neutral and reverse and it will be finished.

If you are using an array why not make neutral gear[0] and put reverse at the end?

Also, are you going to just have buttons or are you going to make a shifter of some sort? With a shifter of sorts a normal way for them to work is that a gear is held as long as a switch is closed. As soon as no switches are closed it goes to neutral. Which closely mimics a standard transmission. That would mean not needing a button for neutral. How do you find neutral now with the controller you want to hack?

I've had a play on a few of the racing games but not all of the ones i'm looking at yet.

Forza which is the main game i'm looking at, does not have a neutral, it goes straight to reverse:
R, 1, 2, 3, 4, 5, 6, 7 etc etc.....

I came across a problem though.
If you have a crash or slow down to under 6mph (which won't happen often) then switch down a gear it puts you straight into 1st gear.

under 6mph (which won't happen often)

I would think < 6MPH would be common.


Rob

Only when you have a crash that almost stops the car dead, otherwise any time your doing that speed your already in first gear e.g at the start of the race.

Under breaking etc you very rarely drop below 30 mph and never below 15 mph.

I could solve the issue by having another button that puts it into 1st gear, whenever it physically goes into neutral on the gearstick. (would have to test if it slowed down gear changes)

Otherwise I could just get into the habit of making sure I put it into 1st whenever I have a bad crash (which is usually my reaction anyway). But I will build it and test both anyway.

ha ha, for some reason I thought we were talking about a golf cart (that must be another thread :)), 6MPH is probably the max for that, but for racing as you say, if you're going that slow you've probably crashed.


Rob

I could solve the issue by having another button that puts it into 1st gear, whenever it physically goes into neutral on the gearstick. (would have to test if it slowed down gear changes)

Otherwise I could just get into the habit of making sure I put it into 1st whenever I have a bad crash (which is usually my reaction anyway). But I will build it and test both anyway.

If you are worried about how many switches you are reading and maybe slowing it down, don't. I did a similar project and did some timing tests. I found that my sketch was reading somewhere on the order of 76,000 reads per second. It only reads switches and is non-blocking. I used a Leonardo because I'm a PC racing guy and it was easy to do with keyboard control.

Your first solution appears best to me. The second one would attempt to downshift from whatever gear you are in back to first. If the game is in first you need a quick easy way to resynch the state of Arduino with the state of the game.