Go Down

Topic: [SOLVED]Arcade trackball to usb mouse help (Read 11198 times) previous topic - next topic

Riva

#15
Nov 04, 2017, 09:33 am Last Edit: Nov 04, 2017, 09:34 am by Riva
Okay so I don't know if this matters or not but I have the Pro Micro, but it shows up in the Arduino IDE as a Leonardo... 
Does not matter for this.

I tried to add more buttons and such to the code and I'm getting some funny things happening and the track ball is hooked up to A0-A3 (I assume from the code) but it isn't doing anything... 
Try getting the code working with the 4 buttons first (on the pins specified) and then start to expand on that if it works. The encoders are connected to digital pins 0-3 not analogue pins A0-A3 as the pins 0-3 are external interrupt pins and give the best results with the encoders (read the blurb on the page I had linked the library to).


Furthermore in windows game controller properties it shows 32 buttons, a stick, rudder, throttle, POV Hat, and x/y axis.  Is this supposed to happen?
Yes. The Joystick library defines the maximum number of axis/buttons usable but you don't need to use them all.

  Also some of the buttons show as pressed and I have nothing hooked up to the other pins on the Micro... 
This is probably because you have altered the code and have the encoders connected to the wrong pins.

The pins are very strange on my board compared to an UNO or something else.  The pin numbers skip around, I assume that all the numbered pins are just the digital pins and the "A" pins are the analog pins?  As you will see in the code I assumed that all the digital pins could be used as buttons?
Yes the pin numbers do jump around a bit but if you get the pin map from Sparkfun you will see where they all fit. Analogue pins can also be used for digital signals but digital pins cannot be used for analogue.

What does this part of the code mean:
// Constant that maps the phyical pin to the joystick button.
const int pinToButtonMap = 9;

It is the base pin number from where the buttons are defined.
Don't PM me for help as I will ignore it.

hydrolisk1792

I'm not understanding what the base pin number is for and why it is needed. I did hook up the trackball to the other pins after reading this and am now getting button presses in the windows properties instead of the joystick moving around in the properties window. :smiley-confuse:
I make things do what they were never intended to do :P

Riva

I'm not understanding what the base pin number is for and why it is needed. I did hook up the trackball to the other pins after reading this and am now getting button presses in the windows properties instead of the joystick moving around in the properties window. :smiley-confuse:
What pins did you connect the trackball to?
Don't PM me for help as I will ignore it.

hydrolisk1792

Quote
what pins did you connect the trackball to?
A0 - A3
I make things do what they were never intended to do :P

Riva

Assuming you have a genuine (or standard clone) of the Sparkfun Pro Micro then the pinout for it is here and the pins you should be using for the encoders are pins 0-3 NOT A0-A3.
I see from this pinout there is no pins 11-12 on the pro micro so you should also have 4 buttons that connect GND to pins 4-7 and alter the sketch line to
Code: [Select]
const int pinToButtonMap = 4;
and
Code: [Select]
 // Initialize 4 Button Pins
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
Don't PM me for help as I will ignore it.

hydrolisk1792

So that means that i hook trackball up to the teal coloured numbered pins on the sparkfun pinout and i can have all the other pins as buttons that activate when shorted to ground? So by hooki g trackball to the pins you specified it will manipulate the joystick portion of the windows properties window and the buttons will manipulate the buttons in the windows properties window?
I make things do what they were never intended to do :P

Riva

So that means that i hook trackball up to the teal coloured numbered pins on the sparkfun pinout and i can have all the other pins as buttons that activate when shorted to ground? So by hooki g trackball to the pins you specified it will manipulate the joystick portion of the windows properties window and the buttons will manipulate the buttons in the windows properties window?
If your Teal is what the image legend names as 'Arduino' then you should get movement of the joystick X/Y axis when the trackball is rotated. The code is a simple test and should simulate the joystick being pushed hard over in the trackball direction of rotation. The same with the buttons on the pins 4-7.
This code is only a test that things are connected properly and will need changing to add extra buttons and adjust the trackball operation to suit your needs.
Don't PM me for help as I will ignore it.

hydrolisk1792

If your Teal is what the image legend names as 'Arduino' then you should get movement of the joystick X/Y axis when the trackball is rotated. The code is a simple test and should simulate the joystick being pushed hard over in the trackball direction of rotation. The same with the buttons on the pins 4-7.
This code is only a test that things are connected properly and will need changing to add extra buttons and adjust the trackball operation to suit your needs.

Okay will do. Ill try that as soon as i get home. Thank you.
I make things do what they were never intended to do :P

hydrolisk1792

