Go Down

Topic: Arduino-Controlled RC Transmitter (Read 67838 times) previous topic - next topic

jds

I wanted to add to my post above that the reason I ask if it is possible to use delay() instead of delaymicroseconds() is that I would like to have interrupts available for reading the ppm stream coming from my radio at more or less the same time when sending a ppm stream to my radio.

Syvwlch

I used microsecond delays because I needed the finer control over timing I got that way. Delay() only gives you delays in milliseconds, which is not precise enough for this application.

At least, that's what I remember of my reasoning, this was a while ago!

Syvwlch

Ah, I see. Sounds like an interesting application :-)

Again, I don't think you can generate the pulse stream with just delay(), you need smaller time increments, and I agree, that is going to prevent you from using interrupts to read your input.

Does your budget stretch to two arduinos? ;-)

jds

I overlooked the fact that delayMicroseconds() is about micro seconds and delay is about milli seconds.

I think I need a delayMicroseconds() that doesn't disable interrupts. Maybe it becomes a little less accurate, but I don't think that is a problem.

Two Arduinos wouldn't be a problem, but if it can be done with one than I should do it with one.

Thanks for your comments Mathieu!

jds

Tomorrow I will try if the following routine can replace delayMicroseconds():

Code: [Select]
void customDelay(unsigned long time) {
   unsigned long end_time = micros() + time;
   while(micros() < end_time);
}

cjparish

Hi Folks,

I know this is quite an old thread, but I thought you might be interested in this.

I decided to replace the PPM encoder board in my old Micron transmitter that I built from a kit some 15+ years ago with an arduino based solution.

This solution reads the four sticks, along with four switches and encodes them into the appropreate PPM pulse train. I have also included code for v-tail, differential and delta mixing.

The way my code differs from yours is in the way I generate the pulse train: I have used the 16bit timer (timer 1) set to phase and frequency correct PWM to generate the pulse train from an array of values.

The timer settings are:
Code: [Select]

  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 = timer_framelength;
  OCR1B = timer_pause;


and the ISR code is:

Code: [Select]

ISR(TIMER1_COMPA_vect)
{
 if (timer_ptr == number_of_outputs) {
   timer_ptr = 0;  //reset the pointer to 0
   OCR1A = timer_framelength - (timer_accumulator * timer_correction_factor); //calculate the padding
   timer_accumulator = 0;  //set the accumulator to 0
 }
 else {
   OCR1A = (pulses[timer_ptr] + timer_pause) * timer_correction_factor; //set the pulse length
   timer_accumulator += pulses[timer_ptr] + timer_pause; //add the pulse length to the accumulator
   timer_ptr++;  //increment the pointer
 }
}


and the required variables and constants are:

Code: [Select]

#define timer_correction_factor 1.09                        //timer correction factor. This is needed if your arduino is too fast or slow, like mine. :(
#define timer_framelength 20000 * timer_correction_factor   //Maximum framelength in counter ticks
#define timer_pause 300 * 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
int pulses[7];


To generate the pulse train, enter values into the array corrisponding to the channel pulse in micro seconds, so for a 2000 micro seconds pulse enter 2000. The frame padding is calculated automatically.

If anyone would like to take a look at the complete source code, feel free to download it; it's just too big to post here:
http://www.miselph.co.uk/arduino/Version_0_2.zip

I hope this can be of use to someone. When I have finished the project I will post the details on this forum.

If anyone needs any help with timers, I have become quite adept at dealing with them and would be more than happy to help

Chris

jds

Wow, I am impressed!

I had a quick look at the code and possibilities. You even included mixing. Are you planning any more possibilities, maybe dual rates?

Can you elaborate on how you connected the sticks and switches.\

You are using the original rf board from your Micron?

Syvwlch

Very, very cool. A huge improvement on my weak efforts! :-)

cjparish

Hi guys!
Thanks for the positive comments.

