DIY G25 shifter interface with H-pattern, sequential and handbrake modes
20 20

211 posts in this topic

On 28/01/2015 at 10:02 PM, xxValiumxx said:

LIES!  Who is JPlays?  I assure you, that's not me.  I'm glad people are finding this to have some use.

 

I just modified the shifter itself to have 2 extra buttons.  In theory, I'm sure 3 are possible, but I didn't bother/couldn't find the correct point to attach a third.

 

https://poweredbyredstone.com/shifter-upgrades/

@xxValiumxx: Sorry for the confusion, I really thought you were JPlays on Twitch   :blink:

I assume you had to adapt the program in the Teensy to output the additional buttons to the virtual joystick interface. Could you please publish your modified code/sketch ?

Edited by pascalh

Share this post


Link to post
Share on other sites

@xxValiumxx: Sorry for the confusion, I really thought you were JPlays on Twitch   :blink:

 

I assume you had to adapt the program in the Teensy to output the additional buttons to the virtual joystick interface. Could you please publish your modified code/sketch ?

Actually, I didn't have to modify the code at all.  the large button takes the place of what would be the mode switch in the G25, missing in the G27, the small button is just before it in the shift register.  The code actually already reads those inputs, they are just held to ground with resistors.  

 

Here's the current state of my code for the G27

//
//  G27 shifter to USB interface
//  based on a Teensy++ 2.0
//  Original by pascalh from insidesimracing.tv
//  http://insidesimracing.tv/forums/topic/13189-diy-g25-shifter-interface-with-h-pattern-sequential-and-handbrake-modes/


//  1 operating mode
//  - H-pattern shifter
//
//
//  G27 shifter pinout
//
//  DB9  Color    Shifter Description       Teensy
//  1    Purple    1      Button Clock      pin 2
//  2    Grey     7       Button Data       pin 3
//  3    Yellow   5       Button !CS & !PL  pin 4
//  4    Orange   3       Shifter X axis    pin 38 (A0)
//  5    White      2       SPI input 
//  6    Black    8       GND               GND
//  7    Red   6       +5V               VCC
//  8    Green    4       Shifter Y axis    pin 39 (A1)
//  9    Red    1       +5V

// Teensy pin definitions
#define LED_PIN            6
#define DATA_IN_PIN        3
#define MODE_PIN           4
#define CLOCK_PIN          2
#define X_AXIS_PIN         38
#define Y_AXIS_PIN         39

// H-shifter mode analog axis thresholds
#define HS_XAXIS_12        400 //Gears 1,2
#define HS_XAXIS_56        650 //Gears 5,6, R
#define HS_YAXIS_135       600 //Gears 1,3,5
#define HS_YAXIS_246       300 //Gears 2,4,6, R

// Digital inputs definitions
#define DI_REVERSE         1
#define DI_SMALL_BUTTON    2
#define DI_BIG_BUTTON      3
#define DI_RED_CENTERRIGHT 4
#define DI_RED_CENTERLEFT  5
#define DI_RED_RIGHT       6
#define DI_RED_LEFT        7
#define DI_BLACK_TOP       8
#define DI_BLACK_RIGHT     9
#define DI_BLACK_LEFT      10
#define DI_BLACK_BOTTOM    11
#define DI_DPAD_RIGHT      12
#define DI_DPAD_LEFT       13
#define DI_DPAD_BOTTOM     14
#define DI_DPAD_TOP        15


// LED blink counter
int led=0;

byte NESButtonData;
// Called at startup
// Must initialize hardware and software modules
void setup()
{
  // G27 shifter analog inputs configuration 
  pinMode(X_AXIS_PIN, INPUT_PULLUP);   // X axis
  pinMode(Y_AXIS_PIN, INPUT_PULLUP);   // Y axis
  
  // G27 shift register interface configuration 
  pinMode(DATA_IN_PIN, INPUT);         // Data in
  pinMode(MODE_PIN, OUTPUT);           // Parallel/serial mode
  pinMode(CLOCK_PIN, OUTPUT);          // Clock
  
  // LED output mode configuration 
  pinMode(LED_PIN, OUTPUT);            // LED
  
  // Virtual joystick configuration 
  Joystick.useManualSend(true);        // Joystick output is synchronized
  
  // Virtual serial interface configuration 
  Serial.begin(38400);
  
  // Virtual joystick initialization 
  Joystick.X(512);  //512 is center
  Joystick.Y(512);  //512 is center
  Joystick.Z(512);  //512 is center
  Joystick.Zrotate(512);      //512 is center
  Joystick.sliderLeft(512);   //512 is center
  Joystick.sliderRight(512);  //512 is center
  
  // Digital outputs initialization
  digitalWrite(LED_PIN, LOW);
  digitalWrite(MODE_PIN, HIGH);
  digitalWrite(CLOCK_PIN, HIGH); 
}

