Pages: 1 ... 3 4 [5] 6   Go Down
Author Topic: Arduino-Controlled RC Transmitter  (Read 26216 times)
0 Members and 1 Guest are viewing this topic.
Poole
Offline Offline
Jr. Member
**
Karma: 0
Posts: 89
I'm not a complete idiot. Some bits are missing
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi sonicj!
Unfortunatly pin 10 is required, as it is the output from the hardware timer. The way I have programmed it it uses both compare registeres to produce the waveform, but yeh final output if from compare b which is hardwired to pin 10.
Sorry.

Chris
Logged

Panama City, FL USA
Offline Offline
Jr. Member
**
Karma: 0
Posts: 51
five by five
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

dang!

so is that a hardware limitation or just a product of your specific code that ties it to pin 10? could the timer be inverted to output to the Compare Match A Pin? i skimmed over the timer section of the manual and i got the impression that they performed in the same manner...?

i had no idea that there were this many options and variables available to a single timer! its incredible how much is really going on inside something so small!

i was able to get the transmitter code working with a 16x2 LCD on a 74ls164n shift register using the ShiftRegLCD library in 2-Wire mode with very little effort! i changed the #define, pin_mode and commented out lcd.begin(16,2); and it seems to be working ok. i might be missing some functionality, but at least its not printing chinese anymore!  smiley i have a couple 74hc595's in route so i can compare the difference. i prefer my $1.50 LCD and $0.70 shift register over my $25 sparkfun serial lcd anyday!

cheers!
-sj
Logged

Panama City, FL USA
Offline Offline
Jr. Member
**
Karma: 0
Posts: 51
five by five
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

built a new "shield" and i've got chris' code running on a duemilanove with working pin 10 now!

any clues to where i should look for variables to invert the ppm stream? i tried inverting / reversing pulse = map but that didn't get it. i tried multiplying some stuff by -1 with no luck. not sure what else to look for... :-/
-sj
Logged

Poole
Offline Offline
Jr. Member
**
Karma: 0
Posts: 89
I'm not a complete idiot. Some bits are missing
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello again,

I am not sure exactly which version of the code you are using, but look for this line (it should be on the 'timer' tab)

TCCR1A = B00110001;
 and change it to
TCCR1A = B00100001;

That should invert the output for you.

The reason this works it that the output it created using hardware timer1 and we need to change the way that the output compare register effects the output of the signal generator. (see page 136 of the ATMega368 datasheet for more info...)

Chris
Logged

Panama City, FL USA
Offline Offline
Jr. Member
**
Karma: 0
Posts: 51
five by five
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

sweet! that did it, thanx!

i KNEW i had seen inverting somewhere... just couldn't put my finger on it; that manual is LOT to take in!

the spektrum module is recognizing the PPM train as it lights up and binds to a rx. servos are whilin' out though so i suppose i need to make some tweaks to the pulse or frame lengths. there are some slight ripples in voltage (not sure what that matters) but the pulse timings look solid!

*edit* - im using your Version_0_2 code

« Last Edit: August 09, 2010, 05:50:14 pm by sonicj » Logged

Poole
Offline Offline
Jr. Member
**
Karma: 0
Posts: 89
I'm not a complete idiot. Some bits are missing
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The voltage ripples are tiny and shouldn't make any difference at all.
What is it your sevos are doing? My thinking is this: if you are missing some channels then try increasing the frame length. If the servos are unstable then you could try increasing the padding time (this is the time the signal spends high) it might help to look at the output from your receiver.
Nice scope by the way. I wish mine did that, but it is 25 years old and I count myself lucky if it takes less than five minutes to warm up!
Logged

Panama City, FL USA
Offline Offline
Jr. Member
**
Karma: 0
Posts: 51
five by five
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The voltage ripples are tiny and shouldn't make any difference at all.
thats what i thought too... but andykunz of spektrum mentions ac or dc coupling here. not sure how that applies yet though...