CrashingDuchman:
The code already includes both dual rates and exponential :D The exponential isn't brilliant, I need to find a better equation, but it does work.
The sticks are connected to analog pins 0,1,2 and 3 and the switches are connected to pins 8,11,12 and 13 (I didn't use 9 or 10 because they are the output pins from timer1)
As the code stands, switches 0 and 1 are set up to activate the rates on the ailerons and elevators.

Here is a piccit:


In this picture the yellow wires are the switches (my farnell order only arrived this morning, and I haven't got tound to wiring them up) and connecting any one of them to ground changes the switch state. The green leads trailing off to the right are the connection points for the oscilloscope.

I am using the original RF board from the Micron transmitter, which is a sub-board attached to the base of the antenna. However, this required me to use a FET attached to the pulse output pin (pin 10) to create a transistor NOT gate so as to facillitate switching of a higher voltage as the RF board runs at 9.5v

My long(er) term goals for this project include an on-transmitter (or plug in, as my tx case is quite small) lcd display and buttons for changing settings without having to reload the firmware, and upgrading the RF section to 2.4gHz.

I am planning on building this into my Mircon transmitter case, and when I do I will post more pics and upload the eagle schematics.

Chris

IanJohnston

Hi all,

Am jumping in here.......Chris's code is just what I was looking for.

I'm going to fit an Arduino inside a 3-axis joystick in order to generate the PPM for connection to my Futaba radio. So, with a 2*16 LCD embedded also it's going to be fun.

I'd already bought the joystick plus other bits and bobs, so this jump-start with the code is great. Thanks Chris.

Ian.

cjparish

Hi Ian,

If you want to use the 16 x 2 LCD as I have you might like the library I have written to control it via a shift register (so it uses less pins :) ).
All the info, including vero-board layout and library can be found on my blog:

http://cjparish.blogspot.com/

Let me know how you get one with it!

Chris

IanJohnston

#41
Mar 27, 2010, 11:40 pm Last Edit: Mar 27, 2010, 11:45 pm by IanJohnston Reason: 1
Well tonight I made a start. I ripped out the original circuit board from a Saitek AV8R-01 and replaced it with an Arduino Nano.



Then I took Chris's code and modified it to use my own I2C LCD library. This will be for de-bugging/testing only as sadly there's no real space to mount an LCD.....unless I change to a tiny 2*16 one. Hmmm!

First problem I have is that all the pots in the joystick are all LOG pots, so the voltages I'm getting aren't linear so I'm gonna change them out.

Chris, I had a quick look through your code when I was changing the LCD library, and I couldn't see where your I/O mapping is done. Also, where to set ranges etc. Any hints/tips before I get stuck right in. I'm more a hardware man than software........but I'll hack my way around no worries.

Ian.

cjparish

#42
Mar 28, 2010, 12:05 am Last Edit: Mar 28, 2010, 12:17 am by cjparish Reason: 1
Hi Ian,

Hardware mapping:

If you open the sketch and look at the sticks_include.h tab and look at line 21 you sould find:

Code: [Select]

int stick_inputs[4] = {0,1,2,3}; //input ports for the sticks


and in switches_include.h on line 6

Code: [Select]

int switch_pins[number_of_switches] = {11,12,13,8};


The stick ranges are set in the sticks_include.h file, right at the top.
Code: [Select]

const int stick_limits[4][3] = { //stick limits, given as top, center and bottom
 {
   604, 501, 396            }
 ,
 {
   620, 501, 396            }
 ,
 {
   617, 511, 398            }
 ,
 {
   649, 480, 368            }
};


I have also changed the PPM generation timings slightly, they should be:

Code: [Select]

#define OUTPUT_TOP 2000 - timer_pause
#define OUTPUT_CENTER 1500 - timer_pause
#define OUTPUT_BOTTOM 1000 - timer_pause

in the output_include.h file

Does that help?

IanJohnston

#43
Mar 28, 2010, 02:48 pm Last Edit: Mar 28, 2010, 04:20 pm by IanJohnston Reason: 1
Chris,

Thanks, that helps.

I'm not getting any PPM output anywhere, have scoped all dig pins. Which output should it be on, and any reason why I'm getting nothing, i.e. does it need activated.

I'm using a Arduino Nano 3.0 (ATmega328) which should be same as Duemilanove (328).

Have reverted back to your original code but still no joy.

Ian.

cjparish

The output should be on pin 10.
Make sure that you have set pinMode(10, OUTPUT); or it won't work.

The chip should be the same, just a different package.

Try running this:

Code: [Select]


void setup()
{
  setup_timer();
}


void 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 = 20000;
  OCR1B = 10000;

  pinMode(10, OUTPUT);
}

void loop()
{

}


I haven't tested it, but that should output a nice square waveform at 50hz. If it doesn't work then there is an issue with how I have set the timers. The normal way to set the timers is by using statements like:
Code: [Select]

TCCR1B = _BV(WGM13) | _BV(CS11);

which allow portability across different chips where the registeres might be slightly different, but according to the data sheet our processors are the same.

Let me know how you get on.

Go Up