Joystick Receiving data While Transmitting

Hi,

We made a new joystick with a 20x4 LCD. We want to see depth-arm/disarm data on the LCD screen.

But with serial communication, it doesn’t work.

How can we do that? If anyone knows something it will help a lot!

Thanks.

Hi @ugurdemirezen,

What do you mean by this? Does your custom joystick have some kind of support for serial communication with the computer it’s connected to?

Assuming there’s some way to send data to your joystick/directly to the screen, you should be able to get the depth and arming state from a MAVLink connection (e.g. using Pymavlink), which you can then send through to the joystick/screen.

Hi @EliotBR,

We are using Arduino Leonardo on our joystick.

I wrote the code that can get the data from a MAVLink connection.

But when we add the Serial.begin(" "); and serial.println() lines to the joystick codes, the joystick receives data but can’t transmit the data to the computer and ROV.

Good to know

Great!

A few questions/comments:

  • How is the Arduino sending the normal joystick signals/data? Is that through the same connection as the serial communication? Could they be interfering with each other?
  • Serial.begin takes in a number specifying the baudrate, not a string with a space
  • Why are you using serial.println? Shouldn’t the joystick be just receiving the MAVLink information from the computer, not sending things back?

Yes it’s the same connection. Yes they could. Because when we connected joystick to computer the joystick does not work after 2 sec.

I am new in the arduino things. I tried with that. If you know something better I am glad to try and learn that!

Thanks a lot @EliotBR

If serial.println is working fine for the joystick connection normally then it should be fine to use.


Are you able to share a minimal example of the code you’re using, so we can see if there’s anything that stands out as likely causing the issue(s)?

If not there’s not very much we can do to help, given we don’t know basically anything about how your system is connected or how it runs.

I can send it via mail to you if it’s okay.

If you send it via private message (click my profile, click message) I can take a look, but if it’s not public and isn’t direct support for one of our products then I won’t be able to spend much time on it.

I talked with my colleagues and he said it’s okay to share it.
Here is the Arduino code it’ has just basic serial communication. And the python code just sends data constantly.

#include <Keypad.h>
#include <Joystick.h>
#include <LiquidCrystal_I2C.h>
int yled=6;
int kled=0;
int buton=0;
LiquidCrystal_I2C lcd(0x27,20,4); // Bu kodu kullanırken ekranda yazı çıkmaz ise 0x27 yerine 0x3f yazınız !!
 
//DEFINITIONS
#define ENABLE_PULLUPS
#define NUMROTARIES 4 //replace "?" with number of rotary encoders you are using
#define NUMBUTTONS 25 //replace "?"with number of buttong you are using
#define NUMROWS 5 //replace "?" with number of rows you have
#define NUMCOLS 5 //replace "?" with number of columns you have
 
//BUTTON MATRIX
//first change number of rows and columns to match your button matrix, 
//then replace all "?" with numbers (starting from 0)
byte buttons[NUMROWS][NUMCOLS] = {
  {0,1,2,3,4},
  {5,6,7,8,9},
  {10,11,12,13,14},
  {15,16,17,18,19},
  {20,21,22,23,24},
  
 
 
};
 
struct rotariesdef {
  byte pin1;
  byte pin2;
  int ccwchar;
  int cwchar;
  volatile unsigned char state;
};
 
//ROTARY ENCODERS
//each line controls a different rotary encoder
//the first two numbers refer to the pins the encoder is connected to 
//the second two are the buttons each click of the encoder wil press 
//do NOT exceed 31 for the final button number
rotariesdef rotaries[NUMROTARIES] {
  {0,1,22,23,0}, //rotary 1
  {2,3,24,25,0}, //rotary 2
  {4,5,26,27,0}, //rotary 3
  {6,7,28,29,0} //rotary 4
 
};
 
#define DIR_CCW 0x10
#define DIR_CW 0x20
#define R_START 0x0
 