Quote
What is it your sevos are doing? My thinking is this: if you are missing some channels then try increasing the frame length. If the servos are unstable then you could try increasing the padding time (this is the time the signal spends high) it might help to look at the output from your receiver.
i think it would be best described it as jitter or constant twitching regardless of position. i tried extending the frame length to 25ms as mentioned in this thread but it didn't seem to help. i'll try adding to the padding next.

when i first loaded ian's code i had some jitter from the servos that seemed to clear up after calibrating the sticks. monitoring the rx outputs made setting up the sticks a lot easier! i'll try that in a minute too!

Quote
Nice scope by the way. I wish mine did that, but it is 25 years old and I count myself lucky if it takes less than five minutes to warm up!
thanx, lol! i purchased this one after much fighting with my dad's Telequipment scope of the same era! i've had it less than a week and im hooked! its surprisingly well built, is easily converted to 100mhz, small, light, cheap, and has a Auto Button!  smiley-wink  heres a link if you're interested. link
cheers!
-sj
Logged

Panama City, FL USA
Offline Offline
Jr. Member
**
Karma: 0
Posts: 51
five by five
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

its definitely a timing issue! changing values in the timer makes the problem/worse so now it just a matter of locating the proper bits of code and plugging in the right values. this is what i have so far:
Code:
//Timer data
#define timer_correction_factor 1.00                       //timer correction factor. This is needed if your arduino is too fast or slow
#define timer_framelength 25000 * timer_correction_factor   //Maximum framelength in counter ticks
#define timer_pause 350 * timer_correction_factor           //Pause between pluses in counter ticks

int timer_accumulator = 0;        //accumulator. Used to calculate the frame padding
int timer_ptr = 0;                 //timer array pointer
i changed the correction factor to 1.0 and this gave me a perfect framelength frequency
i changed the framelength to 25ms
and im getting 0.348ms pulses

i think this is right, but does the following produce a centered pulse if no stick connected to a particular channel?
Code:
void stick_check()
{
  for (int i = 0; i < 5; i++) {
    sticks[i].position = 50;
  }
}

i think all i have left is to widen the LOW so that the pulse ranges are between 1.5 and 2.5ms. looks like currently they are at 1ms at what i think are centered sticks. gotta plug the yoke back in to find out where im at for sure. getting close!  smiley
-sj
Logged

Poole
Offline Offline
Jr. Member
**
Karma: 0
Posts: 89
I'm not a complete idiot. Some bits are missing
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello,

I have to say, I am very surprised that you are having any problems at all, when I use the code (and I have flown with it on several occasions) i have no problems what so ever; it has been jitter free and rock solid. Admittedly i am on 35mHz rather than 2.4 but I don't see how that would be any different.

 The length of the servo pulse is given by the time between the rising edge of one pulse in the ppm chain and the rising edge of the next, not by the length off the low segment in-between.

I know that as i wrote the code I am probably a bit biased, but i assure you it produces a valid ppm stream with accurate pulses for each servo, it must do as i have flown with it. The correction factor is in there because my arduino runs too fast (weird i know, but i have three arduinos and only one of them requires correction!)
I suspect that the problem is coming when the spektrum module you are using is reading the signal. Have you tried scoping the output from a known good transmitter and comparing that to the arduino output. Could it be that the spektrum module is expecting a ppm chain with voltage of 9.6v as most transmitters run on 8 cells? In which case the 5v chain my not be being detected correctly. The reason that the original code produces an inverted ppm chain is because i then ran it through a transistor NOT gate to switch 9.6v as my 35mHz gear needed a higher voltage signal to the rf board.

Let me know how you get on.

Chris  
Logged

Poole
Offline Offline
Jr. Member
**
Karma: 0
Posts: 89
I'm not a complete idiot. Some bits are missing
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
i think all i have left is to widen the LOW so that the pulse ranges are between 1.5 and 2.5ms. looks like currently they are at 1ms at what i think are centered sticks

Sorry, I ment to say in my last post; the correct timing for standard is 1 to 2ms with 1.5 being centred. I found a PDF file that explains exactly how the ppm stream works that is very very helpful http://www.omegaco.demon.co.uk/mectnpdf/mectn004.pdf
Most modern servoes will work over an extended range of around 0.6 to 2.4ms