// Called in a loop after initialization
void loop() 
{
  // Reading of button states from G27 shift register
  int b[24];
  digitalWrite(MODE_PIN, LOW);         // Switch to parallel mode: digital inputs are read into shift register
  delayMicroseconds(10);               // Wait for signal to settle
  digitalWrite(MODE_PIN, HIGH);        // Switch to serial mode: one data bit is output on each clock falling edge
  
  for(int i=0; i<16; i++)              // Iteration over both 8 bit registers
  {
    digitalWrite(CLOCK_PIN, LOW);      // Generate clock falling edge
    delayMicroseconds(10);             // Wait for signal to settle
  
    b[i]=digitalRead(DATA_IN_PIN);     // Read data bit and store it into bit array
    
    digitalWrite(CLOCK_PIN, HIGH);     // Generate clock rising edge
    delayMicroseconds(10);             // Wait for signal to settle
  }
  
  // Reading of shifter position
  int x=analogRead(0);                 // X axis
  int y=analogRead(1);                 // Y axis
  
  // Current gear calculation
  int gear=0;                          // Default value is neutral

    if(x<HS_XAXIS_12)                  // Shifter on the left?
    {
      if(y>HS_YAXIS_135) gear=1;       // 1st gear
      if(y<HS_YAXIS_246) gear=2;       // 2nd gear
    }
    else if(x>HS_XAXIS_56)             // Shifter on the right?
    {
      if(y>HS_YAXIS_135) gear=5;       // 5th gear
      if(y<HS_YAXIS_246) gear=6;       // 6th gear
    }
    else                               // Shifter is in the middle
    {
      if(y>HS_YAXIS_135) gear=3;       // 3rd gear
      if(y<HS_YAXIS_246) gear=4;       // 4th gear
    }
  
  if(gear!=6) b[DI_REVERSE]=0;         // Reverse gear is allowed only on 6th gear position
  if(b[DI_REVERSE]==1) gear=0;         // 6th gear is deactivated if reverse gear is engaged
  
  // Release virtual buttons for all gears
  Joystick.button(1, LOW);
  Joystick.button(2, LOW);
  Joystick.button(3, LOW);
  Joystick.button(4, LOW);
  Joystick.button(5, LOW);
  Joystick.button(6, LOW);
  
  // Depress virtual button for current gear
  if(gear>0) Joystick.button(gear, HIGH);
  
  
  // Set state of virtual buttons for all the physical buttons (including reverse)
  for(int i=0; i<16; i++) Joystick.button(7+i, b[i]);

    Joystick.Z(analogRead(40));  //512 is center  NOTE: This is my clutch pedal.
  // Write new virtual joystick state
  Joystick.send_now();
  
  // Write inputs and outputs (remove comments to debug)
  
  Serial.print(" X axis: ");
  Serial.print(x);
  Serial.print(" Y axis: ");
  Serial.print(y);
  Serial.print(" Digital inputs: ");
  for(int i=0; i<16; i++)Serial.print(b[i]);
  Serial.print(" ");
  Serial.print(" Gear: ");
  Serial.println(gear);
  
  
  // Blink the on-board LED
  if(++led==100) led=0;                     // Period is 100 cycles * 10ms = 1s
  if(led==0) digitalWrite(LED_PIN, LOW);    // LED is off for 50 cycles
  if(led==50) digitalWrite(LED_PIN, HIGH);  // LED is on for 50 cycles 
  
  // Wait
  delay(10);                                // Wait for 10ms
}

Share this post


Link to post
Share on other sites
On 06/02/2015 at 2:08 AM, xxValiumxx said:

 

Actually, I didn't have to modify the code at all.  the large button takes the place of what would be the mode switch in the G25, missing in the G27, the small button is just before it in the shift register.  The code actually already reads those inputs, they are just held to ground with resistors.  

Interesting  ;)

In the original code, I shifted out and stored all 16 bits of the shift registers to keep it the simplest and easiest possible. Funny to see my lazyness become a feature :lol:  

Edited by pascalh

Share this post


Link to post
Share on other sites

Thx pascalh! It gives a second life to my shifter.
It was really interesting to build this by myself (and your great explainations of course).
 

Moreover, i added a connection to the pedals too. I want to share my little work with all of you :

g25_shifter_pedals_advanced.zip

If you want to use this, read the recommandations below :

 

IMPORTANT :

At connection (or reset, see new features), all axes must be resting :

  • shifter must be centered,
  • all 3 pedals must be released

Next, you will have to move all axes to min/max range to be fully operational.

 

It is because i use a kind of auto-calibration on axes.

 

Note :

