1. Do not share user accounts! Any account that is shared by another person will be blocked and closed. This means: we will close not only the account that is shared, but also the main account of the user who uses another person's account. We have the ability to detect account sharing, so please do not try to cheat the system. This action will take place on 04/18/2023. Read all forum rules.
    Dismiss Notice
  2. For downloading SimTools plugins you need a Download Package. Get it with virtual coins that you receive for forum activity or Buy Download Package - We have a zero Spam tolerance so read our forum rules first.

    Buy Now a Download Plan!
  3. Do not try to cheat our system and do not post an unnecessary amount of useless posts only to earn credits here. We have a zero spam tolerance policy and this will cause a ban of your user account. Otherwise we wish you a pleasant stay here! Read the forum rules
  4. We have a few rules which you need to read and accept before posting anything here! Following these rules will keep the forum clean and your stay pleasant. Do not follow these rules can lead to permanent exclusion from this website: Read the forum rules.
    Are you a company? Read our company rules

Showroom (In Progress) DIY FFB non synchronized shifter for American Truck Simulator

Discussion in 'DIY peripherals' started by RiftFlyer, Feb 6, 2019.

  1. RiftFlyer

    RiftFlyer Active Member Gold Contributor

    Joined:
    Apr 15, 2014
    Messages:
    198
    Balance:
    1,711Coins
    Ratings:
    +121 / 0 / -0
    My Motion Simulator:
    DC motor
    I finally took the time to revisit this project and I'm glad to say it is now working as I had hoped. Here is a short video. I'll do a more detailed write up once I make a few final adjustments.

    • Like Like x 2
  2. RiftFlyer

    RiftFlyer Active Member Gold Contributor

    Joined:
    Apr 15, 2014
    Messages:
    198
    Balance:
    1,711Coins
    Ratings:
    +121 / 0 / -0
    My Motion Simulator:
    DC motor
    Changed a few bits since I last posted so I’ve redrawn the schematic. I’m now using magnetic locks and contactless switches.

    IMG_9598.jpeg

    I’m finding this shifter is working well apart from the vibration effects of gear grinding. The vibration motor I’m using is a bit anemic for the mass of the stick.

    motor.png


    I’m thinking either an actuator connected on a parallel pivoting axis to physically move the stick in my hand or switching to a transducer. Can anyone suggest a suitable transducer or motor/potentiometer/driver combo that might work? I have a few wiper motors but they are too bulky for this application.
  3. Gadget999

    Gadget999 Well-Known Member

    Joined:
    Dec 27, 2015
    Messages:
    1,945
    Location:
    London
    Balance:
    11,898Coins
    Ratings:
    +479 / 10 / -0
    My Motion Simulator:
    2DOF, DC motor, Arduino, 6DOF
    Try adding a larger out of balance weight to the end of the motor
    • Like Like x 1
  4. RiftFlyer

    RiftFlyer Active Member Gold Contributor

    Joined:
    Apr 15, 2014
    Messages:
    198
    Balance:
    1,711Coins
    Ratings:
    +121 / 0 / -0
    My Motion Simulator:
    DC motor
    Sharing the Arduino code I've used for the Micro and Uno boards:

    The Micro (seen by windows as a game controller but also communicates with the Uno over i2c);

    Code:
    #include <Wire.h>
    #include <EasyTransferI2C.h>
    #include <Joystick.h>
    Joystick_ Joystick;
    int ledPin = 15;// temporary, used to test gear buttons by lighting LED
    int forward = 4;
    int forwardState = 0;
    int rearward = 5;
    int rearwardState = 0;
    int left = 6;
    int leftState = 0;
    int right = 7;
    int rightState = 0;
    int range = 10;
    int rangeState = 0;
    int splitter = 16;
    int splitterState = 0;
    int jake = 14;
    int jakeState = 0;
    //create object
    EasyTransferI2C ET;
    
    struct SEND_DATA_STRUCTURE {
      //put your variable definitions here for the data you want to send
      //THIS MUST BE EXACTLY THE SAME ON THE OTHER ARDUINO
      int16_t gearPressed;
    };
    
    //give a name to the group of data
    SEND_DATA_STRUCTURE mydata;
    
    //define slave i2c address
    #define I2C_SLAVE_ADDRESS 9
    
    void setup() {
      Wire.begin();
      //start the library, pass in the data details and the name of the serial port. Can be Serial, Serial1, Serial2, etc.
      ET.begin(details(mydata), &Wire);
      pinMode(10, INPUT_PULLUP); //range switch
      pinMode(16, INPUT_PULLUP); //split switch
      pinMode(14, INPUT_PULLUP);
      pinMode(4, INPUT_PULLUP);
      pinMode(5, INPUT_PULLUP);
      pinMode(6, INPUT_PULLUP);
      pinMode(7, INPUT_PULLUP);
    
      pinMode(ledPin, OUTPUT);
      // Initialize Joystick Library
      Joystick.begin();
    }
    
    void loop() {
      //this is how you access the variables. [name of the group].[variable name]
    
      //send the data
      ET.sendData(I2C_SLAVE_ADDRESS);
      leftState = digitalRead (left);
      rightState = digitalRead (right);
      forwardState = digitalRead (forward);
      rearwardState = digitalRead (rearward);
      rangeState = digitalRead(10);
      jakeState = digitalRead(14);
      splitterState = digitalRead(16);
     
     
     
      if (forwardState == LOW){
        digitalWrite(ledPin, HIGH);
        mydata.gearPressed = 1;
       
        if ((leftState == HIGH) && (rightState == HIGH)){
        Joystick.setButton(2, HIGH);
        }
        if ((leftState == LOW) && (rightState == HIGH)){
          Joystick.setButton(0, HIGH);
        }
        if ((leftState == HIGH) && (rightState == LOW)){
          Joystick.setButton(4, HIGH);
        }
      }
     else{
        digitalWrite(ledPin, LOW);
        mydata.gearPressed = 0;
        Joystick.setButton(2, LOW);
        Joystick.setButton(0, LOW);
        Joystick.setButton(4, LOW);
        }
    
        if (rearwardState == LOW){
        digitalWrite(ledPin, HIGH);
        mydata.gearPressed = 1;
       
        if ((leftState == HIGH) && (rightState == HIGH)){
        Joystick.setButton(3, HIGH);
        }
        if ((leftState == LOW) && (rightState == HIGH)){
          Joystick.setButton(1, HIGH);
        }
        if ((leftState == HIGH) && (rightState == LOW)){
          Joystick.setButton(5, HIGH);
        }
      }
     else{
        //digitalWrite(ledPin, LOW);
        //mydata.gearPressed = 0;
        Joystick.setButton(3, LOW);
        Joystick.setButton(1, LOW);
        Joystick.setButton(5, LOW);
        }
    
    
    
     
    
     
      if (rangeState == LOW) {
        Joystick.setButton(6, LOW);
      }
      else {
        Joystick.setButton(6, HIGH);
      }
    
     
      if (splitterState == LOW) {
        Joystick.setButton(7, HIGH);
      }
      else {
        Joystick.setButton(7, LOW);
      }
    
     
      if (jakeState == HIGH) {
        Joystick.setButton(8, LOW);
      }
      else {
        Joystick.setButton(8, HIGH);
      }
    
      delay(50);
    }
    The Uno board which interprets game data and data from the micro to control 3 relays and in turn power the electromagnets and vibration motor;

    Code:
    #include <Wire.h>
    #include <EasyTransferI2C.h>
    
    //create object
    EasyTransferI2C ET;
    struct RECEIVE_DATA_STRUCTURE {
      int16_t gearPressed;// variable passed from second arduino to indicate if shifter is pressing a gear button
    };
    RECEIVE_DATA_STRUCTURE mydata;//give a name to the group of data
    #define I2C_SLAVE_ADDRESS 9//define slave i2c address
    //declaring global variables
    int GearGameDash = 0;
    int bufferArray[5];
    boolean oldGearState;
    boolean inGear = false;
    boolean engineRunning = false;
    const byte relay_pin_front_mag_lock = 6;//assigning Arduino digital pin 6
    const byte relay_pin_rear_mag_lock = 7;//assigning Arduino digital pin 7
    const byte relay_pin_vibe = 5;//assigning Arduino digital pin 5
    const unsigned long relayinterval = 500;//length of time in miliseconds that the mag locks disengage
    unsigned long relaytimer;//stores length of time that the mag locks have been open
    
    
    void setup() {
      Serial.begin(115200);//initialize serial port
    //#ifdef DEBUG
    //  Serial.println("Serial started, enter commands in the form of G000");
    //#endif
    
      Wire.begin(I2C_SLAVE_ADDRESS);//initialize i2c
      ET.begin(details(mydata), &Wire);//define handler function on receiving data
      Wire.onReceive(receive);
      pinMode( relay_pin_front_mag_lock , OUTPUT);//setting the front mag lock relay pin as an output
      digitalWrite(relay_pin_front_mag_lock , LOW);//setting the voltage on the front mag lock relay pin
      pinMode( relay_pin_rear_mag_lock , OUTPUT);//setting the rear mag lock relay pin as an output
      digitalWrite(relay_pin_rear_mag_lock , LOW);//setting the voltage on the rear mag lock relay pin
      pinMode( relay_pin_vibe, OUTPUT);//setting the vibe motor relay pin as an output
      digitalWrite(relay_pin_vibe, HIGH);//setting the voltage on the vibe motor relay pin
      oldGearState = false;
    }
    
    void loop() {
    
      ET.receiveData();
      readSerialData();
    
      if (inGear != oldGearState) {
        gearRelay();
        oldGearState = inGear;
      }
      if (relaytimer > 0)
      {
        if (millis() - relaytimer >= relayinterval)
        {
          digitalWrite(relay_pin_front_mag_lock, LOW);
          digitalWrite(relay_pin_rear_mag_lock, LOW);
          relaytimer = 0;
        }
      }
      vibeRelay();//function to control the shifter vibration
      }
    
    void receive(int numBytes) {}
    
    // This function checks for Gear data from SimTools GameDash
    
    void readSerialData() {
      if (Serial.available() == 5)  {  //if 5 bits available in the Serial buffer...
    
        int i;
        for (i = 0; i < 5; i = i + 1) { // read and label each byte.
          bufferArray[i] = Serial.read();
        }
    
        if (bufferArray[0]  == 'G') {
          GearGameDash = ((bufferArray[1] - 48) * 1000) + ((bufferArray[2] - 48) * 100) + ((bufferArray[3] - 48) * 10) +// Take values 1-4.
                         ((bufferArray[4] - 48) * 1);
          
          if (GearGameDash == 5) {
            inGear = false;
          }
          else {
            inGear = true;
          }
    
        }
        if (bufferArray[0]  == 'E') {
          GearGameDash = ((bufferArray[1] - 48) * 1000) + ((bufferArray[2] - 48) * 100) + ((bufferArray[3] - 48) * 10) +// Take values 1-4.
                         ((bufferArray[4] - 48) * 1);
          
          if (GearGameDash == 0) {
            engineRunning = false;
          }
          else {
            engineRunning = true;
          }
    
        }
      }
    }
    
    //This function checks if the gear box is synchronized and the shifter is trying to get into gear
    //If it is then it releases the magnets to allow the shifter to slot into position.
    
    void gearRelay() {
    
      if ((inGear == true) && (mydata.gearPressed == true))
      {
        relaytimer = millis();
        digitalWrite(relay_pin_front_mag_lock, HIGH);
        digitalWrite(relay_pin_rear_mag_lock, HIGH);
      }
    
    }
    
    //This function checks if the shifter is trying to get into gear while the gear box is not synchronized and the engine is running
    // If it is then it fires the vibe motor to simulate gear grinding on the shifter.
    void vibeRelay()  {
     
      if ((inGear == false) && (engineRunning == true) && (mydata.gearPressed == true))
      {
        digitalWrite(relay_pin_vibe, LOW);
      }
      else  {
        digitalWrite(relay_pin_vibe, HIGH);
      }
    }
    • Useful Useful x 1
    Last edited: May 17, 2024
  5. RiftFlyer

    RiftFlyer Active Member Gold Contributor

    Joined:
    Apr 15, 2014
    Messages:
    198
    Balance:
    1,711Coins
    Ratings:
    +121 / 0 / -0
    My Motion Simulator:
    DC motor
    Short video clip of the build which also links viewers back to this community forum:

  6. noorbeast

    noorbeast VR Tassie Devil Staff Member Moderator Race Director

    Joined:
    Jul 13, 2014
    Messages:
    21,395
    Occupation:
    Innovative tech specialist for NGOs
    Location:
    St Helens, Tasmania, Australia
    Balance:
    150,025Coins
    Ratings:
    +10,993 / 54 / -2
    My Motion Simulator:
    3DOF, DC motor, JRK
    • Like Like x 1