Chris
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 7
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, i am trying to get it running using a Serial connection to my PC. For now its possible to send Channel ID and Position via Serial to the Arduino and the PPM will be adjusted.

The BIG problem is that it my Serial connection is not reliable - i think its because of a timing problem.

Maybe someone of you guys/girls have an idea or solution?

I used Ver 1.6 of Ian´s code and removed all but the most important parts:


? Code should have been here, but i need to post a "normal" message first .... so code in next message (i hope)...


If you start sending - for example-  S010800 ( Set Channel 1 to pos 800) via Serial to the Arduino quite fast you will end up with wrong Serial commands.
I have no real clue why.... :-[
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 7
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is the code i use:


Code:
//Serial to PPM based on Ian´s:
//// RC Joystick 430mHz
//// For use with Arduino Nano V3.0
//// Ian Johnston 28/04/2010
////
//// If you would like to help support future projects like these then please
//// make a small PayPal donation via my website www.ianjohnston.com
//// Thanks!
////
//// Ver 1.6 - Now using Timer1 to set 22mS refresh for PPM output.
////           Dual rates are implemented but need custom setup.
////           Trimming is not working.
////           Battery monitor sub tweaked
////           Adjusted timing off various subs
////           Various tweaks to LCD & battery monitor
////
// Serial to PPM ??? SEND: S010800 to set Channel 1 to Pos 800

int tick = 0; // Used for various timing of subs
int tick2 = 0; // Used for various timing
int slowflag;

int CH1= 700;
int CH2 = 700;
int CH3 = 700;
int CH4 = 700;
int CH5 = 700;
int CH6 = 700;

int RatesHIMIDLO = 2; // Default is MID rates
int TrimSetting = 0;
int Fixed_uS = 300;       // PPM frame fixed LOW phase
int pulseMin = 700;          // pulse minimum width in uS
int pulseMax = 1700;      // pulse maximum width in uS
int outPinTEST = 8;       // digital pin 8
int outPinPPM = 10;       // digital pin 10


//*** Serial COM&Comand
const int MSG_LENGTH = 7;  // message is char 'S' followed by 6 digits
const char HEADER  = 'S';
//***

ISR(TIMER1_COMPA_vect) {

  ppmoutput(); // Jump to ppmoutput subroutine
  tick = tick + 1;  // update timing tick for subs
  tick2 = tick2 + 1;  // update tick

}

void setup() {

  // setup I/O
  pinMode(outPinPPM, OUTPUT);   // sets the digital pin as output


  // ** SERIAL SETUP
  Serial.begin(57600);         // connect to the serial port
  Serial.println("Serial to PPM");
  //****


  // 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 = 22000; // 22mS PPM output refresh
  OCR1B = 1000;
}


void loop() { // Main loop
  processSerial();
  //readanainputsmap(); // Run sub - read ana inputs & map
  checklimits();      // Run sub - check individual channel PPM limits
  //
  //  if (tick >= 11) {     // only run certain subs every 1/4 sec or so (22mS * 11 = 242mS)
  //      tick = 0;
  //      //switchesRates();    // Run sub - read panel switches
  //      //batterymonitor();   // Run sub - check battery
  //  }
  //  
  //  // generate slow changing flag, about 2sec on/off
  //  if (tick2 <= 50) {
  //      slowflag = 0;
  //  }
  //  if (tick2 >= 50 && tick2 <=100) {
  //      slowflag = 1;
  //  }
  //  if (tick2 >= 100) {
  //      slowflag = 0;
  //      tick2 = 0;
  //  }

}


void processSerial() {
  // Process a message available on serial port
  while(Serial.available() >=  MSG_LENGTH )  // process messages when all characters are received: "S" as start indicator, 2 digits as channel number, 4 digits for the value
  {
    if(Serial.read() == HEADER ) //Serial.Read() will "use up" the chars, so we can forget about the "S" now...
    {
      int val = 0;
      int sval =0;
      //First 2 digits are the Channel...
      for(int i =0; i < MSG_LENGTH-5; i++)//7-5=2
      {

        char ch = Serial.read();
        if(ch >= '0' && ch <= '9'){            // is ch a number?
          sval = sval * 10 + ch - '0';           // yes, accumulate the value
        }

      }
      Serial.print("CH: ");
      Serial.println(sval); // For debug


      //Next 4 Digits should be the position/
      for(int i =0; i < MSG_LENGTH-3; i++) // 7-3=4 ... 2+4=6 ... S-12-3456
      {
        char ch = Serial.read();
        if(ch >= '0' && ch <= '9'){            // is ch a number?
          val = val * 10 + ch - '0';           // yes, accumulate the value
        }
      }
      Serial.print("POS: ");
      Serial.println(val); // for debug
      Serial.flush();//clear buffer, there might be some rubbish inside...
      //Serial.println(sval);
      //Serial.println(val);
      // For now its just Channel 1 which will get its new value.
      if (sval==1){
        CH1=val;
        Serial.print("CH1 Set to ");
        Serial.println(CH1);
      }


    }
  }

}


void checklimits() { // check limits sub
  if (CH1 < 700) CH1 = 700;     // Min
  if (CH1 > 1700) CH1 = 1700;   // Max  
  if (CH2 < 700) CH2 = 700;   // Min
  if (CH2 > 1700) CH2 = 1700; // Max
  if (CH3 < 700) CH3 = 700;   // Min
  if (CH3 > 1700) CH3 = 1700; // Max
  if (CH4 < 700) CH4 = 700;       // Min
  if (CH4 > 1700) CH4 = 1700;     // Max  
  if (CH5 < 700) CH5 = 700;               // Min
  if (CH5 > 1700) CH5 = 1700;             // Max
  if (CH6 < 700) CH6 = 700;               // Min
  if (CH6 > 1700) CH6 = 1700;             // Max
}


void ppmoutput() { // PPM output sub
  // test pulse - used to trigger scope
  //digitalWrite(outPinTEST, LOW);
  //delayMicroseconds(100);    // Hold
  // digitalWrite(outPinTEST, HIGH);

  // Channel 1 - Aeleron
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);
  delayMicroseconds(CH1);  // Hold for Aeleron_uS microseconds      

  // Channel 2 - Elevator
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);
  delayMicroseconds(CH2); // Hold for Elevator_uS microseconds      

  // Channel 3 - Throttle
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);
  delayMicroseconds(CH3); // Hold for Throttle_uS microseconds      

  // Channel 4 - Rudder
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);
  delayMicroseconds(CH4);   // Hold for Rudder_uS microseconds

  // Channel 5 - TI Switch
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);
  delayMicroseconds(CH5);     // Hold for TIsw_uS microseconds        

  // Channel 6 - TI pot
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);
  delayMicroseconds(CH6);       // Hold for TI_uS microseconds  

  // Synchro pulse
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);  // Start Synchro pulse

}
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 7
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

 ;D