It can work without connecting the pedals (i don't try with only the pedals connected, i think it could work).

In Richard Burns Rally, you will have to invert pedals axes by modifying the file "input.ini". I don't know why.

 

There are a few new features :

  • reset auto-calibration :

It reset resting, min and max values of each axis. You will have to move all axes to min/max range to be fully operational.

To trigger : both centered red button + both top and bottom black button.

  • auto-clutch :

Clutch will be set to max and gaz to min when moving shifter axis. You can see this as a kind of driving help or a cheat (not good lol)

To enable : both centered red button + left black button enabled

To disable : both centered red button + right black button

It works well in Assetto Corsa for instance.

  • double analog handbrakes :

2 handbrakes can be used on 2 axis (when you push or pull)

  • hat :

The shifter hat has been added as joystick output.

 

Joystick ouputs :

//  Joystick outputs :
//      X               : clutch
//      Y               : brake
//      Z               : gaz
//      Zrotate         : not used
//      hat             : shifter hat
//      sliderLeft      : handbrake 1 (pull)
//      sliderRight     : handbrake 2 (push)
//      buttons 1-6     : Gear 1-6
//      button 7        : reverse
//      button 8        : sequential up shift
//      button 9        : sequential down shift
//      buttons 10-13   : shifter red buttons
//      buttons 14-17   : shifter top black buttons

Thanks again pascalh.

 

Enjoy!

Share this post


Link to post
Share on other sites
On 10/04/2015 at 7:47 PM, spocthier said:

Thx pascalh! It gives a second life to my shifter.

It was really interesting to build this by myself (and your great explainations of course).

 

Moreover, i added a connection to the pedals too. I want to share my little work with all of you :

attachicon.gifg25_shifter_pedals_advanced.zip

If you want to use this, read the recommandations below :

 

IMPORTANT :

At connection (or reset, see new features), all axes must be resting :

  • shifter must be centered,
  • all 3 pedals must be released

Next, you will have to move all axes to min/max range to be fully operational.

 

It is because i use a kind of auto-calibration on axes.

 

Note :

It can work without connecting the pedals (i don't try with only the pedals connected, i think it could work).

In Richard Burns Rally, you will have to invert pedals axes by modifying the file "input.ini". I don't know why.

 

There are a few new features :

  • reset auto-calibration :

It reset resting, min and max values of each axis. You will have to move all axes to min/max range to be fully operational.

To trigger : both centered red button + both top and bottom black button.

  • auto-clutch :

Clutch will be set to max and gaz to min when moving shifter axis. You can see this as a kind of driving help or a cheat (not good lol)

To enable : both centered red button + left black button enabled

To disable : both centered red button + right black button

It works well in Assetto Corsa for instance.

  • double analog handbrakes :

2 handbrakes can be used on 2 axis (when you push or pull)

  • hat :

The shifter hat has been added as joystick output.

 

Joystick ouputs :

//  Joystick outputs :
//      X               : clutch
//      Y               : brake
//      Z               : gaz
//      Zrotate         : not used
//      hat             : shifter hat
//      sliderLeft      : handbrake 1 (pull)
//      sliderRight     : handbrake 2 (push)
//      buttons 1-6     : Gear 1-6
//      button 7        : reverse
//      button 8        : sequential up shift
//      button 9        : sequential down shift
//      buttons 10-13   : shifter red buttons
//      buttons 14-17   : shifter top black buttons

Thanks again pascalh.

 

Enjoy!

Very cool  ;)

I started to work on a similar project (without external handbrake though) when my son bought a TH8RS ...

Glad to see my project extended  :)

Edited by pascalh

Share this post


Link to post
Share on other sites

Thx pascalh! It gives a second life to my shifter.

It was really interesting to build this by myself (and your great explainations of course).

 

Moreover, i added a connection to the pedals too. I want to share my little work with all of you :

attachicon.gifg25_shifter_pedals_advanced.zip

If you want to use this, read the recommandations below :

 

IMPORTANT :

At connection (or reset, see new features), all axes must be resting :

  • shifter must be centered,
  • all 3 pedals must be released

Next, you will have to move all axes to min/max range to be fully operational.

 

It is because i use a kind of auto-calibration on axes.

 

Note :

It can work without connecting the pedals (i don't try with only the pedals connected, i think it could work).

In Richard Burns Rally, you will have to invert pedals axes by modifying the file "input.ini". I don't know why.

 

There are a few new features :

  • reset auto-calibration :

It reset resting, min and max values of each axis. You will have to move all axes to min/max range to be fully operational.

To trigger : both centered red button + both top and bottom black button.

  • auto-clutch :

Clutch will be set to max and gaz to min when moving shifter axis. You can see this as a kind of driving help or a cheat (not good lol)

To enable : both centered red button + left black button enabled

To disable : both centered red button + right black button

It works well in Assetto Corsa for instance.

  • double analog handbrakes :

2 handbrakes can be used on 2 axis (when you push or pull)

  • hat :

The shifter hat has been added as joystick output.

 

Joystick ouputs :

//  Joystick outputs :
//      X               : clutch
//      Y               : brake
//      Z               : gaz
//      Zrotate         : not used
//      hat             : shifter hat
//      sliderLeft      : handbrake 1 (pull)
//      sliderRight     : handbrake 2 (push)
//      buttons 1-6     : Gear 1-6
//      button 7        : reverse
//      button 8        : sequential up shift
//      button 9        : sequential down shift
//      buttons 10-13   : shifter red buttons
//      buttons 14-17   : shifter top black buttons

Thanks again pascalh.

 

Enjoy!

Can you could put a image of the schematics of the interface for the pedals too, from de db pin to teensy?

 

Great Job Guys!

Share this post


Link to post
Share on other sites
On 16/06/2015 at 3:32 AM, hetfieldickinson said:

Can you could put a image of the schematics of the interface for the pedals too, from de db pin to teensy?

 

Great Job Guys!

This is the G25/G27 wiring diagram to the pedals DB9 connector:

g25pinout.png

On the other side of the pedals DB9 connector, you have to connect:

  • pin 1 to Teensy +5V
  • pin 6 to Teensy GND
  • pin 2, 3, 4 to the 3 Teensy analog input pins defined in the code
Edited by pascalh

Share this post


Link to post
Share on other sites

 

 

This is the G25/G27 wiring diagram to the pedals DB9 connector:

 

g25pinout.png

 

On the other side of the pedals DB9 connector, you have to connect:

  • pin 1 to Teensy +5V
  • pin 6 to Teensy GND
  • pin 2, 3, 4 to the 3 Teensy analog input pins defined in the code

 

Thnx for the answer, three last questions (for now),

1 - I need only one teensy 2.0 board and two db9 conectors, right?

2 - I will use the same ground and the 5V to the pedals and shifter?

3 - And finally, i'm a totally newbie to programing, then, is this the code part that show the pins of teensy to the pedal and handbrake (in bold)?

 

// Analog pins definition

//   -shifter

const int X_AXIS_ANALOG_PIN         = 0; //  A0 

const int Y_AXIS_ANALOG_PIN         = 1; //  A1 

//   -pedals

const int CLUTCH_AXIS_ANALOG_PIN    = 7; //  A7   

const int GAZ_AXIS_ANALOG_PIN       = 8; //     A8

const int BRAKE_AXIS_ANALOG_PIN     = 9; //   A9

 

 

Sorry for the "engrish", i'm from Brazil and not practice so much, and again, thnx in advice...

Is probable when I was mounting the interface, more questions will came, i'm counting with you to answer these questions :mrgreen: ....

Share this post


Link to post
Share on other sites
On 18/06/2015 at 3:06 AM, hetfieldickinson said:

Thnx for the answer, three last questions (for now),

1 - I need only one teensy 2.0 board and two db9 conectors, right?

2 - I will use the same ground and the 5V to the pedals and shifter?

3 - And finally, i'm a totally newbie to programing, then, is this the code part that show the pins of teensy to the pedal and handbrake (in bold)?

 

// Analog pins definition

//   -shifter

const int X_AXIS_ANALOG_PIN         = 0; //  A0 

const int Y_AXIS_ANALOG_PIN         = 1; //  A1 

//   -pedals

const int CLUTCH_AXIS_ANALOG_PIN    = 7; //  A7   

const int GAZ_AXIS_ANALOG_PIN       = 8; //     A8

const int BRAKE_AXIS_ANALOG_PIN     = 9; //   A9

Sorry for the "engrish", i'm from Brazil and not practice so much, and again, thnx in advice...

Is probable when I was mounting the interface, more questions will came, i'm counting with you to answer these questions :mrgreen: ....

1 - Yes, only one Teensy and 2 DB9 connectors

2 - Yes, same GND and +5V

3 - Yes, with spocthier's code pedals need to be connected to analog inputs 7, 8 and 9.

     These analog inputs are on pins 12, 13, 14 (see picture below)

pinout2b.png

Edited by pascalh

Share this post


Link to post
Share on other sites

1 - Yes, only one Teensy and 2 DB9 connectors

2 - Yes, same GND and +5V

3 - Yes, with spocthier's code pedals need to be connected to analog inputs 7, 8 and 9.

     These analog inputs are on pins 12, 13, 14 (see picture below)

 

pinout2b.png

Thnx again!

Need to buy the teensy and work on it.

Anyway i'm waiting the second hand shifter to work on it....

One last question, is there any possibility to pass the wheel itself in the tensy board, making the pedals, shifter and wheel recognized as one game controler to avoid problems in games that not suport more than one game controler...

Remember, i'm a newbie, and maybe i'm talking BS.... :oops:

Share this post


Link to post
Share on other sites
On 20/06/2015 at 1:36 AM, hetfieldickinson said:

Thnx again!

Need to buy the teensy and work on it.

Anyway i'm waiting the second hand shifter to work on it....

One last question, is there any possibility to pass the wheel itself in the tensy board, making the pedals, shifter and wheel recognized as one game controler to avoid problems in games that not suport more than one game controler...

Remember, i'm a newbie, and maybe i'm talking BS.... :oops:

No, there is no easy way to pass the wheel connexion through the Teensy board for several reasons:

  • Without opening the wheel, the only way to connect it is through the USB connector. Which means the Teensy should have a USB host and a USB slave connector, but it doesn't.
  • The alternative way would be to open the wheel and bypass the built-in controller. This has never been done as it involves some electronic surgery.Additionally it voids warranty.
  • Then a new FFB and decoder software has to be written, which is not an easy task.

In any case you would loose the Logitech software. The only benefit being to save one USB connexion on the PC, there is really no point in doing it  ;)

