Forum Rule: Always post complete source code & details to reproduce any issue!

# Thread: How do I correct an analog axis bouncing?

1. ## How do I correct an analog axis bouncing?

HI all,
I have a joystick that I use the 2 slider axis (analog 4 and 5). In game (DCS) the 2 axis they control can be seen to be bouncing ever so slightly. The code for the 2 axis is just:
Code:
``` // Pitch and throttle axis
Is there something I can add that will smooth out the input throughout the range of motion?
Thanks.
John  Reply With Quote

2. I found the smoothing tutorial. Who knew...
I need to smooth 2 inputs. Can I write it like this?

Code:
```const int numReadings = 10;

int total = 0;
int average = 0;

int inputPin = A4 and A5;```
Thanks
John  Reply With Quote

3. I use a sliding window averaging scheme for my game controller. Each pass of the main loop I grab an A/D sample and stuff it into an array that is 16 words deep. I use a counter (Analog_Cnt) that is incremented with each pass to determine where in the array to to stuff it (the array index).

Every main loop pass I sum all the values in the array. Since they are all 16-bit values the resulting number is always less than a 32-bit unsigned integer, so no worries about exceeding the 32-bit maximum value.

Next, I divide the sum of all values in the array by 16 by right shifting the result 4 places. This is a fast way to divide without math.

That's it. My main loop executes once every 1 mS.

In the example below some of my A/D inputs are not used and forced to zero.

Code:
```  //---------------------------------------------------------------------------
// Analog Section
//---------------------------------------------------------------------------
total_x = 0;
total_y = 0;
total_z = 0;
total_xr = 0;
total_yr = 0;
total_zr = 0;
total_dial = 0;
total_slider = 0;

Analog_Z [Analog_Cnt] = 0; // analogRead(2);
Analog_XR [Analog_Cnt] = 0; // analogRead(3);
Analog_YR [Analog_Cnt] = 0; // analogRead(0);
Analog_ZR [Analog_Cnt] = 0; // analogRead(1);
Analog_Dial [Analog_Cnt] = 0;
Analog_Slider [Analog_Cnt] = 0;

// Counter for sliding average window
Analog_Cnt++;
if (Analog_Cnt >= ANALOG_AVERAGE_CNT)
{
Analog_Cnt = 0;
}

// Sliding window average X, Y, & Z axis
for (i = 0; i < ANALOG_AVERAGE_CNT; i++)
{
total_x += Analog_X[i];
total_y += Analog_Y[i];
total_z += Analog_Z[i];
total_xr += Analog_XR[i];
total_yr += Analog_YR[i];
total_zr += Analog_ZR[i];
total_dial += Analog_Dial[i];
total_slider += Analog_Slider[i];
}
// Right shift (divide by 16)
average_x = total_x >> ANALOG_AVERAGE_DIV_SHIFT;
average_y = total_y >> ANALOG_AVERAGE_DIV_SHIFT;
average_z = total_z >> ANALOG_AVERAGE_DIV_SHIFT;
average_xr = total_xr >> ANALOG_AVERAGE_DIV_SHIFT;
average_yr = total_yr >> ANALOG_AVERAGE_DIV_SHIFT;
average_zr = total_zr >> ANALOG_AVERAGE_DIV_SHIFT;
average_dial = total_dial >> ANALOG_AVERAGE_DIV_SHIFT;
//  average_slider = total_slider >> ANALOG_AVERAGE_DIV_SHIFT;

Joystick.X(average_x);
Joystick.Y(average_y);
Joystick.Z(average_z);
average_xr = 0;
average_yr = 0;
average_zr = 0;
average_dial = 0;
Joystick.Xrotate(average_xr);
Joystick.Yrotate(average_yr);
Joystick.Zrotate(average_zr);
Joystick.Dial(average_dial);
//  Joystick.Slider(average_slider);  // Used as encoder data```  Reply With Quote

4. I understood absolutely nothing of that. But thank you.
I will try to gain some understanding of it and apply it to what I'm doing.
That's how we learn, right?  Reply With Quote

5.  Reply With Quote

6. Yes. Keep struggling with the problem. You will get it!

The algorithm is simply an algebraic average. That is, you take a number of samples, say 8, and write the down on a piece of paper.

Now add up all 8 samples. Next divide the results by the total number of samples, which is 8. The result of that division is the average of the 8 samples.

That's the crux of it, The rest of the code is all housekeeping stuff to make it work. For example, the array Analog_X [] is just that piece of paper, keeping a record of all the A/D reads.

The last 16 samples are added in the for loop for (i = 0; i < ANALOG_AVERAGE_CNT; i++). That's the sliding window summation routine.

The Right shift (divide by 16) divides the total and gives you the average for the last 16 analog reads in the variable average_x.

Finally, the value in average_x is placed in the USB data structure and manually sent to the PC at the end of the main loop routine.

Some of my A/D channels are forced to zero because in the particular application I was using the software for there was nothing connected to those channels and I didn't want random noise and coupling from other channels creating false values in unused channels.  Reply With Quote

7. Thank you for that explanation.
So if I am reading this correctly, like me, you are only using 2 of the analog inputs (4 and 5). But you are using them for the x and y axis whereas I am using them for the slider axis. For the 0-3 inputs, the first section is:
Analog_Z [Analog_Cnt] = 0; // analogRead(2);
Analog_XR [Analog_Cnt] = 0; // analogRead(3);
Analog_YR [Analog_Cnt] = 0; // analogRead(0);
Analog_ZR [Analog_Cnt] = 0; // analogRead(1);

Was there a need to include them in the remaining sections or was that for continuity sake?
Also. Is all of this in the void loop section of the sketch?
Thanks again for your help. It's starting to make sense.
John  Reply With Quote

8. Originally Posted by Doon1 Thank you for that explanation.
So if I am reading this correctly, like me, you are only using 2 of the analog inputs (4 and 5). But you are using them for the x and y axis whereas I am using them for the slider axis. For the 0-3 inputs, the first section is:
Analog_Z [Analog_Cnt] = 0; // analogRead(2);
Analog_XR [Analog_Cnt] = 0; // analogRead(3);
Analog_YR [Analog_Cnt] = 0; // analogRead(0);
Analog_ZR [Analog_Cnt] = 0; // analogRead(1);

Was there a need to include them in the remaining sections or was that for continuity sake?
Also. Is all of this in the void loop section of the sketch?
Thanks again for your help. It's starting to make sense.
John
The software is used in different configurations, depending on how it is implemented and the total number of channels can vary. When I first did this I wanted to create something that would contain the largest number of A/D channels needed, then I would zero out unused channels.

I know there are more eloquent ways to do that, but I was experimenting at that point.

Yes, all of this was contained in the void loop.  Reply With Quote

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•