Notifications
Clear all

Inexpensive Joysticks - Resolution and Usability

1 Posts
1 Users
0 Likes
946 Views
jBo
 jBo
(@jbo)
Estimable Member
Joined: 3 years ago
Posts: 106
Topic starter  

Waiting for some other parts to come in (aren't we all?), I decided to test what I did have in hand, a 3-pack of cheap joysticks. These plug into the analog to digital pins of a micro-controller, as shown by @dronebot-workshop in Controlling DC Motors with the L298N Dual H-Bridge and an Arduino. In my case, I used an Arduino Nano.

With one axis of a joystick, divide the value by 100, so the ADC result 0..1023 falls into one of 10 slots, or "buckets." This technique is often useful in statistics. In this case it is used to test recently purchased cheap joysticks.

Some buyers say in the reviews that the device is unusable because it is not smooth. They say it goes straight from 504-510, the middle, to 1023, the max, with no possibility of picking other values. Perhaps we can test this. In addition, we can make a judgement, subjective to be sure, whether a particular joystick from a particular manufacturer is adequate for a given task.

The Hookup

Uh, not really much to this. Connect the joystick to the Arduino. I picked the pins I did specifically because the male-female jumpers lined up very nicely, and looked like a real cable. Not much to say, other than this is a 5V device; perhaps it would work with a 3.3V output from, say, an Arduino Pro Mini, I don't know.

The Sketch

Every 1 second, the y axis is read, and exactly one bucket is incremented. The user's goal is to make sure the joystick can produce at least one reading in every bucket. That is, you need at least one from the 0s, the 100s, 200s, 300s and so on. The accumulated counts of all these buckets are printed.

Press the switch of the joystick, and the buckets will be reset to zero.

So you should be able to fairly quickly test a new pack of joysticks. For fun, each time you fill all the buckets, your time is displayed. Beat your best time, Player One! (*)

(*) Astute readers will find a cheat to get out of actually solving the test. Fixing that flaw is left as an exercise for the reader 😀 

 

/*
joyBuckets
2021-08-08 jBo.
With one axis of a joystick, divide the value by 100, so the ADC result 0..1023 falls
into one of 10 buckets. This technique is often useful in statistics. In this
case it is used to test recently purchased cheap joysticks. Some buyers say in
the reviews that the device is unusable because it is not smooth. They say it goes
straight from 504-510, the middle, to 1023, the max, with no possibility of picking
other values. Perhaps we can test this.

Every 1 second, the y axis is read, and exactly one bucket is incremented. The user's
goal is to make sure the joystick can produce at least one reading in every bucket. That is,
you need at least one from the 0s, the 100s, 200s, 300s and so on. The accumulated
counts of all these buckets are printed.

Press the switch of the joystick, and the buckets will be reset to zero.

So you should be able to fairly quickly test a new pack of joysticks. For fun,
each time you fill all the buckets, your time is displayed. Beat your best time!

*/

int joySwitchPin = A0; // Vertical
int joyVert = A1; // Vertical
int joyHorz = A2; // Horizontal

//const bool debugMode_joy = false;
const bool debugMode_joy = true;

int joyposVert = 512;
int joyposHorz = 512;
int joySwitch = -1; //pushbutton switch on the joystick shaft, will be 1 or 0.

const int nBucks = 11; //how many buckets do we have?
long joyBucket[nBucks]; //So, every value from 0..1023 will fit somewhere.

long start_timr = millis();
long elapsed_s = 0; //how much time did this take us, in seconds?


// the setup function runs once when you press reset or power the board
void setup() {

pinMode(joySwitchPin, INPUT_PULLUP);

Serial.begin(9600);

joy_InitBuckets(nBucks);


}

// the loop function runs over and over again forever
void loop() {

if (debugMode_joy) {
joySwitch = digitalRead(joySwitchPin);

// Read the Joystick X and Y positions
joyposVert = analogRead(joyVert);
joyposHorz = analogRead(joyHorz);

//For switch, normal is HIGH, 1; press the switch for LOW, 0.
if ( (!joySwitch) || joy_VerifyBuckets(nBucks) ) {
//either we won the game, or got tired and pressed the switch anyway.
elapsed_s = (millis() - start_timr) / 1000;
Serial.print("Congratulations! You finished in ");
Serial.print(elapsed_s);
Serial.println(" seconds. ");

joy_InitBuckets(nBucks); //reinitialize everything
delay(4000);
start_timr = millis();

} else {
//we're still playing, still accumulating counts in the buckets.

int bucket = joyposVert / 100;
joyBucket[bucket]++;
joy_PrintBuckets(nBucks);

// Serial.print("joySwitch ");
// Serial.print(joySwitch);
// Serial.print("; ");
//
// Serial.print("horiz X ");
// Serial.print(joyposHorz);
// Serial.print("; ");
//
// Serial.print("vert Y ");
// Serial.print(joyposVert);

Serial.println(" ");
}
}
delay(1000); // after the whole thing, add a delay before starting over.
}


void joy_InitBuckets(int nBucks) {
for (int ix = 0; ix < nBucks; ix++) {
joyBucket[ix] = 0;
}

Serial.println(" ");
Serial.println("JoyBuckets - move Y axis, try to get at least one reading ");
Serial.println("in every slot/bucket. Best time wins! ");
Serial.println(" ");

} //end joy_InitBuckets


void joy_PrintBuckets(int nBucks) {
for (int ix = 0; ix < nBucks; ix++) {
Serial.print(joyBucket[ix]);
Serial.print(" ");
}
} //end joy_PrintBuckets


//In order to win the game, there must be at least something in every bucket,
//at least one count. Otherwise, Fail.
bool joy_VerifyBuckets(int nBucks) {
for (int ix = 0; ix < nBucks; ix++) {
if (joyBucket[ix] == 0) return false;
}
return true;
} //end joy_VerifyBuckets



 

This topic was modified 2 years ago by jBo

In theory, theory and practice are the same.
In practice, they're different.


   
Quote