Edited by pascalh

Share this post


Link to post
Share on other sites

No, there is no easy way to pass the wheel connexion through the Teensy board for several reasons:

  • Without opening the wheel, the only way to connect it is through the USB connector. Which means the Teensy should have a USB host and a USB slave connector, but it doesn't.
  • The alternative way would be to open the wheel and bypass the built-in controller. This has never been done as it involves some electronic surgery.Additionally it voids warranty.
  • Then a new FFB and decoder software has to be written, which is not an easy task.

In any case you would loose the Logitech software. The only benefit being to save one USB connexion on the PC, there is really no point in doing it  ;)

Whel, if the only way is the above, absolutely there is no point on conect the wheel through the tensy....

Thx one more time, now I have to purchase a teensy and wait to come.

Anyone purchase the board with the no insurance post from PJRC and received it with no problems?

Its is so dificult to buy a board on Brasil with the certain that its genuine.... :mad: 

Share this post


Link to post
Share on other sites
On 26/06/2015 at 4:42 AM, hetfieldickinson said:

Whel, if the only way is the above, absolutely there is no point on conect the wheel through the tensy....

Thx one more time, now I have to purchase a teensy and wait to come.

Anyone purchase the board with the no insurance post from PJRC and received it with no problems?

Its is so dificult to buy a board on Brasil with the certain that its genuine.... :x

No problem here buying directly from PJRC: quick and easy  :lol:

I bought several Teensies at once to lower the shipping cost per Teensy

Edited by pascalh

Share this post


Link to post
Share on other sites

No problem here buying directly from PJRC: quick and easy  :lol:

I bought several Teensies at once to lower the shipping cost per Teensy

Thnx again, maybe i will give a try to a local costumer (waiting for shots of product, to verify if is the genuine teensy 2.0), and maybe i buy the board on adafruit, theres the same price on the PJRC, is the original one, anda there is a option of low cost untrackable mail, but with insurance, that makes me feel more confortable with the purchase....

Share this post


Link to post
Share on other sites

Hey guys, ressurecting the topic, i received the teensy yesterday, and mount the devices, the shifter its working (next step is implementing the pedals with the code of spocthier), unfortunately i have one problem, I thing my antivirus blocked the software on the keyboard-mouse-controller setting (i made him function on first attempt, i think, do not have certainly....), but it is working on serial-keyboard-mouse-controller setting, there are any problem on left this thing that way?

 

 

Thnx again! :cool:

Share this post


Link to post
Share on other sites
On 20/07/2015 at 4:00 AM, hetfieldickinson said:

Hey guys, ressurecting the topic, i received the teensy yesterday, and mount the devices, the shifter its working (next step is implementing the pedals with the code of spocthier), unfortunately i have one problem, I thing my antivirus blocked the software on the keyboard-mouse-controller setting (i made him function on first attempt, i think, do not have certainly....), but it is working on serial-keyboard-mouse-controller setting, there are any problem on left this thing that way?

 

 

Thnx again! 8-)

Glad it worked on first attempt  :)

No problem using the serial/keyboard/mouse/joystick library. You can send some mouse clicks or move the mouse but I don't see how it could be used with a shifter. It doesn't harm the working of the program, it just uses up some more program flash.

Edited by pascalh

Share this post


Link to post
Share on other sites

Thanx for this great sketch. I have adapted it to Leonado / Pro Micro by using NicoHood HID.

 

If you search for ATmega32U4 on eBay. You can get an alternative to the Teensy for a fraction of the price.

//
//  G25 shifter to USB interface
//  based on a Teensy 2.0
//
//  Modifications by Per Mejdal Rasmussen
//  * Adapted to Leonado / Pro Micro by using NicoHood HID
//  * Dpad uses "Point of View Hat" if dpad_mode is enabled (default)
//  * AnalogRead now uses [XY]_AXIS_PIN constant (bug fix)
//
//  3 operating modes
//  - H-pattern shifter
//  - Sequential shifter
//  - Analog handrake
//
// http://www.isrtv.com/forums/topic/13189-diy-g25-shifter-interface-with-h-pattern-sequential-and-handbrake-modes/

//
//  G25 shifter pinout (for G27: swap pin 1 and 7)
//
//  DB9  Color    Shifter Description       Teensy
//  1    Black    1       +5V               +5V
//  2    Grey     7       Button Data       pin 17
//  3    Yellow   5       Button !CS & !PL  pin 18
//  4    Orange   3       Shifter X axis    pin 21 (A0)
//  5    Red      2       SPI input 
//  6    White    8       GND               GND
//  7    Purple   6       Button Clock      pin 19
//  8    Green    4       Shifter Y axis    pin 20 (A1)
//  9    Black    1       +5V

// Download NicoHood HID from https://github.com/NicoHood/HID
#include "HID.h"
#include "HID-Project.h"

// Teensy pin definitions
#define LED_PIN            11
#define DATA_IN_PIN        14 //2 Button Data
#define MODE_PIN           16 //3 Button !CS & !PL
#define CLOCK_PIN          15 //7 Button Clock
#define X_AXIS_PIN         A0 //4 Shifter X axis
#define Y_AXIS_PIN         A1 //8 Shifter Y axis

// H-shifter mode analog axis thresholds
#define HS_XAXIS_12        400
#define HS_XAXIS_56        600
#define HS_YAXIS_135       800
#define HS_YAXIS_246       300

// Sequential shifter mode analog axis thresholds
#define SS_UPSHIFT_BEGIN   670
#define SS_UPSHIFT_END     600
#define SS_DOWNSHIFT_BEGIN 430
#define SS_DOWNSHIFT_END   500

// Handbrake mode analog axis limits
#define HB_MAXIMUM         530
#define HB_MINIMUM         400
#define HB_RANGE           (HB_MAXIMUM-HB_MINIMUM)

// Digital inputs definitions
#define DI_REVERSE         1
#define DI_MODE            3
#define DI_RED_CENTERRIGHT 4
#define DI_RED_CENTERLEFT  5
#define DI_RED_RIGHT       6
#define DI_RED_LEFT        7
#define DI_BLACK_TOP       8
#define DI_BLACK_RIGHT     9
#define DI_BLACK_LEFT      10
#define DI_BLACK_BOTTOM    11
#define DI_DPAD_RIGHT      12
#define DI_DPAD_LEFT       13
#define DI_DPAD_BOTTOM     14
#define DI_DPAD_TOP        15

// Shifter state
#define DOWN_SHIFT         -1
#define NO_SHIFT           0
#define UP_SHIFT           1

// Shifter mode
#define SHIFTER_MODE       0
#define HANDBRAKE_MODE     1

// LED blink counter
int led=0;

// Shifter state
int shift=NO_SHIFT;

// Handbrake mode
int mode=SHIFTER_MODE;

//Dpad mode
int dpad_mode=1;

// Called at startup
// Must initialize hardware and software modules
void setup()
{
  // G25 shifter analog inputs configuration 
  pinMode(X_AXIS_PIN, INPUT_PULLUP);   // X axis
  pinMode(Y_AXIS_PIN, INPUT_PULLUP);   // Y axis
  
  // G25 shift register interface configuration 
  pinMode(DATA_IN_PIN, INPUT);         // Data in
  pinMode(MODE_PIN, OUTPUT);           // Parallel/serial mode
  pinMode(CLOCK_PIN, OUTPUT);          // Clock
  
  // LED output mode configuration 
  pinMode(LED_PIN, OUTPUT);            // LED
  
  // Virtual joystick configuration 
  Gamepad.begin();
  
  // Virtual serial interface configuration 
  Serial.begin(38400);
 
  // Digital outputs initialization
  digitalWrite(LED_PIN, LOW);
  digitalWrite(MODE_PIN, HIGH);
  digitalWrite(CLOCK_PIN, HIGH); 
}