#ifdef HALF_STEP
#define R_CCW_BEGIN 0x1
#define R_CW_BEGIN 0x2
#define R_START_M 0x3
#define R_CW_BEGIN_M 0x4
#define R_CCW_BEGIN_M 0x5
const unsigned char ttable[6][4] = {
  // R_START (00)
  {R_START_M,            R_CW_BEGIN,     R_CCW_BEGIN,  R_START},
  // R_CCW_BEGIN
  {R_START_M | DIR_CCW, R_START,        R_CCW_BEGIN,  R_START},
  // R_CW_BEGIN
  {R_START_M | DIR_CW,  R_CW_BEGIN,     R_START,      R_START},
  // R_START_M (11)
  {R_START_M,            R_CCW_BEGIN_M,  R_CW_BEGIN_M, R_START},
  // R_CW_BEGIN_M
  {R_START_M,            R_START_M,      R_CW_BEGIN_M, R_START | DIR_CW},
  // R_CCW_BEGIN_M
  {R_START_M,            R_CCW_BEGIN_M,  R_START_M,    R_START | DIR_CCW},
};
#else
#define R_CW_FINAL 0x1
#define R_CW_BEGIN 0x2
#define R_CW_NEXT 0x3
#define R_CCW_BEGIN 0x4
#define R_CCW_FINAL 0x5
#define R_CCW_NEXT 0x6
 
const unsigned char ttable[7][4] = {
  // R_START
  {R_START,    R_CW_BEGIN,  R_CCW_BEGIN, R_START},
  // R_CW_FINAL
  {R_CW_NEXT,  R_START,     R_CW_FINAL,  R_START | DIR_CW},
  // R_CW_BEGIN
  {R_CW_NEXT,  R_CW_BEGIN,  R_START,     R_START},
  // R_CW_NEXT
  {R_CW_NEXT,  R_CW_BEGIN,  R_CW_FINAL,  R_START},
  // R_CCW_BEGIN
  {R_CCW_NEXT, R_START,     R_CCW_BEGIN, R_START},
  // R_CCW_FINAL
  {R_CCW_NEXT, R_CCW_FINAL, R_START,     R_START | DIR_CCW},
  // R_CCW_NEXT
  {R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START},
};
#endif
 
//BUTTON MATRIX PART 2
byte rowPins[NUMROWS] = {5,9,8,7,3}; //change "?" to the pins the rows of your button matrix are connected to
byte colPins[NUMCOLS] = {10,11,12,13,4}; //change "?" to the pins the rows of your button matrix are connected to
 
Keypad buttbx = Keypad( makeKeymap(buttons), rowPins, colPins, NUMROWS, NUMCOLS);
 
//JOYSTICK SETTINGS
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,
  JOYSTICK_TYPE_JOYSTICK,
  25, //number of buttons
  0, //number of hat switches
  //Set as many axis to "true" as you have potentiometers for
  true, // y axis
  true, // x axis
  true, // z axis
  true, // rx axis
  false, // ry axis
  false, // rz axis
  false, // rudder
  false, // throttle
  false, // accelerator
  false, // brake
  false); // steering wheel
 
const int numReadings = 20;
 
int readings[numReadings];      // the readings from the analog input
int index = 0;              // the index of the current reading
int total = 0;                  // the running total
int currentOutputLevel = 0;
 
//POTENTIOMETERS PART 1
//add all the axis' which are enabled above
int YAxis_ = 0;
int XAxis_ = 0;  
int ZAxis_ = 0;  
int RxAxis_ = 0;
int aa=1;
               
//POTENTIOMETERS  PART 2
//Which pins are your potentiometers connected to?
int potentiometerPin1 = A2; //Change "?" to the pin your potentiometer is connected to
int potentiometerPin2 = A1;
int potentiometerPin3 = A0;   //z
int potentiometerPin4 = A3;//  dalma
int potentiometerPin5 = A5;//  dalma
int potentiometerPin6 = A0;//  dalma
const bool initAutoSendState = true;
 
void setup() {
  Serial.begin(115200);
 Serial.setTimeout(1);
  lcd.begin();

pinMode(yled,INPUT_PULLUP);
pinMode(kled,INPUT_PULLUP);
Serial.begin(115200);
 
  pinMode(aa,INPUT_PULLUP);
  Joystick.begin();
  rotary_init();
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
}
 
void loop() {
while (!Serial.available());
 x = Serial.readString().toInt();
  digitalWrite(yled,1);
  digitalWrite(kled,1);
  CheckAllEncoders();
  CheckAllButtons();
  CheckAllPotentiometers();
  if(digitalRead(aa)==0)
  {
    Joystick.pressButton(aa);
  }
  else
  {
    Joystick.releaseButton(aa);
  }

}
 
//POTENTIOMETERS PART 3
//change the details to match teh details above for each potentiometer you are using
void CheckAllPotentiometers(){
                           
  ///potentiometer 1
  currentOutputLevel = getAverageOutput(potentiometerPin1);  // y ekseni a5
  YAxis_ = map(currentOutputLevel,1023,0,0,255);
  Joystick.setYAxis(YAxis_); 
 
  //potentiometer 2
  currentOutputLevel = getAverageOutput(potentiometerPin2);  //x ekseni a4
  XAxis_ = map(currentOutputLevel,0 ,1023,0,255);
  Joystick.setXAxis(XAxis_);
 
  //potentiometer 3
  currentOutputLevel = getAverageOutput(potentiometerPin3);  //xekseni a3
  ZAxis_= map(currentOutputLevel,1023,0,255,10);
  Joystick.setZAxis(ZAxis_);
 
  //potentiometer 4   
  currentOutputLevel = getAverageOutput(potentiometerPin4);  // y dönmesi a2
  RxAxis_= map(currentOutputLevel,1023,0,0,255);
  Joystick.setRxAxis(RxAxis_);
 
 
}
 
int getAverageOutput(int pinToRead){
  index = 0;
  total = 0; 
 
  while (index < numReadings){
    readings[index] = analogRead(pinToRead);
    total = total + readings[index];
    index = index + 1;
    //delay (1);
  }
  return total / numReadings;
}
 
void CheckAllButtons(void) {
      if (buttbx.getKeys())
    {
       for (int i=0; i<LIST_MAX; i++)   
        {
           if ( buttbx.key[i].stateChanged )   
            {
            switch (buttbx.key[i].kstate) { 
                    case PRESSED:
                    case HOLD:
                              Joystick.setButton(buttbx.key[i].kchar, 1);
                              buton=buttbx.key[i].kchar, 1;
                              Serial.println(buton);
                              if(buton==9){
                                  Serial.println("4");
                                }
                              else if(buton==0){
                                  Serial.println("5");
                                }
                              break;
                    case RELEASED:
                    case IDLE:
                              Joystick.setButton(buttbx.key[i].kchar, 0);
                              break;
            }
           }   
         }
     }
}
 
void rotary_init() {
  for (int i=0;i<NUMROTARIES;i++) {
    pinMode(rotaries[i].pin1, INPUT);
    pinMode(rotaries[i].pin2, INPUT);
    #ifdef ENABLE_PULLUPS
      digitalWrite(rotaries[i].pin1, HIGH);
      digitalWrite(rotaries[i].pin2, HIGH);
    #endif
  }
}
 
unsigned char rotary_process(int _i) {
  //Serial.print("Processing rotary: ");
  //Serial.println(_i);
  unsigned char pinstate = (digitalRead(rotaries[_i].pin2) << 1) | digitalRead(rotaries[_i].pin1);
  rotaries[_i].state = ttable[rotaries[_i].state & 0xf][pinstate];
  return (rotaries[_i].state & 0x30);
}
 
void CheckAllEncoders(void) {

  for (int i=0;i<NUMROTARIES;i++) {
    unsigned char result = rotary_process(i);
    if (result == DIR_CCW) {
      
      Joystick.setButton(rotaries[i].ccwchar, 1); delay(50); Joystick.setButton(rotaries[i].ccwchar, 0);
    };
    if (result == DIR_CW) {
     
      Joystick.setButton(rotaries[i].cwchar, 1); delay(50); Joystick.setButton(rotaries[i].cwchar, 0);
    };
  }

}

You call Serial.begin twice here (which doesn’t really make sense).

This line does nothing while waiting for serial data to be available, which seems odd given you already have a Serial.setTimeout call in the setup function (presumably it would make more sense to set an appropriate timeout, rather than writing your own ‘endless timeout’ code and then applying a short timeout afterwards). It also means no buttons are checked and no joystick messages can be sent while the code is waiting for serial data. I expect this line can be removed.

I expect you want to use Serial.parseInt() here instead, and you should likely be sending a non-numerical character between each number you send so that it knows when each number is finished (you may already be doing that part, depends on the code running on your computer).

This waits for serial input for the timeout you’ve set (or until it reaches a non-numerical character) and stops the rest of your program in the meantime (which may be fine, if the timeout is reasonably short and/or the data is sent quite frequently).

This seems to just be wasting time. If those lights aren’t going to be changed anywhere else then they should just be turned on in the setup function.

This code is very reliant on the serial reads that come before it - if they’re slow then this doesn’t get run frequently. It may be worth looking into setting up a time-based interrupt or similar so that this can run more regularly, although I’d suggest trying the other changes first.