#23
Nov 07, 2017, 03:52 am Last Edit: Nov 07, 2017, 06:58 am by hydrolisk1792
Okay, so I did as you stated and modified the code and got everything to work.  How would I go about making the trackball a lot less sensitive and more like the joystick?  I can already tell by my test that I will need to somehow make a dead zone so the computer will realize that if I'm rolling the ball Up it actually goes up and ignores the little fidgets from side to side for instance.  Also I'm looking for a way to have the acceleration taken into account. Like the faster I roll it the more the joystick registers in that direction.  Like when you push just a bit on an actual analog joystick it goes a little bit in that direction.  It is all working how you stated it would though, so many thanks to you for all your help thus far and I gave you some good karma for putting up with me though all this.  I know I can be a bit annoying with simple to answer questions and all.  I'm new to this but am learning a lot from you and I thank you for that as well.

Furthermore, how would I go about adding one more actual rotary encoder to the sketch as the Z axis.  I tried doing it and all I get is it fidgeting back and forth in the properties window.  I took the X axis and copied it and changed all the values that had "X" and changed them to Z and reduced the numbers to 63 and -63 but that didn't seem to work the way I hoped.  Also if you could get this working, is there a way to have it accelerate the faster I turn the knob is that direction?  I did this on pins 4 & 5.

I'm also having trouble adding buttons above pin ten.  I'm getting the same result as last time where some of the buttons are locked down like they are being pressed even though they aren't.  I'll post my code.

EDIT:  I went ahead and installed some 1K pullup resistors on pins 4 & 5 but that didn't seem to fix the problem.  I was reading on a different forum that sometimes the rotary encoder needs theses resistors to operate properly, however that didn't seem to do the trick :( Also should I be hooking the centre pin of the encoder to GND or 5VDC?  I currently have it hooked to GND.

Code: [Select]


#include <Encoder.h>
#include <Joystick.h>

// Constant that maps the phyical pin to the joystick button.
const int pinToButtonMap = 6;
 
Encoder axisX(0, 1);
Encoder axisY(2, 3);
Encoder axisZ(4, 5);

void setup() {
  // Initialize Buttons

  pinMode(6, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(14, INPUT_PULLUP);
  pinMode(15, INPUT_PULLUP);
  pinMode(16, INPUT_PULLUP);
  pinMode(18, INPUT_PULLUP);
  pinMode(19, INPUT_PULLUP);
  pinMode(20, INPUT_PULLUP);
  pinMode(21, INPUT_PULLUP);
 
 
  // Initialize Joystick Library
  Joystick.begin(false);
}

void loop() {
  Joystick.setXAxis(0);               // Center joystick X
  int newX = axisX.read();            // Read X encoder
  if (newX > 0)                       // Has the value increased since last read
  {
    Joystick.setXAxis(127);           // Set joystick X hard over to right
    axisX.write(0);                   // Zero encoder count for next time
 }
  if (newX < 0)                       // Has encoder decreased since last read
  {
    Joystick.setXAxis(-127);          // Set joystick hard left
    axisX.write(0);                   // Zero encoder count
  }
 
  Joystick.setYAxis(0);               // Center joystick Y
  int newY = axisY.read();
  if (newY > 0)
  {
    Joystick.setYAxis(127);
    axisY.write(0);
  }
  if (newY < 0)
  {
    Joystick.setYAxis(-127);
    axisY.write(0);
  }

  Joystick.setZAxis(0);               // Center joystick Z
  int newZ = axisZ.read();
  if (newZ > 0)
  {
    Joystick.setZAxis(63);
    delay(50);
    axisZ.write(0);
  }
  if (newZ < 0)
  {
    Joystick.setZAxis(-63);
    delay(50);
    axisZ.write(0);
  }

  // Read button pin values
  for (byte index = 0; index < 12; index++)
  {
    byte currentButtonState = !digitalRead(index + pinToButtonMap); // Read button state
    Joystick.setButton(index, currentButtonState);                  // Set state in joystick
  }

  Joystick.sendState();               // Send the joystick data
  delay(50);                          // Wait a bit
}

I make things do what they were never intended to do :P

Riva

A lot of questions...
Adding more encoders is possible but it may impact the performance of the first 2 encoders. From the encoder page I linked it...
Quote
Encoders have 2 signals, which must be connected to 2 pins. There are three options.
    Best Performance: Both signals connect to interrupt pins.
    Good Performance: First signal connects to an interrupt pin, second to a non-interrupt pin.
    Low Performance: Both signals connect to non-interrupt pins, details below.
I would then suggest change to the 'good performance' model and have one encoder pin connected to an interrupt pin (pins 0-3) instead of the current two pins.

The button reading code was only for testing the joystick library worked as expected and is not really suitable for more buttons like this as it cannot cope well non contiguous pin numbers, as you have found.
I suggest putting the button pin numbers into an array and then using that array to configure the pins and read them.

A dead zone might not be so important if you can make the trackball act like an analogue joystick as the off axis values will be small when rolling in a single direction compared to the test code that makes any movement in any axis a full joystick axis move.
A possible way to do the acceleration is to count the number of changes in an axis within a fixed time interval as this will be higher the faster the encoder is rotated, you then map this change value to the amount of joystick movement.
I don't have the hardware to check what value you would get for this so you will need to work on this (with a bit of help).
I would start with loading the original encoder code posted on the library web page that prints the encoder changes to the Serial monitor and then modify it to suit your encoder pins and time interval, and run it.
Start turning the encoder at a fixed speed that sort of matches your minimum joystick movement so you get several results printed in the serial monitor and then do the same at the speed you would expect for full joystick movement. This should give an idea of the min/max values used for acceleration.
Once you have that the code can be altered to use it.
I will try to make time to change the code to suit more buttons and post it here but I'm working (or meant to be :) so might not have time.


Don't PM me for help as I will ignore it.

Riva

Try this sketch to test the encoder counts at different speeds.
Code: [Select]

#include <Encoder.h>

// Change these pin numbers to the pins connected to your encoder.
//   Best Performance: both pins have interrupt capability
//   Good Performance: only the first pin has interrupt capability
//   Low Performance:  neither pin has interrupt capability
Encoder knobLeft(0, 1);
Encoder knobRight(2, 3);
//   avoid using pins with LEDs attached

void setup() {
  Serial.begin(115200);
  Serial.println("TwoKnobs Encoder Test:");
}

void loop() {
  int newLeft, newRight;
  newLeft = knobLeft.read();
  newRight = knobRight.read();
  if (newLeft != 0 || newRight != 0) {
    Serial.print("Left = ");
    Serial.print(newLeft);
    Serial.print(", Right = ");
    Serial.print(newRight);
    Serial.println();
    knobLeft.write(0);
    knobRight.write(0);
  }
  delay(50);
}
Don't PM me for help as I will ignore it.

Riva

And this sketch is your code modified to allow the reading of all buttons.
Code: [Select]

#include <Encoder.h>
#include <Joystick.h>

Encoder axisX(0, 1);
Encoder axisY(2, 3);
Encoder axisZ(4, 5);

const byte buttonArray[] = {6, 7, 8, 9, 10, 14, 15, 16, 18, 19, 20, 21};

void setup() {
  // Initialize Buttons
  for(byte x = 0; x < sizeof(buttonArray); x++)
  {
    pinMode(buttonArray[x], INPUT_PULLUP);
  }
 
  // Initialize Joystick Library
  Joystick.begin(false);
}

void loop() {
  Joystick.setXAxis(0);               // Center joystick X
  int newX = axisX.read();            // Read X encoder
  if (newX > 0)                       // Has the value increased since last read
  {
    Joystick.setXAxis(127);           // Set joystick X hard over to right
    axisX.write(0);                   // Zero encoder count for next time
  }
  if (newX < 0)                       // Has encoder decreased since last read
  {
    Joystick.setXAxis(-127);          // Set joystick hard left
    axisX.write(0);                   // Zero encoder count
  }
 
  Joystick.setYAxis(0);               // Center joystick Y
  int newY = axisY.read();
  if (newY > 0)
  {
    Joystick.setYAxis(127);
    axisY.write(0);
  }
  if (newY < 0)
  {
    Joystick.setYAxis(-127);
    axisY.write(0);
  }
 
  Joystick.setZAxis(0);               // Center joystick Z
  int newZ = axisZ.read();
  if (newZ > 0)
  {
    Joystick.setZAxis(63);
    delay(50);
    axisZ.write(0);
  }
  if (newZ < 0)
  {
    Joystick.setZAxis(-63);
    delay(50);
    axisZ.write(0);
  }
 
  // Read button pin values
  for(byte x = 0; x < sizeof(buttonArray); x++)
  {
    byte currentButtonState = !digitalRead(buttonArray[x]);   // Read button state
    Joystick.setButton(x, currentButtonState);                // Set state in joystick
  }
 
  Joystick.sendState();               // Send the joystick data
  delay(50);                          // Wait a bit
}
Don't PM me for help as I will ignore it.

hydrolisk1792

And this sketch is your code modified to allow the reading of all buttons.
Code: [Select]

#include <Encoder.h>
#include <Joystick.h>

Encoder axisX(0, 1);
Encoder axisY(2, 3);
Encoder axisZ(4, 5);

const byte buttonArray[] = {6, 7, 8, 9, 10, 14, 15, 16, 18, 19, 20, 21};

void setup() {
  // Initialize Buttons
  for(byte x = 0; x < sizeof(buttonArray); x++)
  {
    pinMode(buttonArray[x], INPUT_PULLUP);
  }
 
  // Initialize Joystick Library
  Joystick.begin(false);
}

void loop() {
  Joystick.setXAxis(0);               // Center joystick X
  int newX = axisX.read();            // Read X encoder
  if (newX > 0)                       // Has the value increased since last read
  {
    Joystick.setXAxis(127);           // Set joystick X hard over to right
    axisX.write(0);                   // Zero encoder count for next time
  }
  if (newX < 0)                       // Has encoder decreased since last read
  {
    Joystick.setXAxis(-127);          // Set joystick hard left
    axisX.write(0);                   // Zero encoder count
  }
 
  Joystick.setYAxis(0);               // Center joystick Y
  int newY = axisY.read();
  if (newY > 0)
  {
    Joystick.setYAxis(127);
    axisY.write(0);
  }
  if (newY < 0)
  {
    Joystick.setYAxis(-127);
    axisY.write(0);
  }
 
  Joystick.setZAxis(0);               // Center joystick Z
  int newZ = axisZ.read();
  if (newZ > 0)
  {
    Joystick.setZAxis(63);
    delay(50);
    axisZ.write(0);
  }
  if (newZ < 0)
  {
    Joystick.setZAxis(-63);
    delay(50);
    axisZ.write(0);
  }
 
  // Read button pin values
  for(byte x = 0; x < sizeof(buttonArray); x++)
  {
    byte currentButtonState = !digitalRead(buttonArray[x]);   // Read button state
    Joystick.setButton(x, currentButtonState);                // Set state in joystick
  }
 
  Joystick.sendState();               // Send the joystick data
  delay(50);                          // Wait a bit
}

So over a length of about ten to fifteen feet away from the arduino cable length, would i need to add some 1k pullup resistors as well as the internal pullups for the buttons and the encoders?  Now because of you i understand the button code fully, thank you.  Okay for the trackball encoders, would i be able to use the same counting technique as the normal encoder knob?  I havent tried the code you posted yet as i just changed benches and some things are shuffeled around lol. I should be able to trt your code and report back to you with the results.
I make things do what they were never intended to do :P

Riva

#28
Nov 09, 2017, 10:30 am Last Edit: Nov 09, 2017, 10:31 am by Riva
So over a length of about ten to fifteen feet away from the arduino cable length, would i need to add some 1k pullup resistors as well as the internal pullups for the buttons and the encoders?
1K seems a bit strong as a pullup but this will all depend on the type of wire and if it's screened. If your getting spurious readings the maybe start with 10K and work your way down toward 1K. Another option might be to put the Arduino near the encoders and run a longer USB lead back to the computer.

Now because of you i understand the button code fully, thank you.
The original code was just the example supplied with the joystick library but it doies not suit none contiguous pin numbers so using an array seemed the sensible thing to do.

Okay for the trackball encoders, would i be able to use the same counting technique as the normal encoder knob?
Not sure what you mean here. As the test code stands it sends the joystick data every 50 milliseconds (plus overhead) and the encoders are read in a interrupt so may/may not update more than once in that time. How fast they update also depends on there resolution and how fast you turn them and this might be okay at a lower speed.
The test code reads the encoder counts every 50ms then zeros them and prints it out so you should be able to determine how many pulses you get at different encoder speeds and this information can be used to add velocity to the encoder joystick axis.
If you want to add a third encode to the mix then either the other two encoders need connecting differently so only one interrupt is used per encoder instead of two (reducing performance) or the code will need to poll the third encoder quickly to manually count pulses.

Don't PM me for help as I will ignore it.

hydrolisk1792

Okay I hooked the Trackball to to the serial monitor and that is exactly what I needed the trackball to do.  So I will try to somehow mix that code into the joystick library and see what happens.  The Minimum number is about 0 - 1  Plus Minus. and the max number is roughly 210 - 222 Plus Minus.  I also unhooked the trackball and hooked up one rotary encoder to the serial monitor and I'm thinking that my rotary encoder is damaged or something because I couldn't get it to go above Plus Minus 2 in the serial monitor...  I'm going to try spraying some cleaner into it and see if that will fix it.  I've seen this happen to rotary encoder knobs on the Microwaves we have at my work and I spray them with this special cleaner and they work like new, so I'll take it to work with me tonight and spray some stuff in it and see if that does the trick...  All the buttons work BTW :)  Thank you for that.  I'm going to experiment with the two codes you gave me and see if I can get the track ball to act the way it does in the serial monitor.
I make things do what they were never intended to do :P

Go Up