// Called in a loop after initialization
void loop() 
{
  // Reading of button states from G25 shift register
  int b[16];
  
  digitalWrite(MODE_PIN, LOW);         // Parallel mode: inputs are read into shift register
  delayMicroseconds(10);               // Wait for signal to settle
  digitalWrite(MODE_PIN, HIGH);        // Serial mode: data bits are output on clock falling edge
  
  for(int i=0; i<16; i++)              // Iteration over both 8 bit registers
  {
    digitalWrite(CLOCK_PIN, LOW);      // Generate clock falling edge
    delayMicroseconds(10);             // Wait for signal to settle
  
    b[i]=digitalRead(DATA_IN_PIN);     // Read data bit and store it into bit array
    
    digitalWrite(CLOCK_PIN, HIGH);     // Generate clock rising edge
    delayMicroseconds(10);             // Wait for signal to settle
  }

  // Reading of shifter position
  int x=analogRead(X_AXIS_PIN);                 // X axis
  int y=analogRead(Y_AXIS_PIN);                 // Y axis
  
  // Handbrake mode logic
  if(b[DI_RED_CENTERLEFT]!=0)          // Is left center red button depressed?
  {
    if(b[DI_RED_CENTERRIGHT]!=0)       // Is right center red button also depressed?
    {
      if(b[DI_RED_RIGHT]!=0)           // Is rightmost red button also depressed?
      {
        mode=HANDBRAKE_MODE;           // Handbrake mode is activated if the 3 rightmost 
      }                                // red buttons are depressed
      if(b[DI_RED_LEFT]!=0)            // Is leftmost red button also depressed?
      {
        mode=SHIFTER_MODE;             // Handbrake mode is deactivated if the 3 leftmost
      }                                // red buttons are depressed
    }
  }
  
  // Current gear calculation
  int gear=0;                          // Default value is neutral

  if(b[DI_MODE]==0)                    // H-shifter mode?
  {
    if(x<HS_XAXIS_12)                  // Shifter on the left?
    {
      if(y>HS_YAXIS_135) gear=1;       // 1st gear
      if(y<HS_YAXIS_246) gear=2;       // 2nd gear
    }
    else if(x>HS_XAXIS_56)             // Shifter on the right?
    {
      if(y>HS_YAXIS_135) gear=5;       // 5th gear
      if(y<HS_YAXIS_246) gear=6;       // 6th gear
    }
    else                               // Shifter is in the middle
    {
      if(y>HS_YAXIS_135) gear=3;       // 3rd gear
      if(y<HS_YAXIS_246) gear=4;       // 4th gear
    }
  }
  else                                 // Sequential mode 
  {
    if(mode==SHIFTER_MODE)             // Shifter mode?
    {
      Gamepad.zAxis(0);
      if(shift==NO_SHIFT)              // Current state: no shift
      {
        if(y>SS_UPSHIFT_BEGIN)         // Shifter to the front?
        {
          gear=1;                      // Shift-up
          shift=UP_SHIFT;              // New state: up-shift
        }
        if(y<SS_DOWNSHIFT_BEGIN)       // Shifter to the rear?
        {
          gear=2;                      // Shift-down
          shift=DOWN_SHIFT;            // New state: down-shift
        }
      }
      if(shift==UP_SHIFT)              // Current state: up-shift?
      {
        if(y>SS_UPSHIFT_END) gear=1;   // Beyond lower up-shift threshold: up-shift
        else shift=NO_SHIFT;           // Else new state: no shift
      }
      if(shift==DOWN_SHIFT)            // Current state: down-shift
      {
        if(y<SS_DOWNSHIFT_END) gear=2; // Below higher down-shift threshold: down-shift
        else shift=0;                  // Else new state: no shift
      }
    }
    else                               // Handbrake mode
    {
      if(y<HB_MINIMUM) y=HB_MINIMUM;   // Clip minimum position
      if(y>HB_MAXIMUM) y=HB_MAXIMUM;   // Clip maximum position
      
      long offset=(long)y-HB_MINIMUM;
      y=(int)(offset*1023/HB_RANGE);   // Scale input between minimum and maximum clip position
      
      Gamepad.zAxis(y/4+0x80);                   // Set handbrake analog output
      gear=0;                          // No gear engaged: neutral
    }
  }
  
  if(gear!=6) b[DI_REVERSE]=0;         // Reverse gear is allowed only on 6th gear position
  if(b[DI_REVERSE]==1) gear=0;         // 6th gear is deactivated if reverse gear is engaged
  
  // Release virtual buttons for all gears
  Gamepad.release(1);
  Gamepad.release(2);
  Gamepad.release(3);
  Gamepad.release(4);
  Gamepad.release(5);
  Gamepad.release(6);
  
  // Depress virtual button for current gear
  if(gear>0) Gamepad.press(gear);
  
  // Dpad positions
  //  812
  //  703
  //  654
  int number_of_buttons = 16;
  if (dpad_mode)
  {
    number_of_buttons = 12;
    int dpad = 0;
    if(b[DI_DPAD_TOP])
    {
     if (b[DI_DPAD_LEFT])       dpad = 8;
     else if (b[DI_DPAD_RIGHT]) dpad = 2;
     else                       dpad = 1;
    }
    else if (b[DI_DPAD_BOTTOM])
    {
      if (b[DI_DPAD_LEFT])       dpad = 6;
      else if (b[DI_DPAD_RIGHT]) dpad = 4;
      else                       dpad = 5; 
    }
    else
    {
      if (b[DI_DPAD_LEFT])       dpad = 7;
      if (b[DI_DPAD_RIGHT])      dpad = 3;
    }
    Gamepad.dPad1(dpad);
  }

  // Set state of virtual buttons for all the physical buttons (including reverse)
  for(int i=0; i<number_of_buttons; i++)
  {
    if (b[i])
    {
      Gamepad.press(7+i);
    }
    else
    {
      Gamepad.release(7+i);
    }
  }
  
  // Write new virtual joystick state
  Gamepad.write();
  
  // Write inputs and outputs (remove comments to debug)
  /*
  Serial.print(" X axis: ");
  Serial.print(x);
  Serial.print(" Y axis: ");
  Serial.print(y);
  Serial.print(" Digital inputs: ");
  for(int i=0; i<16; i++)Serial.print(b[i]);
  Serial.print(" ");
  Serial.print(" Gear: ");
  Serial.print(gear);
  Serial.print(" Mode: ");
  Serial.print(mode);
  Serial.print(" Shift: ");
  Serial.println(shift);
  */

  // Blink the on-board LED
  if(++led==100) led=0;                     // Period is 100 cycles * 10ms = 1s
  if(led==0) digitalWrite(LED_PIN, LOW);    // LED is off for 50 cycles
  if(led==50) digitalWrite(LED_PIN, HIGH);  // LED is on for 50 cycles 
  
  // Wait
  delay(10);                                // Wait for 10ms
}

