MHeironimus / ArduinoJoystickLibrary

An Arduino library that adds one or more joysticks to the list of HID devices an Arduino Leonardo or Arduino Micro can support.
GNU Lesser General Public License v3.0
2.07k stars 403 forks source link

Using a Leonardo to add elevator and aileron trim wheels to flight sim #75

Open Flycivil opened 6 years ago

Flycivil commented 6 years ago

I have created a joystick with the leonardo using your libraries however I am unable to convert the axes satisfactorily to act as trim wheels. Please could you advise me how the code may be changed? (If indeed this is possible). Thanks FlyCivil

MHeironimus commented 6 years ago

Sorry for the delay in getting back to you. This is possible to do, but the library does not currently support it. I hope to add some Flight Simulator enhancements in a future release and I will add this enhancement request to the backlog.

MrDannyPicard commented 3 years ago

This code i've posted on reddit actually use a potentiometer as my elevator trim. https://www.reddit.com/r/flightsim/comments/ir5t38/almost_finished_making_my_172_g1000_button_box/g4y7ecq/

ask away if you don't understand it.

pesce commented 3 years ago

I used an Arduino Pro Mini, rotary encoder, and mapped the outputs as buttons in FS2020. Works great. Also, printed this case: https://www.thingiverse.com/thing:4290141.. Had some issues with pasting the code.

-------------BEGIN CODE-------------

include

// Rotary Encoder Inputs

define CLK 2

define DT 3

define SW 4

int counter = 0; int currentStateCLK; int lastStateCLK; String currentDir =""; unsigned long lastButtonPress = 0;

// Create the Joystick Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_GAMEPAD, 2, 0, // Button Count, Hat Switch Count false, false, false, // no X and no Y, no Z Axis false, false, false, // No Rx, Ry, or Rz false, false, // No rudder or throttle false, false, false); // No accelerator, brake, or steering

