When I plug the Arduino into a running computer, axis are updated according to the inputs. However, often when cold booting windows, the Arduino shows up as a joystick, but the axis are frozen. When debugging with the serial output active, I can see the script is running and updating variables, however, they do not seem to update the joystick axis in Windows. I can make it work again by momentarily unplugging the usb connection.
Technical Details
Arduino Board : Arduino Micro Pro clone
Host OS : Windows 10 Pro 1903
Arduino IDE Version : 1.8.10
Sketch File that Reproduces Issue
/* Joystick script with filtering
* This script takes two axis, then oversamples a 10 bit
* input signal at a rate of 200Hz to get an 11 bit output
* at 50 Hz. The clock is used to exactly time the polling,
* to avoid sampling bias. A crude bandpass filter throws
* away spikes that are impossible(!) to result from user
* input. This will convert spikes on the control axis into
* a mere stutter. Then a Kalman filter is applied to the
* 50 Hz 11 bit signal to remove remaining gaussian noise.
* X and Y each get their own one dimensional Kalman
* because there is no correlation that is relevant for the
* filter. The constants in this script are configured for
* the Saitek Pro yoke pitch and roll axis.
*/
#include "Joystick.h"
#include "SimpleKalmanFilter.h"
#define CENTER_X 1170
#define CENTER_Y 1000
#define RANGE 840
#define ADC_BITS 10
#define OUTPUT_BITS 11
#define OUTPUT_HZ 50
#define BANDPASS_SPD 10
#define MEASUREM_UNCERT 5
#define PROC_VARIANCE 3
/* Settings
* CENTER_X Center of the roll axis in output resolution
* CENTER_Y Center of the pitch axis in output resolution
* RANGE Range of movement in output resolution
* ADC_BITS Resolution of the ADC on the board
* OUTPUT_BITS Desired output resolution bitdepth. Setting this
* higher than ADC_BITS will invoke oversampling
* OUTPUT_HZ Desired output frequency to the computer
* BANDPASS_SPD Rate of change over which measurements will be
* discarded. 10 Means 10 times the full range per
* second. Don't set the bandpass speed too low,
* erratic output if it is actually achieved! It
* needs to be a value where with 100% certainty it
* is a potentiometer spike and not user input!
* MEASUREMENT_UNCERT Random noise to be expected from the Pot,
* in output resolution units
* PROC_VARIANCE Normal accelerations of the control to be
* expected, in output resoltution units per sample
* in OUTPUT_HZ. Decreasing this will decrease
* responsiveness
*
* Go easy on the oversampling, it has a exponential performance
* impact. 2 Bit oversampling will slow down the script 16
* times compared to no oversampling! Depending on the board, the
* output frequency might need to be reduced for the processor to
* not miss samples.
*/
int potX, valX;
int potY, valY;
int bandPass;
unsigned long sumX, sumY;
unsigned long lastPoll = 0;
unsigned int oSampleBits, sampleTime, adcRes, samples;
// output just X and Y axis
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,
JOYSTICK_TYPE_JOYSTICK, 0, 0,
true, true, false, false, false, false,
false, false, false, false, false);
SimpleKalmanFilter kalmanFilterX(MEASUREM_UNCERT, MEASUREM_UNCERT, PROC_VARIANCE);
SimpleKalmanFilter kalmanFilterY(MEASUREM_UNCERT, MEASUREM_UNCERT, PROC_VARIANCE);
void setup() {
Joystick.begin();
Joystick.setXAxisRange(-RANGE, RANGE);
Joystick.setYAxisRange(-RANGE, RANGE);
#if defined(ARDUINO_ARCH_SAMD) || defined(__SAM3X8E__) || defined(ARDUINO_SAMD_MKRZERO)
analogReadResolution(ADC_BITS);
#endif
pinMode(A0, INPUT);
pinMode(A1, INPUT);
//initialize parameters for the filters and sampling
oSampleBits = constrain(OUTPUT_BITS - ADC_BITS, 0, 16-ADC_BITS);
sampleTime = 1000000 / ( pow(4,oSampleBits) * OUTPUT_HZ );
bandPass = pow(2,ADC_BITS);
//Prepare some calculations for the loop
adcRes = pow(2,ADC_BITS);
samples = pow(4,oSampleBits);
//Serial.begin( 9600 ); //remove comment for debugging on the serial monitor/plotter
}
void loop() {
//enable band pass filter after 2 seconds stabilization
if (bandPass == adcRes && millis() > 2000) {
bandPass = (BANDPASS_SPD * adcRes) / OUTPUT_HZ;
}
//oversample start
sumX = 0;
sumY = 0;
for(int i=0; i < samples; i++) { //sum up total of 4^oSampleBits measurements
while (lastPoll+sampleTime > micros()) {delayMicroseconds(4);} //clocked sample rate.
potX = analogRead(A1); //Roll axis, adjust A1/A0 according to actual wiring
potY = analogRead(A0); //Pitch axis
lastPoll = micros();
if (abs((valX >> oSampleBits)-potX) < bandPass) { //very crude bandpass filter
sumX += potX;
} else {
sumX += valX >> oSampleBits; //use last value as a substitute, valX in ADC_BITS
//Serial.println(" !!!BANDPASS FILTER HAS TWROWN OUT AN INPUT VALUE!!!");
}
if (abs((valY >> oSampleBits)-potY) < bandPass) {
sumY += potY;
} else {
sumX += valY >> oSampleBits;
//Serial.println("!!!BANDPASS FILTER HAS TWROWN OUT AN INPUT VALUE!!!");
}
}
valX = (sumX >> oSampleBits); //reduce the bitdepth of the sum to OUTPUT_BITS
valY = (sumY >> oSampleBits);
//oversampling finished
valX = kalmanFilterX.updateEstimate(valX); //apply Kalman filter to remove remaining gaussian noise
valY = kalmanFilterY.updateEstimate(valY);
/*
//remove comment for debugging on the serial monitor/plotter
Serial.print("X: ");
Serial.print(valX);
Serial.print(" Y: ");
Serial.print(valY);
Serial.println("");
*/
Joystick.setXAxis(valX - CENTER_X);
Joystick.setYAxis(-valY + CENTER_Y); //reverse pitch axis for the saitek
}
Wiring Details
2 potentiometers are wired to GND, VCC, A0 and A1
Additional context
It makes no difference what USB port is used. Tried USB 3.1 and 2.0 ports. Other Joysticks have no problem. I have tried to delay the Joystick.begin() in the setup() routine by up to 20 seconds (windows is on the desktop by then), but that didn't help.
Description of Issue
When I plug the Arduino into a running computer, axis are updated according to the inputs. However, often when cold booting windows, the Arduino shows up as a joystick, but the axis are frozen. When debugging with the serial output active, I can see the script is running and updating variables, however, they do not seem to update the joystick axis in Windows. I can make it work again by momentarily unplugging the usb connection.
Technical Details
Sketch File that Reproduces Issue
Wiring Details
2 potentiometers are wired to GND, VCC, A0 and A1
Additional context
It makes no difference what USB port is used. Tried USB 3.1 and 2.0 ports. Other Joysticks have no problem. I have tried to delay the Joystick.begin() in the setup() routine by up to 20 seconds (windows is on the desktop by then), but that didn't help.