Well I have just put the Arduino to some useful work - converting one of Brian's 35Mhz transmitters (Futaba Skysport 6A) to 458MHz. (John W showed the way on here in the 458MHz thread.)
The Arduino Nano does the work of converting the stick inputs (I have retained the case and pots) and feeding it into an Orange 458Mhz TX module. I used the Funduino breakout board for the Nano for about £2.50 on ebay. This made the connection easier but the pin alignment is a little confusing. My main error was connecting the ppm output to the wrong pin. The ppm signal is easily picked up on a scope (which I am lucky to have) so I could find the right pin.
I have only just got it working but it looks very promising. I still have to decide what to do about some of the aircraft features e.g exponential. I think I will use the "Flaps" pot for control of the proportional piston tank.
(Gosh John is posting a reply as I write this. Good point John. Do read the excellent instructions by Phil Green.) I will not post a photo yet because it is a bit of a "rat's nest"- even by my standards!
Cost of this TX amounts to about £18! I am using the China sourced Nanos which are a bit "like fuses". Two have died already but on the plus side they only cost about £2.50 each. So this is still a remarkably cheap project.
Many thanks to Phil Green for all his work on this project.
Phil Green's software follows just bung it in as a sketch in the Arduino Nano:
// 7 channel encoder by Phil Green
// Simple, minimal six channel PPM encoder. Four propo, one toggle-switched with servo-slow (ch6), one momentary button (ch5)
// Please do not use bootloader, startup delay messes things up and can strip servo gears.
// Connections:
// Pots wired between ground and regulated 5v from Arduino. Wipers connected as follows:
// A0=aileron, A1=elevator, A2=rudder, A3=throttle. A6=expo, A7=rates. D10=mixer, D11=ch5 button, D12=hip-hop group, (and also ch6 toggle switch)
// Features
// Stick calibration - hold button in, switch on, still holding button move sticks and trims to extreme corners. Centralise trims, release button.
// Variable expo & rates on ch1, 2 & 4. Elevon mixer on ch1 & ch2, 75% aileron, 25% elevator.
// Flick toggle 3x for range test. Servo reversing by holding sticks over on power up (saved to eeprom). Servo-slow on channel 6 toggle.
// Scope trigger on D10. Thanks to Paul Luby for his expo maths!
// Phil_G on most forums, philg@talk21.com http://www.singlechannel.co.uk
int sw_mix = 10; // mixer switch
int sw_btn = 11; // pushbutton channel 5
int sw_tog = 12; // toggle channel 6
int ppm = 13, ppmPulse = 300, neutralPulse = 1200, raw, flips, ch, calibrated=1, startup=1, stickcalHi[]={0,0,0,0}, stickcalLo[]={1023,1023,1023,1023};
float ch0val, chtemp, channel[]={1200,1200,1200,1200,1200,1200,8000}; // last is sync
float lastch6, cchannel6, slow, sweep, rate =0, expo = 0;
byte reverse[]={0,0,0,0,0,0}, rangetest=0, flip=0;
unsigned int framecounter=0;
#include <EEPROM.h>
void setup() {
noInterrupts();
pinMode(ppm, OUTPUT);
pinMode(sw_mix, INPUT_PULLUP); // set to OUTPUT for scope trigger
pinMode(sw_btn, INPUT_PULLUP);
pinMode(sw_tog, INPUT_PULLUP);
}
void loop() {
while (startup==1 && digitalRead(sw_btn) == 0) {
// calibrate sticks
calibrated=0;
for (int stick=0; stick <4; ++stick) {
raw=analogRead(stick);
if (raw > stickcalHi[stick]) stickcalHi[stick] = raw;
if (raw < stickcalLo[stick]) stickcalLo[stick] = raw;
}
}
if (startup==1 && calibrated==0) {
for (ch=0; ch<4; ch++) {EEPROMWriteInt(ch*4,stickcalLo[ch]); EEPROMWriteInt(ch*4+2,stickcalHi[ch]);}
calibrated=1;
}
if (startup==1) {
for (ch=0; ch<4; ch++) {stickcalLo[ch]=EEPROMReadInt(ch*4); stickcalHi[ch]=EEPROMReadInt(ch*4+2); reverse[ch]=EEPROM.read(ch+16) & 1; }
reverse[3]=0; // no throttle reverse for safety
slow=digitalRead(sw_tog)==0 ?500:-500; // initial channel 6 value
}
for (ch=0; ch<4; ch++) {channel[ch] = map(analogRead(ch),stickcalLo[ch],stickcalHi[ch],-500,500); channel[ch] = constrain(channel[ch], -600, 600);}
channel[4]=digitalRead(sw_btn)==0 ?500:-500; // channel 5
if (digitalRead(sw_tog) == 0) {
cchannel6 = 500;
if (slow < 500) slow+=2;
}
if (digitalRead(sw_tog) == 1) {
cchannel6 = -500;
if (slow > -500) slow-=2;
}
channel[5]=slow;
ch0val=channel[0];
// check for reversing, stick over on power-up, not throttle though.
if (startup==1) {
for (ch=0; ch<3; ch++) {
if (channel[ch] > 450 || channel[ch] < -450) { reverse[ch] ^=B00000001; EEPROM.write(16+ch,reverse[ch]);}
}
}
// end of once-only startup routines
startup=0;
// read expo pot
expo = map(analogRead(A6),0,1023,100,300); expo/=100;
// read rates pot
rate = map(analogRead(A7),0,1023,100,10);
rate/=100;
for (ch=0; ch<3; ch++) {
if (channel[ch] <0) {channel[ch]=abs(channel[ch])/500; channel[ch]=pow(channel[ch],expo)*-500; }
else
channel[ch]=(pow(channel[ch]/500,expo)*500);
channel[ch]*=rate;
}
// do timed stuff
if (cchannel6 != lastch6) {++flips; framecounter=0;}
if (framecounter < 12 && flips >5) {
rangetest ^= 1; // this flags the 3 flicks 'active'
framecounter=12;
}
if (framecounter > 11) flips=0;
lastch6=cchannel6;
// format the frame
channel[6]=0; // 6th element is sync
for (ch=0; ch<6; ch++) {
channel[ch]+=neutralPulse;
if (reverse[ch] ==1) channel[ch] = 2400-channel[ch];
channel[6]+=channel[ch];
}
channel[6] = 15500-channel[6];
chtemp=channel[3]; channel[3]=channel[2]; channel[2]=chtemp; // change channel order to Futaba AETR
if (rangetest==1) {
channel[2]=700; // throttle low
if (framecounter==50) {
framecounter=0;
flip^=1;
}
channel[0]=flip==0 ?800:1600;
if (ch0val < -50 || ch0val > 50) rangetest=0;
}
// check if mixer switched in
if (digitalRead(sw_mix) == 0) {
channel[0]*=.75;
channel[1]*=.25;
chtemp=channel[1];
channel[1]=channel[0]+600-channel[1];
channel[0]+=chtemp;
}
//send ppm frame, last channel holds sync value
for (int ch=0; ch<7; ch++) {
digitalWrite(ppm, HIGH);
delayMicroseconds(ppmPulse);
digitalWrite(ppm, LOW);
delayMicroseconds(channel[ch]);
}
if (framecounter<255) ++framecounter;
// scope trigger pin 10, ensure mixer switched off, then temp define as OUTPUT in setup
// digitalWrite(10, HIGH);
// delayMicroseconds(100);
// digitalWrite(10, LOW);
}
// This function will write a 2 byte integer to the eeprom at the specified address and address + 1
void EEPROMWriteInt(int p_address, int p_value)
{
byte lowByte = p_value%256;
byte highByte = p_value/256;
EEPROM.write(p_address, lowByte);
EEPROM.write(p_address + 1, highByte);
}
//This function will read a 2 byte integer from the eeprom at the specified address and address + 1
unsigned int EEPROMReadInt(int p_address)
{
byte lowByte = EEPROM.read(p_address);
byte highByte = EEPROM.read(p_address + 1);
return lowByte + highByte*256;
}
Last edited by david f on Sun Nov 29, 2015 2:02 pm; edited 9 times in total
Tue Oct 29, 2024 4:46 pm by tsenecal
» RC Drift Gyro for pitch control
Sun Oct 20, 2024 2:04 pm by geofrancis
» WW2 mini sub build
Thu Oct 17, 2024 2:34 pm by geofrancis
» sonar data link
Mon Oct 14, 2024 4:31 pm by geofrancis
» Robbe Seawolf V2
Sat Oct 12, 2024 3:52 pm by geofrancis
» ExpressLRS - 868/915 Mhz equipment
Fri Oct 11, 2024 8:58 pm by Marylandradiosailor
» Flight controllers as sub levelers
Fri Oct 11, 2024 8:14 pm by geofrancis
» 868/915 Mhz as a viable frequency for submarines.
Thu Oct 10, 2024 3:21 am by tsenecal
» Microgyro pitch controller corrosion
Wed Oct 02, 2024 11:32 am by geofrancis