void setup() { // Set encoder pins as inputs pinMode(CLK,INPUT); pinMode(DT,INPUT); pinMode(SW, INPUT_PULLUP);

// Setup Serial Monitor Serial.begin(9600);

// Read the initial state of CLK lastStateCLK = digitalRead(CLK); Joystick.begin(); }

void loop() { // Read the current state of CLK currentStateCLK = digitalRead(CLK);

// If last and current state of CLK are different, then pulse occurred // React to only 1 state change to avoid double count if (currentStateCLK != lastStateCLK && currentStateCLK == 1){

// If the DT state is different than the CLK state then
// the encoder is rotating CW so increment
if (digitalRead(DT) != currentStateCLK) {
  counter ++;
  currentDir ="CW";
  Joystick.setButton(0, HIGH); //tap that button
  delay(50);
  Joystick.setButton(0, LOW); //let go of the button
 } else {
 // Encoder is rotating CCW so decrement
 counter --;
 currentDir ="CCW";
 Joystick.setButton(1, HIGH);
 delay(50);
 Joystick.setButton(1, LOW);
}

Serial.print("Direction: ");
Serial.print(currentDir);
Serial.print(" | Counter: ");
Serial.println(counter);

}

// Remember last CLK state lastStateCLK = currentStateCLK;

// Put in a slight delay to help debounce the reading delay(1); }

-------------END CODE-------------

adamburrito commented 3 years ago

I used an Arduino Pro Mini, rotary encoder, and mapped the outputs as buttons in FS2020. Works great. Also, printed this case: https://www.thingiverse.com/thing:4290141.. Had some issues with pasting the code.

How fortuitous, I just got my first Leonardo today for exactly the same project... I've already made that same trim wheel (works great) but wanted to use it in MSFS2020 so needed this Leonardo (or joystick card) since the software linked in that trim wheel video only works for Xplane. Anyway, I have decent amount of experience using Arduino Mini's and Mega clones with other projects, so think I sorta know what I'm doing... But I tried your code for my Leonardo clone (Keyestudio clone), my WIndows 10 sees it as a joystick, I connect the ground and the two outputs A and B to digital pins 2 and 3 but I'm seeing erratic behavior with the button input in the joystick properties. Do you have to connect diodes or anything to get this to work properly or can you connect the encoder directly to the leonardo as I have done? I'm using WayinTop 5 Set 360 Degree Rotary Encoder Code Switch Push Button EC11 Digital Potentiometer with Switchs purchased off amazon, they work great with my other arduinos and I also use them with some Leo Bodnar boards I have (which is what I'm trying to mimic with the leonardo as it's substantially cheaper!) Thanks for any help in advance!

Flycivil commented 3 years ago

I used a denounce circuits for Arduinos with rotary encoders to eliminate this. The Leobodnars however work without the need (maybe why more expensive?).Sent from Samsung tablet. -------- Original message --------From: adamburrito notifications@github.com Date: 11/01/2021 03:29 (GMT+00:00) To: MHeironimus/ArduinoJoystickLibrary ArduinoJoystickLibrary@noreply.github.com Cc: Flycivil pdvw@btinternet.com, Author author@noreply.github.com Subject: Re: [MHeironimus/ArduinoJoystickLibrary] Using a Leonardo to add elevator and aileron trim wheels to flight sim (#75)

I used an Arduino Pro Mini, rotary encoder, and mapped the outputs as buttons in FS2020. Works great. Also, printed this case: https://www.thingiverse.com/thing:4290141.. Had some issues with pasting the code.

How fortuitous, I just got my first Leonardo today for exactly the same project... I've already made that same trim wheel (works great) but wanted to use it in MSFS2020 so needed this Leonardo (or joystick card) since the software linked in that trim wheel video only works for Xplane. Anyway, I have decent amount of experience using Arduino Mini's and Mega clones with other projects, so think I sorta know what I'm doing... But I tried your code for me Leonardo clone (Keyestudio clone), my WIndows 10 sees it as a joystick, I connect the ground and the two outputs A and B to digital pins 2 and 3 but I'm seeing erratic behavior with the button input in the joystick properties. Do you have to connect diodes or anything to get this to work properly or can you connect the encoder directly to the leonardo as I have done? I'm using these encoders purchased off amazon, they work great with my other arduinos and I also use them with some Leo Bodnar boards I have (which is what I'm trying to mimic with the leonardo as it's substantially cheaper!) Thanks for any help in advance!

—You are receiving this because you authored the thread.Reply to this email directly, view it on GitHub, or unsubscribe. [ { "@context": "http://schema.org", "@type": "EmailMessage", "potentialAction": { "@type": "ViewAction", "target": "https://github.com/MHeironimus/ArduinoJoystickLibrary/issues/75#issuecomment-757606424", "url": "https://github.com/MHeironimus/ArduinoJoystickLibrary/issues/75#issuecomment-757606424", "name": "View Issue" }, "description": "View this Issue on GitHub", "publisher": { "@type": "Organization", "name": "GitHub", "url": "https://github.com" } } ]

pesce commented 3 years ago

Excellent! No, I didn't use any diodes or anything else. I did have to connect all 3 outputs of the rotary encoder though. CLK -> pin 2, DT -> 3, and SW -> 4. When I tried to use it without the SW input, I saw some strange behavior. Let me know if that helps. Also, the serial monitor should display the rotary encoder output.. nothing while sitting still and then counting up or down depending on the direction it is turned.

On Sun, Jan 10, 2021 at 7:30 PM adamburrito notifications@github.com wrote:

I used an Arduino Pro Mini, rotary encoder, and mapped the outputs as buttons in FS2020. Works great. Also, printed this case: https://www.thingiverse.com/thing:4290141.. Had some issues with pasting the code.

How fortuitous, I just got my first Leonardo today for exactly the same project... I've already made that same trim wheel (works great) but wanted to use it in MSFS2020 so needed this Leonardo (or joystick card) since the software linked in that trim wheel video only works for Xplane. Anyway, I have decent amount of experience using Arduino Mini's and Mega clones with other projects, so think I sorta know what I'm doing... But I tried your code for me Leonardo clone (Keyestudio clone), my WIndows 10 sees it as a joystick, I connect the ground and the two outputs A and B to digital pins 2 and 3 but I'm seeing erratic behavior with the button input in the joystick properties. Do you have to connect diodes or anything to get this to work properly or can you connect the encoder directly to the leonardo as I have done? I'm using these encoders purchased off amazon, they work great with my other arduinos and I also use them with some Leo Bodnar boards I have (which is what I'm trying to mimic with the leonardo as it's substantially cheaper!) Thanks for any help in advance!

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/MHeironimus/ArduinoJoystickLibrary/issues/75#issuecomment-757606424, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABB2RM3CMDGSJQB3MDWO62DSZJWDNANCNFSM4EMECWDA .

adamburrito commented 3 years ago

Excellent! No, I didn't use any diodes or anything else. I did have to connect all 3 outputs of the rotary encoder though. CLK -> pin 2, DT -> 3, and SW -> 4. When I tried to use it without the SW input, I saw some strange behavior. Let me know if that helps. Also, the serial monitor should display the rotary encoder output.. nothing while sitting still and then counting up or down depending on the direction it is turned.

Hey, thanks guys for responding to my query. I'll look into a debounce circuit perhaps if I can't get this thing going with Pesce's help, but if he's not needing it with his setup then I'd prefer to go his route.

So Pesce, I tried to connect both grounds, DT, CLK, and SW to those pins (I've also switched to code to try other pins to eliminate the possibility of bad pins on my new board), and I still can't get it to work. Strangely, just handling the board, even with no pins connected, will cause the serial monitor to go crazy with either CW or CWW counts, and with the pins connected I do see my inputs registering into the monitor during the flow of uncontrolled CW or CWW counts, so something is happening. However, I never see the click/switch input. I've soldered up the rotary encoder (like the many others I've worked with successfully before), tried different combos of pins, switching them around, and I keep getting the same results. I've also tested other sketches, like the examples in MatthewH's joystick library, and I do see the expected results of the rotary encoder showing both inputs of joystick buttons being pressed when I rotate the encoder (basically, working as a button but not properly, hence why I need something like your code), but more importantly I do see the button press/click with the encoder with their examples.

So, I'm wondering if it's possible there's something in your code that you posted, maybe something missing? I think you mentioned in the post that you had trouble uploading the code. Any chance you could double check and see if that code you posted is indeed what you're using to make it work? Thanks again for your help!!!

RafaPolit commented 1 year ago

I used an Arduino Pro Mini, rotary encoder, and mapped the outputs as buttons in FS2020. Works great. Also, printed this case: https://www.thingiverse.com/thing:4290141.. Had some issues with pasting the code.

I have used your example as base, and have created a code to include 4 rotary encoders. Here's my approach if it helps anyone. Yours helped me to get me started, I appreciate it.

Note, the delay on the encoders is set to really low: 2ms. You almost don't see the buttons light up in the USB game controller in windows, but they work correctly. Your proposed 50ms did not allow things like naturally calculated acceleration (SPAD.neXt) and similar approaches.

// 4 Rotary Encoders with click
//--------------------------------------------------------------------
#include <Joystick.h>

// Time between readings
const int rotaryInterval = 1;
const int buttonInterval = 50;

// Rotary Encoder Inputs
int CLK[4] = { 2, 5, 21, 18 };
int DT[4] = { 3, 6, 20, 8 };
int SW[4] = { 4, 7, 19, 9 };

int counter[4] = { 0, 0, 0, 0 };
int currentStateCLK[4];
int lastStateCLK[4];
String currentDir[4] = { "", "", "", "" };
unsigned long lastButtonState[4] = { 0, 0, 0, 0 };

unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()
unsigned long previousRotaryMillis = 0; // time when rotary change was last checked
unsigned long previousButtonMillis = 0; // time when button press last checked

Joystick_ Joystick;

void setup() {
  for (int index = 0; index < 4; index++) {
    // Initialize Encoder Pins
    pinMode(CLK[index], INPUT);
    pinMode(DT[index], INPUT);
    pinMode(SW[index], INPUT_PULLUP);
  }

  for (int index = 0; index < 4; index++) {
    // Read the initial state of CLK
    lastStateCLK[index] = digitalRead(CLK[index]);
  }

  // Initialize Joystick Library
  Joystick.begin();
}

void loop() {
  // Notice that none of the action happens in loop() apart from reading millis()
  //   it just calls the functions that have the action code

  currentMillis = millis();   // capture the latest value of millis()
                              // this is equivalent to noting the time from a clock
                              // use the same time for all LED flashes to keep them synchronized

  readRotary();
  readButton();
}

void readRotary() {
  if (currentMillis - previousRotaryMillis >= rotaryInterval) {
    for (int index = 0; index < 4; index++) {
      // Read the current state of CLK
      currentStateCLK[index] = digitalRead(CLK[index]);

      // If last and current state of CLK are different, then pulse occurred
      // React to only 1 state change to avoid double count
      if (currentStateCLK[index] != lastStateCLK[index] && currentStateCLK[index] == 1) {

        // If the DT state is different than the CLK state then
        // the encoder is rotating CW so increment
        if (digitalRead(DT[index]) != currentStateCLK[index]) {
          Joystick.setButton(index * 3, HIGH);  //tap that button
          delay(2);
          Joystick.setButton(index * 3, LOW);  //let go of the button
        } else {
          // Encoder is rotating CCW so decrement
          Joystick.setButton(index * 3 + 1, HIGH);
          delay(2);
          Joystick.setButton(index * 3 + 1, LOW);
        }
      }

      // Remember last CLK state
      lastStateCLK[index] = currentStateCLK[index];

      // Update Previous Milis
      previousRotaryMillis += rotaryInterval;
    }
  }
}

void readButton() {
  if (millis() - previousButtonMillis >= buttonInterval) {
    for (int index = 0; index < 4; index++) {
      int currentButtonState = !digitalRead(SW[index]);
      if (currentButtonState != lastButtonState[index])
      {
        Joystick.setButton(index * 3 + 2, currentButtonState);
        lastButtonState[index] = currentButtonState;
      }
    }

    // Update Previous Milis
    previousButtonMillis += buttonInterval;
  }
}