Share this post


Link to post
Share on other sites
On 08/09/2015 at 9:56 PM, CableCat said:

 

Thanx for this great sketch. I have adapted it to Leonado / Pro Micro by using NicoHood HID.

 

If you search for ATmega32U4 on eBay. You can get an alternative to the Teensy for a fraction of the price.

 

Nice to see my project ported to another plateform :)

Concerning the price, there is almost no difference between a Teensy LC at $11.65 (http://pjrc.com/store/teensylc.html) and an ebay Arduino Pro knock off. The lowest price I could find for one of those is $10 (http://www.ebay.fr/itm/Arduino-pro-micro-kompatibles-Board-Atmel-ATmega32U4-16MHz-5V-/221656602005?hash=item339bc35595).

In my opinion, there is really no point in trading this small additional cost for the level of quality and support PJRC offers.

Edited by pascalh

Share this post


Link to post
Share on other sites
I was not aware of the Teensy LC. I had my eye on the Teensy 3.1, which cost $46.23 in my local DIY electronic store. But when factoring in shipping to Denmark, Then the price on eBay is still less than 1/5 of the price:
 
www.pjrc.com: 11.65 + 10.22 = $21.87
www.let-elektronik.dk: 22.75 + 6.28 = $29.03
www.ebay.com/itm/310634777706: $4.34 (free shipping)
 
G25box_small.jpg
My plan is to connect 2 sets of pedals. So there are also pedals for the driver-instructor.
Edited by CableCat

Share this post


Link to post
Share on other sites
On 09/09/2015 at 8:24 PM, CableCat said:

 

I was not aware of the Teensy LC. I had my eye on the Teensy 3.1, which cost $46.23 in my local DIY electronic store. But when factoring in shipping to Denmark, Then the price on eBay is still less than 1/5 of the price:
 
www.pjrc.com: 11.65 + 10.22 = $21.87
www.let-elektronik.dk: 22.75 + 6.28 = $29.03
www.ebay.com/itm/310634777706: $4.34 (free shipping)
 

 

Nice  ;)

I've ordered two of those to do some testing  :)

Edited by pascalh

Share this post


Link to post
Share on other sites

I've ordered two of those to do some testing  :)

 

I can also recommend this from the same seller:

http://www.ebay.com/itm/201037850851

 

Should you need the recreate my build environment, here is how:

 

Download and extract: 

https://www.arduino.cc/download.php?f=/arduino-nightly-windows.zip

 

Download and extract SF32u4_boards-master\sparkfun to arduino-nightly\hardware

https://github.com/sparkfun/SF32u4_boards/archive/master.zip

 

Download and extract HID-dev_2_4 to arduino-nightly\libraries, then rename it to HID

https://github.com/NicoHood/HID/archive/dev_2_4.zip

 

Select "SparkFun Pro Micro 5V/16Mhz" as your board.

 

 

promicro.jpg

Edited by CableCat

Share this post


Link to post
Share on other sites

Hi, I am missing the shifter for my G25, which makes it impossible for me to change max rotation on my steering wheel. I'm wondering if you could help me adapt your code to make a small 4-button box with this function.

The normal way of doing this is holding the two center red buttons and pressing a black button. Using your designations:

RED_CR + RED_CL +
BL_T: 225°
BL_R: 675°
BL_L: 450°
BL_B: 900° (default)

Is this possible with the same hardware, adding four buttons? No USB-interface. Thanks

Share this post


Link to post
Share on other sites
On 10/9/2015 at 10:29 AM, CableCat said:

 

I can also recommend this from the same seller:

http://www.ebay.com/itm/201037850851

 

Should you need the recreate my build environment, here is how:

 

Download and extract: 

https://www.arduino.cc/download.php?f=/arduino-nightly-windows.zip

 

Download and extract SF32u4_boards-master\sparkfun to arduino-nightly\hardware

https://github.com/sparkfun/SF32u4_boards/archive/master.zip

 

Download and extract HID-dev_2_4 to arduino-nightly\libraries, then rename it to HID

https://github.com/NicoHood/HID/archive/dev_2_4.zip

 

Select "SparkFun Pro Micro 5V/16Mhz" as your board.

 

 

promicro.jpg

CableCat, Could you please help in updating and expanding your short guide to replicate your build environment? I am having rather big problems even getting the your code to compile. The issue is that as of 1.6.6, some arduino stuff has changed and as such the sparkfun board does not work. So I would need to know the exact versions you used.

If it is not possible to get the older versions, we need a new code because I get an error saying that <'Gamepad' was not declared in this scope>. I simply have to little knowledge to figure out what to do to fix it. I have looked extensively in the docs for arduino but I can't find anything regarding 'Gamepad'. As of the new version, nicohood's stuff comes build-in but I don't know if I am missing something..

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
20 20