Hi, I am a complete and utter beginner when it comes to Arduino and coding so please bear with me and I apologise if this is posted in the wrong place but it seems the logical one.
I am trying to combine two projects into one. The first is hacking a Logitech throttle quadrant game controller using a pro micro. I followed a previous project that I found online. It works very well. I then found a project to add a trim wheel to the quadrant using another pro micro. Not wanting to use two boards when there are enough inputs on one I tried to understand and combine the relevant parts of the code. However the trim wheel works fine but the quadrant stops working altogether. I have spent days trawling through the code and reading info online but I can't figure this out.
Can anyone help me with this please? Even just a pointer in the right direction please?
* Throttle script with filtering
* This script takes three axis, and filters the signal for an 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
* 20 Hz signal to remove remaining gaussian noise.
* All axes 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 throttle quadrant. Thanks to this project
* https://forums.x-plane.org/index.php?/forums/topic/240443-saitek-throttle-quadrant-usb-conversion-using-arduino/
*/
// Robust Rotary encoder reading
//
// Copyright John Main - best-microcontroller-projects.com
//
// Modified for trim wheel application by Jason Merrill
//
#include "Joystick.h"
#include "SimpleKalmanFilter.h"
#define REV_THRESHOLD_X 790
#define REV_THRESHOLD_Y 840
#define REV_THRESHOLD_Z 830
#define OUTPUT_LIMIT 890
#define OUTPUT_HZ 20
#define BANDPASS_SPD 13
#define MEASUREM_UNCERT 10
#define PROC_VARIANCE 2
#define CLK 3
#define DATA 2
/* Settings
* REV_THRESHOLD Past idle notch of the throttle, activates reverse
* OUTPUT_LIMIT Limit of value that is output for a slider. should
* correspond to the idle notch
* 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
*/
int potX, valX;
int potY, valY;
int potZ, valZ;
int but1, but2, but3, but4, but5, but6;
int revX, revY, revZ;
unsigned int bandPass;
unsigned long lastPoll = 0;
unsigned int sampleTime;
const int16_t MAX_VALUE = 100;
const int16_t MIN_VALUE = -100;
static uint8_t prevNextCode = 0;
static uint16_t store=0;
int16_t counter = 0;
// output configuration
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,
JOYSTICK_TYPE_JOYSTICK, 9, 0, // 9 Buttons, 0 Hate Switch
true, true, true, // X, Y, Z Axis
false, false, false, // No Rx, Ry, Rz
false, true, // No Rudder but has Throttle( ie Trim Wheel)
false, false, false); // No Accel, Brake or Steering
SimpleKalmanFilter kalmanFilterX(MEASUREM_UNCERT, MEASUREM_UNCERT, PROC_VARIANCE);
SimpleKalmanFilter kalmanFilterY(MEASUREM_UNCERT, MEASUREM_UNCERT, PROC_VARIANCE);
SimpleKalmanFilter kalmanFilterZ(MEASUREM_UNCERT, MEASUREM_UNCERT, PROC_VARIANCE);
void setup() {
Joystick.begin();
Joystick.setXAxisRange(0, OUTPUT_LIMIT);
Joystick.setYAxisRange(0, OUTPUT_LIMIT);
Joystick.setZAxisRange(0, OUTPUT_LIMIT);
Joystick.setThrottleRange(MIN_VALUE, MAX_VALUE);
pinMode(A0, INPUT); //configure inputs for potentiometers
pinMode(A1, INPUT);
pinMode(A2, INPUT);
pinMode(CLK, INPUT);
pinMode(CLK, INPUT_PULLUP);
pinMode(DATA, INPUT);
pinMode(DATA, INPUT_PULLUP);
pinMode(4,INPUT_PULLUP); //configure inputs for buttons, use internal pullup resistor
pinMode(5,INPUT_PULLUP);
pinMode(6,INPUT_PULLUP);
pinMode(7,INPUT_PULLUP);
pinMode(8,INPUT_PULLUP);
pinMode(9,INPUT_PULLUP);
//initialize parameters for the filters and sampling
sampleTime = 1000000 / OUTPUT_HZ;
bandPass = 30000; //just the first two seconds, no real bandpass
Serial.begin( 9600 ); //remove comment for debugging on the serial monitor/plotter
}
void loop() {
//enable band pass filter after 2 seconds stabilization
if (bandPass == 30000 && millis() > 2000) {
bandPass = (BANDPASS_SPD * OUTPUT_LIMIT) / OUTPUT_HZ;
}
static int8_t c,val;
if( val=read_rotary() ) {
c +=val;
if ( prevNextCode==0x0b) {
counter++;
if(counter > MAX_VALUE){
counter = MAX_VALUE;
}
Joystick.setThrottle(counter);
}
if ( prevNextCode==0x07) {
counter--;
if(counter < MIN_VALUE){
counter = MIN_VALUE;
}
Joystick.setThrottle(counter);
}
}
}
// A vald CW or CCW move returns 1, invalid returns 0.
int8_t read_rotary() {{
static int8_t rot_enc_table[] = {0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0};
prevNextCode <<= 2;
if (digitalRead(DATA)) prevNextCode |= 0x02;
if (digitalRead(CLK)) prevNextCode |= 0x01;
prevNextCode &= 0x0f;
// If valid then store as 16 bit data.
if (rot_enc_table[prevNextCode] ) {
store <<= 4;
store |= prevNextCode;
if ((store&0xff)==0x2b) return -1;
if ((store&0xff)==0x17) return 1;
}
return 0;
}
//read inputs
while (lastPoll+sampleTime > micros()) {delayMicroseconds(4);} //clocked sample rate.
potX = analogRead(A0); //X axis, Throttle
potY = analogRead(A1); //Y axis, Prop
potZ = analogRead(A2); //Z axis, Mixture
lastPoll = micros();
but1 = !digitalRead(4);
but2 = !digitalRead(5);
but3 = !digitalRead(6);
but4 = !digitalRead(7);
but5 = !digitalRead(8);
but6 = !digitalRead(9);
//process notch and reverse ranges
if (potX > REV_THRESHOLD_X) { //test whether lever is in reverse range
revX = 1; //reverse on
} else {
revX = 0; //reverse off
}
if (potX > OUTPUT_LIMIT){ potX = OUTPUT_LIMIT;} //limit the output range
if (potY > REV_THRESHOLD_Y) { //test whether lever is in reverse range
revY = 1; //reverse on
} else {
revY = 0; //reverse off
}
if (potY > OUTPUT_LIMIT){ potY = OUTPUT_LIMIT;} //limit the output range
if (potZ > REV_THRESHOLD_Z) { //test whether lever is in reverse range
revZ = 1; //reverse on
} else {
revZ = 0; //reverse off
}
if (potZ > OUTPUT_LIMIT){ potZ = OUTPUT_LIMIT;} //limit the output range
//throw out too large changes (bandpass)
if (abs(valX -potX) < bandPass) { //very crude bandpass filter
valX= potX;
} else {
Serial.println(" !!!BANDPASS FILTER HAS TWROWN OUT AN INPUT VALUE!!!"); //debug only
}
if (abs(valY -potY) < bandPass) {
valY= potY;
} else {
Serial.println(" !!!BANDPASS FILTER HAS TWROWN OUT AN INPUT VALUE!!!"); //debug only
}
if (abs(valZ -potZ) < bandPass) {
valZ= potZ;
} else {
Serial.println(" !!!BANDPASS FILTER HAS TWROWN OUT AN INPUT VALUE!!!"); //debug only
}
//apply Kalman filter to remove remaining gaussian noise
valX = kalmanFilterX.updateEstimate(valX);
valY = kalmanFilterY.updateEstimate(valY);
valZ = kalmanFilterZ.updateEstimate(valZ);
// //remove comment for debugging on the serial monitor/plotter
Serial.print("X: ");
Serial.print(valX);
Serial.print(" Y: ");
Serial.print(valY);
Serial.print(" Z: ");
Serial.print(valZ);
Serial.print(" rev X: ");
Serial.print(revX);
Serial.print(" rev Y: ");
Serial.print(revY);
Serial.print(" rev Z: ");
Serial.print(revZ);
Serial.println("");
Joystick.setXAxis(OUTPUT_LIMIT - valX);
Joystick.setYAxis(OUTPUT_LIMIT - valY);
Joystick.setZAxis(OUTPUT_LIMIT - valZ);
Joystick.setButton(0, but1);
Joystick.setButton(1, but2);
Joystick.setButton(2, but3);
Joystick.setButton(3, but4);
Joystick.setButton(4, but5);
Joystick.setButton(5, but6);
Joystick.setButton(6, revX);
Joystick.setButton(7, revY);
Joystick.setButton(8, revZ);
}