// PPM Encoder Joystick to Futaba Trainer Port
// For use with Arduino Nano V3.0
// Ian Johnston 29/04/2010
// Version 1.1
int AI_Pin_AEL = 6; // Ana In - Aeleron potentiometer (Ana In Ch.0 playing up?)
int AI_Pin_ELE = 1; // Ana In - Elevator potentiometer
int AI_Pin_THR = 2; // Ana In - Throttle potentiometer
int AI_Pin_RUD = 3; // Ana In - Rudder potentiometer
int AI_Pin_TIpot = 4; // Ana In - TI potentiometer
int AI_Raw_AEL; // Ana In raw var - 0->1023
int AI_Raw_ELE; // Ana In raw var - 0->1023
int AI_Raw_THR; // Ana In raw var - 0->1023
int AI_Raw_RUD; // Ana In raw var - 0->1023
int AI_Raw_TIpot; // Ana In raw var - 0->1023
int AI_AEL; // Ana In var - 0->1023 compensated
int AI_ELE; // Ana In var - 0->1023 compensated
int AI_THR; // Ana In var - 0->1023 compensated
int AI_RUD; // Ana In var - 0->1023 compensated
int AI_TIpot; // Ana In var - 0->1023 compensated
int Aeleron_uS = 700; // Ana In Ch.0 uS var - Aeleron
int Elevator_uS = 700; // Ana In Ch.1 uS var - Elevator
int Throttle_uS = 700; // Ana In Ch.2 uS var - Throttle
int Rudder_uS = 700; // Ana In Ch.3 uS var - Rudder
int TI_uS = 700; // Ana In Ch.4 uS var - TI
int TIsw_uS = 700; // Ana In Ch.4 uS var - TI Switch
int Fixed_uS = 100; // PPM frame fixed LOW phase
int pulseMin = 700; // pulse minimum width minus start in uS
int pulseMax = 2100; // pulse maximum width in uS
float DualrateMultAel = 0.9; // Dual rate mult
float DualrateMultEle = 0.9; // Dual rate mult
float DualrateMultThr = 0.9; // Dual rate mult
float DualrateMultRud = 0.9; // Dual rate mult
float DualrateMultTI = 0.9; // Dual rate mult
int DualrateAdjAel = 0; // Dual rate mid adjustment
int DualrateAdjEle = 0; // Dual rate mid adjustment
int DualrateAdjThr = 0; // Dual rate mid adjustment
int DualrateAdjRud = 0; // Dual rate mid adjustment
int DualrateAdjTI = 0; // Dual rate mid adjustment
int outPinPPM = 10; // digital pin 10
int outPinTEST = 8; // digital pin 8
int inPinD6 = 6; // digital pin 6
int inPinD11 = 11; // digital pin 11
ISR(TIMER1_COMPA_vect) {
ppmoutput(); // Jump to ppmoutput subroutine
}
void setup() {
// Serial.begin(9600) ; // Test
pinMode(outPinPPM, OUTPUT); // sets the digital pin as output
pinMode(outPinTEST, OUTPUT); // sets digital pin as output, added dc
pinMode(inPinD6, INPUT); // sets the digital pin as input
digitalWrite(inPinD6, HIGH); // turn on pull-up resistor
pinMode(inPinD11, INPUT); // sets the digital pin as input
digitalWrite(inPinD11, HIGH); // turn on pull-up resistor
// Setup timer
TCCR1A = B00110001; // Compare register B used in mode '3'
TCCR1B = B00010010; // WGM13 and CS11 set to 1
TCCR1C = B00000000; // All set to 0
TIMSK1 = B00000010; // Interrupt on compare B
TIFR1 = B00000010; // Interrupt on compare B
OCR1A = 22500; // 22.5mS PPM output refresh
OCR1B = 1000;
}
void ppmoutput() { // PPM output sub
// test pulse and Channel 1 start- used to trigger scope. Modified so Test Pulse
// and Channel 1 Pulse start at same time
digitalWrite(outPinPPM, LOW); //Starts Channel 1 Output Pulse
digitalWrite(outPinTEST, LOW); // Starts Test Sync Pulse
delayMicroseconds(100); // Hold, Test Sync Pin for 100 us
digitalWrite(outPinTEST, HIGH);
// Channel 1 - Aeleron
delayMicroseconds(Fixed_uS - 100); // Hold Channel 1 minus 100 us used in Test Sync Pulse
digitalWrite(outPinPPM, HIGH);
delayMicroseconds(Aeleron_uS); // Hold for Aeleron_uS microseconds
// Channel 2 - Elevator
digitalWrite(outPinPPM, LOW);
delayMicroseconds(Fixed_uS); // Hold
digitalWrite(outPinPPM, HIGH);
delayMicroseconds(Elevator_uS); // Hold for Elevator_uS microseconds
// Channel 3 - Throttle
digitalWrite(outPinPPM, LOW);
delayMicroseconds(Fixed_uS); // Hold
digitalWrite(outPinPPM, HIGH);
delayMicroseconds(Throttle_uS); // Hold for Throttle_uS microseconds
// Channel 4 - Rudder
digitalWrite(outPinPPM, LOW);
delayMicroseconds(Fixed_uS); // Hold
digitalWrite(outPinPPM, HIGH);
delayMicroseconds(Rudder_uS); // Hold for Rudder_uS microseconds
// Channel 5 - TI Switch
digitalWrite(outPinPPM, LOW);
delayMicroseconds(Fixed_uS); // Hold
digitalWrite(outPinPPM, HIGH);
delayMicroseconds(TIsw_uS); // Hold for TIsw_uS microseconds
// Channel 6 - TI pot
digitalWrite(outPinPPM, LOW);
delayMicroseconds(Fixed_uS); // Hold
digitalWrite(outPinPPM, HIGH);
delayMicroseconds(TI_uS); // Hold for TI_uS microseconds
// Synchro pulse
digitalWrite(outPinPPM, LOW);
delayMicroseconds(Fixed_uS); // Hold
digitalWrite(outPinPPM, HIGH); // Start Synchro pulse
}
void loop() { // Main loop
// Read analogue ports
AI_Raw_AEL = analogRead(AI_Pin_AEL);
AI_Raw_ELE = analogRead(AI_Pin_ELE);
AI_Raw_THR = analogRead(AI_Pin_THR);
AI_Raw_RUD = analogRead(AI_Pin_RUD);
AI_Raw_TIpot = analogRead(AI_Pin_TIpot);
// Compensate for discrepancy in pot inputs including centering offset.
// Also use this to invert inputs if necessary (swap x1 & y1)
// y=mx+c, x to y scales to x1 to y1
AI_AEL = map(AI_Raw_AEL, 0, 1023, 1200, 0) - 100; // Invert Aeleron pot and slight centre offset
AI_ELE = map(AI_Raw_ELE, 0, 1023, 1200, 0) - 120; // Invert Elevator pot and slight centre offset
AI_THR = map(AI_Raw_THR, 0, 1023, 0, 1023) + 0; // Throttle
AI_RUD = map(AI_Raw_RUD, 0, 1023, 0, 1023) + 0; // Rudder
AI_TIpot = map(AI_Raw_TIpot, 0, 1023, 1023, 0) + 0; // Thermal Intelligence pot (TI)
// Map analogue inputs to PPM rates for each of the channels
Aeleron_uS = (AI_AEL * DualrateMultAel) + pulseMin + DualrateAdjAel;
Elevator_uS = (AI_ELE * DualrateMultEle) + pulseMin + DualrateAdjEle;
Throttle_uS = (AI_THR * DualrateMultThr) + pulseMin + DualrateAdjThr;
Rudder_uS = (AI_RUD * DualrateMultRud) + pulseMin + DualrateAdjRud;
TI_uS = (AI_TIpot * DualrateMultTI) + pulseMin + DualrateAdjTI;
// Check limits
if (Aeleron_uS <= 700) Aeleron_uS = 700; // Min
if (Aeleron_uS >= 2100) Aeleron_uS = 2100; // Max
if (Elevator_uS <= 700) Elevator_uS = 700; // Min
if (Elevator_uS >= 2100) Elevator_uS = 2100; // Max
if (Throttle_uS <= 700) Throttle_uS = 700; // Min
if (Throttle_uS >= 2100) Throttle_uS = 2100; // Max
if (Rudder_uS <= 700) Rudder_uS = 700; // Min
if (Rudder_uS >= 2100) Rudder_uS = 2100; // Max
if (TI_uS <= 700) TI_uS = 700; // Min
if (TI_uS >= 2100) TI_uS = 2100; // Max
if (digitalRead(inPinD6) == 0) { // Low rate
DualrateMultAel = 0.5;
DualrateMultEle = 0.5;
DualrateMultThr = 0.9;
DualrateMultRud = 0.7;
DualrateMultTI = 0.9;
DualrateAdjAel = 200;
DualrateAdjEle = 200;
DualrateAdjThr = 0;
DualrateAdjRud = 100;
DualrateAdjTI = 0;
}
if (digitalRead(inPinD6) == 1) { // Normal/high rate
DualrateMultAel = 0.9;
DualrateMultEle = 0.9;
DualrateMultThr = 0.9;
DualrateMultRud = 0.9;
DualrateMultTI = 0.9;
DualrateAdjAel = 0;
DualrateAdjEle = 0;
DualrateAdjThr = 0;
DualrateAdjRud = 0;
DualrateAdjTI = 0;
}
if (digitalRead(inPinD11) == 1) { // TI Switch
TIsw_uS = 2100;
} else {
TIsw_uS = 700;
}
}