Here's a quick writeup of what you're looking for, I haven't tested it (haven't even compiled it) so I'm not sure it works, but it should give you a fairly good hint in the right direction.
What you basically want is tie PPM-input directly to Servo Out
#include<ServoOut.h>#include<Timer1.h>#define CHANNELS 4#define SERVOS 4uint16_tg_channels[CHANNELS];// output buffer for PPMInuint8_tg_workIn[PPMIN_WORK_SIZE(CHANNELS)];// we need to have a work buffer for the PPMIn classrc::PPMIng_PPMIn(g_channels,g_workIn,CHANNELS);uint8_tg_pinsOut[SERVOS]={2,3,4,5};// Output pinsuint16_tg_servos[SERVOS];// Input buffer for servoOut, microsecondsuint8_tg_workOut[SERVOOUT_WORK_SIZE(SERVOS)];// we need to have a work buffer for the ServoOut classrc::ServoOutg_ServoOut(g_pinsOut,g_servos,g_workOut,SERVOS);voidsetup(){// Initialize timer1, this is required for all features that use Timer1// (PPMIn/PPMOut/ServoIn/ServoOut)rc::Timer1::init();// We use pin 8 as PPM input pinpinMode(8,INPUT);// We use pin change interrupts to detect changes in the signal// If you're unfamiliar with how this works, please look up some// article or tutorial on the subject.// only allow pin change interrupts for PB0 (digital pin 8)PCMSK0=(1<<PCINT0);// enable pin change interrupt 0PCICR=(1<<PCIE0);// set up the output pinsfor(uint8_ti=0;i<SERVOS;++i){pinMode(g_pinsOut[i],OUTPUT);// put them lowdigitalWrite(g_pinsOut[i],LOW);// fill servo output buffer (input for ServoOut)g_servos[i]=1000;}// start listeningg_PPMIn.start();// start outputtingg_ServoOut.start();}voidloop(){// update incoming valuesg_PPMIn.update();if(g_PPMIn.isStable()){// do magic, incoming values available in g_channels in microseconds.// update the input bufferfor(uint8_ti=0;i<SERVOS;++i){// fill ServoOut input buffer directly from PPMIng_servos[i]=g_channels[i];}// tell ServoOut there are new values available in its input bufferg_ServoOut.update();}}
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2014-09-14
Hi!
I stumbled upon your library a few hours ago, since I'm trying to send a PPM signal from a transmitter to a receiver and to feed 3 servos. I used the example you gave (on top of my comment to servo pinOut 4), but the outcome was a very fast non-stop throwing up-and-down of just one of the servos (i think). I tried to move it with the joystick from the receiver side, but it barely changed the outcome, it didn't stop with the fast throttling up-and-down.
What do you think is the problem, how can i fix it ?
PS:I'm just starting to use and learn about microcontrollers, PPM, PWM and C++, I know that's one of the problems :)
Regards, George
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Try using one servo first, if that works fine then the servos are probably causing a lot of noise on the power lines. I've seen this happen using some cheap micro servos. The moment the one of the servos starts moving it will draw quite some current and this is interfering with the servo signals. You can fix this by adding a small electrolytic capacitor between the power and ground lines of the servos. Most receivers I've seen also have an electrolytic cap for this purpose.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2014-09-15
Hi!
I tried your advice, to use one servo only but it's not moving at all now.
Maybe I didn't understand your lib since I don't know C++ (I'm a Java developer).
What I'm trying to do is make a robotic hand controlled by joysticks and a microcontroller sending PPM transmit signal to a transmitter, and the transmitter to send the signal to another microcontroller. And the controller to decode the PPM and feed the servos with it.
If You can spend the time to look through what I'm uploading on both sides, and maybe tell me what I'm doing wrong, this will be of great help for me !
Regards, George
Transmitter and Joystick side:
//PPM OUT#include<PPMOut.h>#include<Timer1.h>#define CHANNELS 1uint8_tg_pins[CHANNELS]={0};// Input pins for the Joystick pot ????uint16_tg_input[CHANNELS];// Input buffer in microsecondsuint8_tg_work[PPMOUT_WORK_SIZE(CHANNELS)];// we need to have a work buffer for the PPMOut class// PPMOut requires two buffers:// Input buffer containing input samples in microseconds// Work buffer of ((channels + 1) * 2) elements for internal calculations and frame buffering// This setup removes any limit on the number of channels you want, and makes sure the library doesn't use more// memory than it really needs, since the client code supplies the buffers.rc::PPMOutg_PPMOut(CHANNELS,g_input,g_work,CHANNELS);voidsetup(){// Initialize timer1, this is required for all features that use Timer1// (PPMIn/PPMOut/ServoIn/ServoOut)rc::Timer1::init();for(uint8_ti=0;i<CHANNELS;++i){// set up input pinspinMode(g_pins[i],INPUT);// fill input buffer, convert raw values to microsecondsg_input[i]=map(analogRead(g_pins[i]),0,1024,1000,2000);}// initialize PPMOut with some settingsg_PPMOut.setPulseLength(448);// pulse length in microsecondsg_PPMOut.setPauseLength(10448);// length of pause after last channel in microseconds// note: this is also called the end of frame, or start of frame, and is usually around 10ms// start PPMOut, use pin 9 (pins 9 and 10 are preferred)g_PPMOut.start(9);}voidloop(){// update the input bufferfor(uint8_ti=0;i<CHANNELS;++i){// fill input buffer, convert raw values to microsecondsg_input[i]=map(analogRead(g_pins[i]),0,1024,1000,2000);}// tell PPMOut there are new values available in the input bufferg_PPMOut.update();}
Receiver and Servos side:
//PPM IN#include<PPMIn.h>#include<ServoOut.h>#include<Timer1.h>#define CHANNELS 1#define SERVOS 1uint16_tg_channels[CHANNELS];// output buffer for PPMInuint8_tg_workIn[PPMIN_WORK_SIZE(CHANNELS)];// we need to have a work buffer for the PPMIn classrc::PPMIng_PPMIn(g_channels,g_workIn,CHANNELS);uint8_tg_pinsOut[SERVOS]={3};// Output pinsuint16_tg_servos[SERVOS];// Input buffer for servoOut, microsecondsuint8_tg_workOut[SERVOOUT_WORK_SIZE(SERVOS)];// we need to have a work buffer for the ServoOut classrc::ServoOutg_ServoOut(g_pinsOut,g_servos,g_workOut,SERVOS);voidsetup(){// Initialize timer1, this is required for all features that use Timer1// (PPMIn/PPMOut/ServoIn/ServoOut)rc::Timer1::init();// We use pin 8 as PPM input pinpinMode(8,INPUT);// We use pin change interrupts to detect changes in the signal// If you're unfamiliar with how this works, please look up some// article or tutorial on the subject.// only allow pin change interrupts for PB0 (digital pin 8)PCMSK0=(1<<PCINT0);// enable pin change interrupt 0PCICR=(1<<PCIE0);// set up the output pinsfor(uint8_ti=0;i<SERVOS;++i){pinMode(g_pinsOut[i],OUTPUT);// put them lowdigitalWrite(g_pinsOut[i],LOW);// fill servo output buffer (input for ServoOut)g_servos[i]=1000;}// start listeningg_PPMIn.start();// start outputtingg_ServoOut.start();}voidloop(){// update incoming valuesg_PPMIn.update();if(g_PPMIn.isStable()){// do magic, incoming values available in g_channels in microseconds.// update the input bufferfor(uint8_ti=0;i<SERVOS;++i){// fill ServoOut input buffer directly from PPMIng_servos[i]=g_channels[i];}// tell ServoOut there are new values available in its input bufferg_ServoOut.update();}}
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Your code looks okay at first glance. How did you wire your hardware? What kind of transmitter and receiver are you using? Depending on the type of hardware you may have to set the number of channels to match the number of channels on the RX/TX. My Esky TX/RX combo for example always expects a 6 channel PPM signal, even if I only want to use just three channels.
But anyway, if all you want to do at the receiving side is control a bunch of servo's and you already have an RC receiver, then you might as well just hook the servos directly to the RX, no need to add an extra microcontroller, unless you want to do all sorts of post processing :)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2014-10-21
I too am looking to control some servos wirelessly. Here's my setup.
Transmit side: Atmega 328p Arduino Pro Mini 5v. Uses the PPM_OUT to generate a 2 channel PPM signal that is transmitted via a 433mhz rf transmitter directly connected to the ppm output pin as designated by your suggested PPM_out example in your library.
Receive side: Atmega 328p Arduino Pro Mini 5v. Taking the TX ppm input from a 433mhz receiver. Than it should generate appropriate servo signal, and push it out to the two servo's.
When I use the above code I get no servo movement whatsoever. I can see my led blinking on the TX side, and seems that a PPM signal is being transmitted, and received. Some guidance here would be much appreciated.
This is the first in a series of RC projects I am looking to do with increasing number of channels. But first wanted to start with something simple.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I suggest you test the two parts on the RX side (PPMIn and ServoOut) individually to narrow down the cause of the problem.
Verify that you actually receive what you transmit, for example by lighting up the on board LED when a channel has a specific value, or when it's value is below or above a certain threshold.
Verify that the servos can actually be controlled by hardcoding the values in g_servos to various values. You can "animate" them by incrementing the value in the loop function and making the code sleep for a dozen milliseconds.
so something like this
void loop()
{
// update the input buffer
for (uint8_t i = 0; i < SERVOS; ++i)
{
++g_servos[i];
if (g_servos[i] > 2000)
g_servos[i] = 1000;
}
// tell ServoOut there are new values available in its input buffer
g_ServoOut.update();
delay(16);
}
If that works properly, then at least the servo control works fine.
As for the RX testing:
void loop()
{
// update incoming values
g_PPMIn.update();
if (g_PPMIn.isStable())
{
// turn led on.
}
else
{
// turn led off.
}
}
and
void loop()
{
// update incoming values
g_PPMIn.update();
if (g_PPMIn.isStable())
{
if ( g_channels[0] > 1500 )
{
// turn led on.
}
else
{
// turn led off.
}
}
}
That should at least give you some idea which piece of code doesn't work as expected.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2014-11-12
So I went through and did the suggested testing. And it fails both to write the hardcoded values from the first posted test you gave, and fails to light the led for a stable ppm signal (at least that's what I assume the test is for)
I got rid of my wireless reciever, transmitter pair, and just used a cross over wire from the PPM signal being generated on the first pro mini 5v 328p to the second, meant to act as the receiver. When I did a simple serial monitor test on the second one to check what the incoming stream looked like, I got a bunch of ones and zeros whose pattern would change as I moved the joystick around on the transmitter pro mini. So I assume that means that I am in fact generating a PPM signal.
I verified my servos work, that I have them properly wired, both according to the suggested pinout in your ServoOut sketch, and by running them through an independent live test with a previous virtual wire library based sketch.
So it seems that I am either not generating the appropriate PPM signal. Which I am simply using the PPMOut example exactly how it is, and also modified for my 2 channel setup.
So it seems more likely and issue on the PPMin/ServoOut side. I am using this as my code on the receiver side:
~~~~~~~~~~~~~
include <PPMIn.h>
include <ServoOut.h>
include <Timer1.h>
define CHANNELS 2
define SERVOS 2
uint16_t g_channels[CHANNELS]; // output buffer for PPMIn
uint8_t g_workIn[PPMIN_WORK_SIZE(CHANNELS)]; // we need to have a work buffer for the PPMIn class
uint8_t g_pinsOut[SERVOS] = {2, 3}; // Output pins
uint16_t g_servos[SERVOS]; // Input buffer for servoOut, microseconds
uint8_t g_workOut[SERVOOUT_WORK_SIZE(SERVOS)]; // we need to have a work buffer for the ServoOut class
void setup()
{
// Initialize timer1, this is required for all features that use Timer1
// (PPMIn/PPMOut/ServoIn/ServoOut)
rc::Timer1::init();
// We use pin 8 as PPM input pin
pinMode(8, INPUT);
// We use pin change interrupts to detect changes in the signal
// If you're unfamiliar with how this works, please look up some
// article or tutorial on the subject.
// only allow pin change interrupts for PB0 (digital pin 8)
PCMSK0 = (1 << PCINT0);
// enable pin change interrupt 0
PCICR = (1 << PCIE0);
// set up the output pins
for (uint8_t i = 0; i < SERVOS; ++i)
{
pinMode(g_pinsOut[i], OUTPUT);
// put them low
digitalWrite(g_pinsOut[i], LOW);
// fill servo output buffer (input for ServoOut)
g_servos[i] = 1000;
}
// start listening
g_PPMIn.start();
// start outputting
g_ServoOut.start();
if (g_PPMIn.isStable())
{
// do magic, incoming values available in g_channels in microseconds.
// update the input buffer
for (uint8_t i = 0; i < SERVOS; ++i)
{
// fill ServoOut input buffer directly from PPMIn
g_servos[i] = g_channels[i];
}
// tell ServoOut there are new values available in its input buffer
g_ServoOut.update();
}
}
I am using this on the Transmitter side to generate the PPM.
/ --------------------------------------------------------------------------- This software is in the public domain, furnished "as is", without technical support, and with no warranty, express or implied, as to its usefulness for any purpose.
ppmout_example.pde Demonstrate Pulse Position Modulation Output functionality Author: Daniel van den Ouden Project: ArduinoRCLib Website: http://sourceforge.net/p/arduinorclib/ -------------------------------------------------------------------------/
include <PPMOut.h>
include <Timer1.h>
define CHANNELS 2
uint8_t g_pins[CHANNELS] = {A0, A1}; // Input pins
uint16_t g_input[CHANNELS]; // Input buffer in microseconds
uint8_t g_work[PPMOUT_WORK_SIZE(CHANNELS)]; // we need to have a work buffer for the PPMOut class
// PPMOut requires two buffers:
// Input buffer containing input samples in microseconds
// Work buffer of ((channels + 1) * 2) elements for internal calculations and frame buffering
// This setup removes any limit on the number of channels you want, and makes sure the library doesn't use more
// memory than it really needs, since the client code supplies the buffers.
rc::PPMOut g_PPMOut(CHANNELS, g_input, g_work, CHANNELS);
void setup()
{
// Initialize timer1, this is required for all features that use Timer1
// (PPMIn/PPMOut/ServoIn/ServoOut)
rc::Timer1::init();
for (uint8_t i = 0; i < CHANNELS; ++i)
{
// set up input pins
pinMode(g_pins[i], INPUT);
// fill input buffer, convert raw values to microseconds
g_input[i] = map(analogRead(g_pins[i]), 0, 1024, 1000, 2000);
}
// initialize PPMOut with some settings
g_PPMOut.setPulseLength(448); // pulse length in microseconds
g_PPMOut.setPauseLength(10448); // length of pause after last channel in microseconds
// note: this is also called the end of frame, or start of frame, and is usually around 10ms
// start PPMOut, use pin 9 (pins 9 and 10 are preferred)
g_PPMOut.start(10);
}
void loop()
{
// update the input buffer
for (uint8_t i = 0; i < CHANNELS; ++i)
{
// fill input buffer, convert raw values to microseconds
g_input[i] = map(analogRead(g_pins[i]), 0, 1024, 1000, 2000);
}
// tell PPMOut there are new values available in the input buffer
g_PPMOut.update();
}
~~~~~~~~~~
Any help you care to give is greatly appreciated.
Thanks,
Andrew
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Arduino pin 8 on the Atmega328 (uno/nano) corresponds with PB0 (port B, bit 0). Hence the pin B and (1 << 0) bits of code. This interrupt handler is called whenever pin 8 changes. Without it, the PPMIn code would never receive any notifications that the input pin has changed, and thus would never receive a signal.
I'll see if I can test your code tonight. I just received a new Nano yesterday after I blew up my old one, so I should be able to test it :)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2014-11-12
Thanks so much.
Not missing, just my novice hardware programming/understanding. Of course now that you explain it, it's "oh yeah, totally makes sense." but i'm not sure I would have ever come to the conclusion on my own. Well not at least for a few more weeks of starring at it...
I'll also muck around with it a bit more today and see what I come up with. It's become a matter of principal now to get this working, one of those projects you can't let go regardless the amount of time.
Thanks
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2014-11-12
So my initial testing of adding the interrupt handler is that I still had no movement on the servos.
I stumbled upon this piece of code in a forum somewhere that measures the different time values of an incoming PPM signal. So I ran some tests on the receiver pro mini (328p based) by uploading the code below to it, and recording the different results for the various joystick movements on the Transmitter/PPM generation side. Again using a simple crossover wire for the transmit method from one pro-mini to the next.
The results from the serial monitor (I summarized them with the min max values, you can see the full results in the attached file.
Joystick Center: min/max per channel: 592/659 839/922 frameLength: 4204
Joystick Left: min/max per channel: 439/922 443/923 frameLength: 3660
Joystick Right: min/max per channel: 595/1352 594/1352 frameLength: 4704
Joystick Up: min/max per channel: 390/919 390/919 frameLength: 3440
Joystick Down: min/max per channel: 776/1352 775/1352 frameLength: 4868
pulseIn isn't incredibly accurate. It relies on the number of clockcycles between pin changes, any interrupt that occurs while monitoring for pin changes will throw the result off by at least a microsecond, if not more. The amount of interrupts will be fairly constant though, so the results will be fairly consistent, but not extremely accurate. Any jitter you see in the pulse lengths on the actual channels may also be due to the analogIn on the transmitter side; those readings are hardly ever stable.
The difference in frame length for left/right/up/down movement is because RC PPM signals do not have a fixed frame width. Longer pulses on the channels will increase the total frame width, shorter pulses will decrease it. Some "real" transmitters work like this, others don't (and use a fixed frame width/variable start of frame pulse).
But the frame length is way to small. If the transmitter code you posted earlier is what you used to get the results in the attachment then the frame length should be way larger. It should be somewhere between 12000 and 15000. The synclength (3rd number) also should be consistently around 10K. The other two numbers should be between 500 and 1500.
#define minsync 300
That should've been at least 3000. With a length of 300 microseconds the code will not be able to differentiate between channels data and the start/end frame marker.
I just loaded the PPMOut example to an Arduino Mega (slightly modified to make it work on that board) with 4 channels and a constant 1500 uS value per channel. I connected that to and Arduino Nano with a slightly modified PPMIn example to output the incoming values on serial port:
As you can see, the channel values are pretty solid (you need to add 448, the pause width, to get the actual value, about 1496). But you can see the frame length decreasing. I can also see this happening on the transmitting arduino since I'm outputting the PPM signal on pin 13 (LED) and I can see the LED dimming slightly in about two seconds and then go full brightness again.
I also see this happening when I run it on the Arduino Nano if I run the PPMOut code on there. So I guess that's definitely a bug :(
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2014-11-13
So I made the suggested changes to the library files, and got a stable stream that allowed me to control my servo on pin 2 of the Atmega 328. However for whatever reason the other channel is either not getting through, or some other conflict is occurring, because I get no joy trying to control the servo on pin 3. I can verify that both servos are properly powered with an external supply, have filter caps, etc. When I switch the signal wires on the servos I can verify again that any servo hooked to pin 2 will work just fine. But 0 control whatsoever of anything on pin 3.
I even Switched the servoOut pins to 4 and 5 and then I just got no control at all.
Seems like a port conflict I am guessing. I'll try and see if I get more luck from other pins. But when I looked at the port pinout I saw no reason why 3, 4, and 5 should not work.
In either case it was wonderful to see some movement. Even tested via my 433 TX , RX unit and again the signal for pin 2 at least worked like a charm.
I'll keep you posted if I discover anything else interesting.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2014-11-13
So I have discovered that for whatever reason there is a port conflict with using d3, d4, or d5... When i switched the servoOut pin to D10, I had full reliable control of both servos. So beautiful to see the wonders of PPM control that allows for beautifully smooth control methods compared to the ultra clunky virtual wire library...
Soon I ought to have a full pan tilt emote control security camera in place. Yay! Thanks for all the help! Love this library!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hallo,
I want to test a PPM signal.
Do you have an example PPM-in to 4 Servos out.
Please excuse my english.
thanks Bernd
First of all, sorry for the late reply!
Here's a quick writeup of what you're looking for, I haven't tested it (haven't even compiled it) so I'm not sure it works, but it should give you a fairly good hint in the right direction.
What you basically want is tie PPM-input directly to Servo Out
Hi!
I stumbled upon your library a few hours ago, since I'm trying to send a PPM signal from a transmitter to a receiver and to feed 3 servos. I used the example you gave (on top of my comment to servo pinOut 4), but the outcome was a very fast non-stop throwing up-and-down of just one of the servos (i think). I tried to move it with the joystick from the receiver side, but it barely changed the outcome, it didn't stop with the fast throttling up-and-down.
What do you think is the problem, how can i fix it ?
PS:I'm just starting to use and learn about microcontrollers, PPM, PWM and C++, I know that's one of the problems :)
Regards, George
Hi George,
Try using one servo first, if that works fine then the servos are probably causing a lot of noise on the power lines. I've seen this happen using some cheap micro servos. The moment the one of the servos starts moving it will draw quite some current and this is interfering with the servo signals. You can fix this by adding a small electrolytic capacitor between the power and ground lines of the servos. Most receivers I've seen also have an electrolytic cap for this purpose.
Hi!
I tried your advice, to use one servo only but it's not moving at all now.
Maybe I didn't understand your lib since I don't know C++ (I'm a Java developer).
What I'm trying to do is make a robotic hand controlled by joysticks and a microcontroller sending PPM transmit signal to a transmitter, and the transmitter to send the signal to another microcontroller. And the controller to decode the PPM and feed the servos with it.
If You can spend the time to look through what I'm uploading on both sides, and maybe tell me what I'm doing wrong, this will be of great help for me !
Regards, George
Transmitter and Joystick side:
Receiver and Servos side:
Your code looks okay at first glance. How did you wire your hardware? What kind of transmitter and receiver are you using? Depending on the type of hardware you may have to set the number of channels to match the number of channels on the RX/TX. My Esky TX/RX combo for example always expects a 6 channel PPM signal, even if I only want to use just three channels.
But anyway, if all you want to do at the receiving side is control a bunch of servo's and you already have an RC receiver, then you might as well just hook the servos directly to the RX, no need to add an extra microcontroller, unless you want to do all sorts of post processing :)
I too am looking to control some servos wirelessly. Here's my setup.
Transmit side: Atmega 328p Arduino Pro Mini 5v. Uses the PPM_OUT to generate a 2 channel PPM signal that is transmitted via a 433mhz rf transmitter directly connected to the ppm output pin as designated by your suggested PPM_out example in your library.
Receive side: Atmega 328p Arduino Pro Mini 5v. Taking the TX ppm input from a 433mhz receiver. Than it should generate appropriate servo signal, and push it out to the two servo's.
When I use the above code I get no servo movement whatsoever. I can see my led blinking on the TX side, and seems that a PPM signal is being transmitted, and received. Some guidance here would be much appreciated.
This is the first in a series of RC projects I am looking to do with increasing number of channels. But first wanted to start with something simple.
Hi,
I suggest you test the two parts on the RX side (PPMIn and ServoOut) individually to narrow down the cause of the problem.
Verify that you actually receive what you transmit, for example by lighting up the on board LED when a channel has a specific value, or when it's value is below or above a certain threshold.
Verify that the servos can actually be controlled by hardcoding the values in g_servos to various values. You can "animate" them by incrementing the value in the loop function and making the code sleep for a dozen milliseconds.
so something like this
If that works properly, then at least the servo control works fine.
As for the RX testing:
and
That should at least give you some idea which piece of code doesn't work as expected.
So I went through and did the suggested testing. And it fails both to write the hardcoded values from the first posted test you gave, and fails to light the led for a stable ppm signal (at least that's what I assume the test is for)
I got rid of my wireless reciever, transmitter pair, and just used a cross over wire from the PPM signal being generated on the first pro mini 5v 328p to the second, meant to act as the receiver. When I did a simple serial monitor test on the second one to check what the incoming stream looked like, I got a bunch of ones and zeros whose pattern would change as I moved the joystick around on the transmitter pro mini. So I assume that means that I am in fact generating a PPM signal.
I verified my servos work, that I have them properly wired, both according to the suggested pinout in your ServoOut sketch, and by running them through an independent live test with a previous virtual wire library based sketch.
So it seems that I am either not generating the appropriate PPM signal. Which I am simply using the PPMOut example exactly how it is, and also modified for my 2 channel setup.
So it seems more likely and issue on the PPMin/ServoOut side. I am using this as my code on the receiver side:
~~~~~~~~~~~~~
include <PPMIn.h>
include <ServoOut.h>
include <Timer1.h>
define CHANNELS 2
define SERVOS 2
uint16_t g_channels[CHANNELS]; // output buffer for PPMIn
uint8_t g_workIn[PPMIN_WORK_SIZE(CHANNELS)]; // we need to have a work buffer for the PPMIn class
rc::PPMIn g_PPMIn(g_channels, g_workIn, CHANNELS);
uint8_t g_pinsOut[SERVOS] = {2, 3}; // Output pins
uint16_t g_servos[SERVOS]; // Input buffer for servoOut, microseconds
uint8_t g_workOut[SERVOOUT_WORK_SIZE(SERVOS)]; // we need to have a work buffer for the ServoOut class
rc::ServoOut g_ServoOut(g_pinsOut, g_servos, g_workOut, SERVOS);
void setup()
{
// Initialize timer1, this is required for all features that use Timer1
// (PPMIn/PPMOut/ServoIn/ServoOut)
rc::Timer1::init();
}
void loop()
{
// update incoming values
g_PPMIn.update();
}
/ ---------------------------------------------------------------------------
This software is in the public domain, furnished "as is", without technical
support, and with no warranty, express or implied, as to its usefulness for
any purpose.
ppmout_example.pde
Demonstrate Pulse Position Modulation Output functionality
Author: Daniel van den Ouden
Project: ArduinoRCLib
Website: http://sourceforge.net/p/arduinorclib/
-------------------------------------------------------------------------/
include <PPMOut.h>
include <Timer1.h>
define CHANNELS 2
uint8_t g_pins[CHANNELS] = {A0, A1}; // Input pins
uint16_t g_input[CHANNELS]; // Input buffer in microseconds
uint8_t g_work[PPMOUT_WORK_SIZE(CHANNELS)]; // we need to have a work buffer for the PPMOut class
// PPMOut requires two buffers:
// Input buffer containing input samples in microseconds
// Work buffer of ((channels + 1) * 2) elements for internal calculations and frame buffering
// This setup removes any limit on the number of channels you want, and makes sure the library doesn't use more
// memory than it really needs, since the client code supplies the buffers.
rc::PPMOut g_PPMOut(CHANNELS, g_input, g_work, CHANNELS);
void setup()
{
// Initialize timer1, this is required for all features that use Timer1
// (PPMIn/PPMOut/ServoIn/ServoOut)
rc::Timer1::init();
}
void loop()
{
// update the input buffer
for (uint8_t i = 0; i < CHANNELS; ++i)
{
// fill input buffer, convert raw values to microseconds
g_input[i] = map(analogRead(g_pins[i]), 0, 1024, 1000, 2000);
}
}
~~~~~~~~~~
Any help you care to give is greatly appreciated.
Thanks,
Andrew
I'm missing the pin change interrupt handler in your receiver side code:
Arduino pin 8 on the Atmega328 (uno/nano) corresponds with PB0 (port B, bit 0). Hence the pin B and (1 << 0) bits of code. This interrupt handler is called whenever pin 8 changes. Without it, the PPMIn code would never receive any notifications that the input pin has changed, and thus would never receive a signal.
I'll see if I can test your code tonight. I just received a new Nano yesterday after I blew up my old one, so I should be able to test it :)
Thanks so much.
Not missing, just my novice hardware programming/understanding. Of course now that you explain it, it's "oh yeah, totally makes sense." but i'm not sure I would have ever come to the conclusion on my own. Well not at least for a few more weeks of starring at it...
I'll also muck around with it a bit more today and see what I come up with. It's become a matter of principal now to get this working, one of those projects you can't let go regardless the amount of time.
Thanks
You're welcome :)
So my initial testing of adding the interrupt handler is that I still had no movement on the servos.
I stumbled upon this piece of code in a forum somewhere that measures the different time values of an incoming PPM signal. So I ran some tests on the receiver pro mini (328p based) by uploading the code below to it, and recording the different results for the various joystick movements on the Transmitter/PPM generation side. Again using a simple crossover wire for the transmit method from one pro-mini to the next.
The results from the serial monitor (I summarized them with the min max values, you can see the full results in the attached file.
The PPM timing test code:
pulseIn isn't incredibly accurate. It relies on the number of clockcycles between pin changes, any interrupt that occurs while monitoring for pin changes will throw the result off by at least a microsecond, if not more. The amount of interrupts will be fairly constant though, so the results will be fairly consistent, but not extremely accurate. Any jitter you see in the pulse lengths on the actual channels may also be due to the analogIn on the transmitter side; those readings are hardly ever stable.
The difference in frame length for left/right/up/down movement is because RC PPM signals do not have a fixed frame width. Longer pulses on the channels will increase the total frame width, shorter pulses will decrease it. Some "real" transmitters work like this, others don't (and use a fixed frame width/variable start of frame pulse).
But the frame length is way to small. If the transmitter code you posted earlier is what you used to get the results in the attachment then the frame length should be way larger. It should be somewhere between 12000 and 15000. The synclength (3rd number) also should be consistently around 10K. The other two numbers should be between 500 and 1500.
That should've been at least 3000. With a length of 300 microseconds the code will not be able to differentiate between channels data and the start/end frame marker.
See https://sourceforge.net/p/arduinorclib/wiki/PPM%20Signal/
Check out this video for PPM in action: https://www.youtube.com/watch?v=-ufBy22aJQA
I just loaded the PPMOut example to an Arduino Mega (slightly modified to make it work on that board) with 4 channels and a constant 1500 uS value per channel. I connected that to and Arduino Nano with a slightly modified PPMIn example to output the incoming values on serial port:
That looks fairly solid.
I then ran the PPM testing code you posted (with minsync = 3000, channelnumber = 4) and the result were weird. Here's an excerpt:
As you can see, the channel values are pretty solid (you need to add 448, the pause width, to get the actual value, about 1496). But you can see the frame length decreasing. I can also see this happening on the transmitting arduino since I'm outputting the PPM signal on pin 13 (LED) and I can see the LED dimming slightly in about two seconds and then go full brightness again.
I also see this happening when I run it on the Arduino Nano if I run the PPMOut code on there. So I guess that's definitely a bug :(
and oh crap
https://sourceforge.net/p/arduinorclib/tickets/57/
That's it
In PPMOut.h, replace the define of PPM_OUT_WORK_SIZE with this:
In PPMOut.cpp, add a comma to the first line of this snippet and add the following two lines after it:
Now it should be stable...
I should've patched this a long time ago...
So I made the suggested changes to the library files, and got a stable stream that allowed me to control my servo on pin 2 of the Atmega 328. However for whatever reason the other channel is either not getting through, or some other conflict is occurring, because I get no joy trying to control the servo on pin 3. I can verify that both servos are properly powered with an external supply, have filter caps, etc. When I switch the signal wires on the servos I can verify again that any servo hooked to pin 2 will work just fine. But 0 control whatsoever of anything on pin 3.
I even Switched the servoOut pins to 4 and 5 and then I just got no control at all.
Seems like a port conflict I am guessing. I'll try and see if I get more luck from other pins. But when I looked at the port pinout I saw no reason why 3, 4, and 5 should not work.
In either case it was wonderful to see some movement. Even tested via my 433 TX , RX unit and again the signal for pin 2 at least worked like a charm.
I'll keep you posted if I discover anything else interesting.
So I have discovered that for whatever reason there is a port conflict with using d3, d4, or d5... When i switched the servoOut pin to D10, I had full reliable control of both servos. So beautiful to see the wonders of PPM control that allows for beautifully smooth control methods compared to the ultra clunky virtual wire library...
Soon I ought to have a full pan tilt emote control security camera in place. Yay! Thanks for all the help! Love this library!
Awesome, good to hear that it's working now and glad to be of help!
It's weird that pins 2-3 weren't working. That used to work fine: https://www.youtube.com/watch?v=wCi2PpY_LIs
Pins 0-7 are all on hardware port D, pins 8-13 are on port B, maybe there's some issues in the ServoOut code after all...
D2 worked fine, just not D3, D$, or D5. But yeah, you get the idea. Perhaps it's an Atmega 328p thing.