I used Chris Code today and Lo and behold: Its working like a charm now  :smiley

Well, i guess it was all about the Interrupt in the timer ... now there is plenty of time for the UART AND no more kick in while the UART is working...

Only drawback is that i blew my PIN 10 on my Arduino Mega, but work is in progress on an Duemilano now.

You guys Rock!


Question: I like to buy a new Joystick for Mac/PC, the one i have at the moment only puts out values between -127 and +127, so 8Bit resulution. Not that good even i doubt that many RC Servos have a better resolution.
Does anyone know a good (not too expencive) Joystick with atlast a 10Bit Resolution?

Thanks!
Logged

Netherlands
Offline Offline
Sr. Member
****
Karma: 0
Posts: 414
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

would you consider a Wii Nunchuck?
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 7
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wii Nunchuck - mmm... its Bluetooth and i try to avoid 2.4GHz equiptment since it have my 2.4GHz RC Transceiver next to my PC and i don´t like to debug errors which might occure because of that. As soon as everything else works fine, i might try a Nunchuck too  smiley

An other Question: As i allready wrote i blew up my Pin 10 on my Adruino Mega.. What would be the best way to protect that Pin since it seems to be quite fragile? A fast Diode?
Logged

Pages: 1 ... 3 4 [5] 6   Go Up
Jump to: