hi,
thanks for your work about this RC lib. i am trying to control pan-tilt cam on my rc rover with wiiMplus (trying to make a headtracker basically). i am reading wiiMPlus and can control 2 servos for pan-tilt. now i am trying to integrate my T9X transmitter and send mixed PPMout signals to the trainer port of my tx using your RC Lib. here is my code:
#include<PPMOut.h>#include<Timer1.h>#include<Streaming.h>#include<Wire.h>//#include <Servo.h>//Servo yawServo;//Servo pitchServo;#define CHANNELS 2//uint8_t g_pins[CHANNELS] = {A0, A1, A2, A3}; // Input pinsuint16_tg_input[CHANNELS];// Input buffer in microsecondsuint8_tg_work[PPMOUT_WORK_SIZE(CHANNELS)];// we need to have a work buffer for the PPMOut classrc::PPMOutg_PPMOut(CHANNELS,g_input,g_work,CHANNELS);intyawServoVal;intpitchServoVal;#define steps_per_deg_slow 20#define steps_per_deg_fast 4bytedata[6];//six data bytesintyaw,pitch,roll;//three axesintyaw0,pitch0,roll0;//calibration zeroesinttime,last_time;floatdelta_t;intlast_yaw[3],last_pitch[3],last_roll[3];floatyaw_deg,pitch_deg,roll_deg;intyaw_deg2,pitch_deg2,roll_deg2;intstartTag=0xDEAD;intaccel_x_axis,accel_y_axis,accel_z_axis;voidwmpOn(){Wire.beginTransmission(0x53);//WM+ starts out deactivated at address 0x53Wire.write(0xfe);//send 0x04 to address 0xFE to activate WM+Wire.write(0x04);Wire.endTransmission();//WM+ jumps to address 0x52 and is now active}voidwmpSendZero(){Wire.beginTransmission(0x52);//now at address 0x52Wire.write(0x00);//send zero to signal we want infoWire.endTransmission();}voidcalibrateZeroes(){for(inti=0;i<10;i++){wmpSendZero();Wire.requestFrom(0x52,6);for(inti=0;i<6;i++){data[i]=Wire.read();}yaw0+=(((data[3]>>2)<<8)+data[0])/10;//average 10 readings for each zeropitch0+=(((data[4]>>2)<<8)+data[1])/10;roll0+=(((data[5]>>2)<<8)+data[2])/10;}Serial.print("Yaw0:");Serial.print(yaw0);Serial.print(" Pitch0:");Serial.print(pitch0);Serial.print(" Roll0:");Serial.println(roll0);}voidreceiveData(){wmpSendZero();//send zero before each request (same as nunchuck)Wire.requestFrom(0x52,6);//request the six bytes from the WM+for(inti=0;i<6;i++){data[i]=Wire.read();}if(bitRead(data[3],1)==1)yaw=(((data[3]>>2)<<8)+data[0]-yaw0)/steps_per_deg_slow;//see http://wiibrew.org/wiki/Wiimote/Extension_Controllers#Wii_Motion_Pluselseyaw=(((data[3]>>2)<<8)+data[0]-yaw0)/steps_per_deg_fast;if(bitRead(data[3],0)==1)pitch=(((data[4]>>2)<<8)+data[1]-pitch0)/steps_per_deg_slow;//for info on what each byte representselsepitch=(((data[4]>>2)<<8)+data[1]-pitch0)/steps_per_deg_fast;if(bitRead(data[4],1)==1)roll=(((data[5]>>2)<<8)+data[2]-roll0)/steps_per_deg_slow;elseroll=(((data[5]>>2)<<8)+data[2]-roll0)/steps_per_deg_fast;}floattrapIntegrate(inty2,inty1,floatdeltax){floatarea=0;area=(y2+y1)/2*deltax/1000;returnarea;}floatrk4Integrate(inty4,inty3,inty2,inty1,floatdeltax){floatarea=0;area=((y4+2*y3+2*y2+y1)/6)*deltax/1000;returnarea;}voidsetup(){Serial.begin(57600);Serial.println("WM+ Tuning");Wire.begin();wmpOn();//turn WM+ oncalibrateZeroes();//calibrate zeroesdelay(1000);//yawServo.attach(8);//pitchServo.attach(9);pinMode(4,INPUT);// Initialize timer1, this is required for all features that use Timer1// (PPMIn/PPMOut/ServoIn/ServoOut) rc::Timer1::init();// fill input buffer, convert raw values to microsecondsg_input[1]=map(yawServoVal,0,179,1000,2000);g_input[2]=map(pitchServoVal,0,179,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(){receiveData();//receive data and calculate yaw pitch and rolltime=millis();delta_t=(time-last_time);/* Runge-kutta 4th Order Integration */yaw_deg+=rk4Integrate(yaw,last_yaw[0],last_yaw[1],last_yaw[2],delta_t);pitch_deg+=rk4Integrate(pitch,last_pitch[0],last_pitch[1],last_pitch[2],delta_t);roll_deg+=rk4Integrate(roll,last_roll[0],last_roll[1],last_roll[2],delta_t);last_yaw[2]=last_yaw[1];last_pitch[2]=last_pitch[1];last_roll[2]=last_roll[1];last_yaw[1]=last_yaw[0];last_pitch[1]=last_pitch[0];last_roll[1]=last_roll[0];last_yaw[0]=yaw;last_pitch[0]=pitch;last_roll[0]=roll;last_time=time;/* Runge-kutta 4th Order Integration */if(digitalRead(4)==1){last_yaw[2]=0;last_pitch[2]=0;last_roll[2]=0;last_yaw[1]=0;last_pitch[1]=0;last_roll[1]=0;last_yaw[0]=0;last_pitch[0]=0;last_roll[0]=0;yaw=0;pitch=0;roll=0;yaw_deg=0;pitch_deg=0;roll_deg=0;}yawServoVal=map(yaw_deg,-90,90,0,179);if(yawServoVal<0){yawServoVal=0;};if(yawServoVal>179){yawServoVal=179;};//yawServo.write(yawServoVal);//delay(10);pitchServoVal=map(roll_deg,-90,90,0,179);if(pitchServoVal<0){pitchServoVal=0;};if(pitchServoVal>179){pitchServoVal=179;};//pitchServo.write(pitchServoVal);//delay(10);g_input[1]=map(yawServoVal,0,179,1000,2000);g_input[2]=map(pitchServoVal,0,179,1000,2000);g_PPMOut.update();// tell PPMOut there are new values available in the input bufferSerial.print("Yaw:");Serial.print(yawServoVal);Serial.print(" Pitch:");Serial.print(pitchServoVal);Serial.print(" Roll:");Serial.println(roll_deg);delay(10);}
i am not a master on neither programming nor electronics, just an experienced hobbyist. i couldnt get the system working. on serial monitor i can see good pan-tilt angles but cant send ppm through tx. is there a way to see whether the code is creating valid ppm data? or is there something wrong with my code... this old hobbyist is awaiting help... :)
Dincer
Last edit: dvdouden 2013-04-15
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Right now you're writing out of bounds (and probably directly into the work buffer of PPMOut.
There's also still a bug in PPMOut which needs fixing. I haven't had time to release a patch yet, but it's easy to fix by hand.
Open PPMOut.h (it's in the ArduinoRCLib directory) and find the line which says
You can slow down the PPM output by a factor 256. If you then attach an LED (with the right resistor) to pin 9 you should be able to actually see the PPM signal. Just don't forget to revert the timer1 init when you're done.
Last edit: dvdouden 2013-04-15
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2013-04-15
many thks for your assistance... this lib is really easy to use releiving us from burdens of many libes of code... i will make the changes you have pointed and try again... thks also for the tip you have given about monitoring the ppm out. it will be helpful because i dont have an osciloscope. i was just wondering about the timing of setPulseLenght and setPauseLenght for my particular tx which is Turnigy9x which is said to have a 22us gap btw ppm pulses... thks again and i will post results here... hoping to be helpful for others...
Dincer
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
My experience with PPM is that most transmitters/receivers aren't particularly picky about pulse and pause lengths. It's the time between the start of two pulses that actually matters, not the length of the pulse. See also: https://sourceforge.net/p/arduinorclib/wiki/PPM%20Signal/
I'm not familiar with the Turnigy 9X though...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2013-04-15
changed the g_input() lines as you said to 0,1 and changed the #define line in ppmout.h but still no luck... :( cant utilize the ppmout to my tx trainer port. i am using 2 aux channels on my tx for pan-tilt servos, i can move them with two knobs on my tx at trainer mode. but cant move them with ppm which i send from trainer port... serial monitor shows perfect control with wiimplus but cant pass to tx... :(
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2013-04-15
i will now try to monitor pin9 for ppmout using the led trick you have mentioned but i dont think there is a bad connection. i am frustrated with this project... :( maybe i should revert to a dedicated imu like, gy-85 9dof and a arduino nano328...
dincer
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
One possible reason could be that the transmitter expects at least 4 or 6 channels instead of two. You could try increasing CHANNELS and initializing all channels to 1500 in the setup function.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2013-04-15
i dont think that can help.. i am customizing trainer input and restricting to 2 channells i want in the trainer menu of my tx. i will try your point anyway.. 'initializing all channels to 1500 in the setup function.' what you mean by that? sorry i didnt understand, do you mean making values in g-input() statements 1500?
thks for your help and patience and understanding this 56yr old hobbyist... :)
dincer
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It's just as you think. Set CHANNELS to 6 and add the following to the setup function:
for (uint8_t i = 0; i < CHANNELS; ++i)
{
if (i == 2)
g_input[i] = 2000; // throttle channel
else
g_input[i] = 1500;
}
and make sure you disconnect any motor you have on channel 3, just to be safe ;)
The TX is usually expecting a full 4, 6 or 9 channel signal on the trainer port. Its firmware will filter out any channels you've disabled, but it'll still expect the other channels as input. At least that's how it works on a Futaba radio.
And no problem, glad to be of help :)
Last edit: dvdouden 2013-04-15
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2013-04-15
thank you i will try that... but T9X is a 9ch radio, indeed 8 ch on ppm. then i must set CHANNELS to 8 and set them 1500 except throttle ch. which will be 2000... but still dont understand why we are setting all channels to 1500? where will be our g_input servoVAL values?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Because 1500 (microseconds, or 1.5 milliseconds) is the center value for a channel (servo center). We need to set them because by default it will be initialized to 0, and 0 microseconds is not a valid channel value.
For Futaba (and a lot of other brands) the channels are mapped like this:
CH1 (g_input[0]) = aileron
CH2 (g_input[1]) = elevator
CH3 (g_input[2]) = throttle
CH4 (g_input[3]) = rudder
CH5 (g_input[4]) = gyro/gear
CH6 (g_input[5]) = pitch/flaps
CH7 (g_input[6]) = AUX1
CH8 (g_input[7]) = AUX2
CH9 (g_input[8]) = AUX3
I've just looked it up in a manual for the Turnigy 9X, and it seems to use the same channel mapping.
g_input contains the values for each channel, and PPMOut uses those values to generate a PPM signal containing those values. So by setting CHANNELS to 8, it will generate an 8 channel PPM signal using the values it finds in g_input. Of course you will need to specify values that make sense, that's why we set all channels to 1500. Throttle is set to 2000 since the throttle channel is usually inverted, so that means 0 throttle (1000 would be full throttle).
In the loop function you overwrite the values for the channels you want to use (in this case we've mapped yaw to channel 1 (g_input[0]) and pitch to channel 2 (g_input[1]), if you want to put them on AUX 1 and 2 you'll have to use g_input[6] and g_input[7]. After you've set the channel values you can tell g_PPMOut that new values are available in g_input by calling update, this will cause PPMOut to read all the channel values and start generating a PPM signal from those values.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2013-04-15
No way... :( it didnt work that way either... this is the last version of the code after i made changes for a complete 8ch ppmout build up:
#include<PPMOut.h>#include<Timer1.h>#include<Streaming.h>#include<Wire.h>//#include <Servo.h>//Servo yawServo;//Servo pitchServo;#define CHANNELS 8//uint8_t g_pins[CHANNELS] = {A0, A1, A2, A3}; // Input pinsuint16_tg_input[CHANNELS];// Input buffer in microsecondsuint8_tg_work[PPMOUT_WORK_SIZE(CHANNELS)];// we need to have a work buffer for the PPMOut classrc::PPMOutg_PPMOut(CHANNELS,g_input,g_work,CHANNELS);intyawServoVal;intpitchServoVal;#define steps_per_deg_slow 20#define steps_per_deg_fast 4bytedata[6];//six data bytesintyaw,pitch,roll;//three axesintyaw0,pitch0,roll0;//calibration zeroesinttime,last_time;floatdelta_t;intlast_yaw[3],last_pitch[3],last_roll[3];floatyaw_deg,pitch_deg,roll_deg;intyaw_deg2,pitch_deg2,roll_deg2;intstartTag=0xDEAD;intaccel_x_axis,accel_y_axis,accel_z_axis;voidwmpOn(){Wire.beginTransmission(0x53);//WM+ starts out deactivated at address 0x53Wire.write(0xfe);//send 0x04 to address 0xFE to activate WM+Wire.write(0x04);Wire.endTransmission();//WM+ jumps to address 0x52 and is now active}voidwmpSendZero(){Wire.beginTransmission(0x52);//now at address 0x52Wire.write(0x00);//send zero to signal we want infoWire.endTransmission();}voidcalibrateZeroes(){for(inti=0;i<10;i++){wmpSendZero();Wire.requestFrom(0x52,6);for(inti=0;i<6;i++){data[i]=Wire.read();}yaw0+=(((data[3]>>2)<<8)+data[0])/10;//average 10 readings for each zeropitch0+=(((data[4]>>2)<<8)+data[1])/10;roll0+=(((data[5]>>2)<<8)+data[2])/10;}Serial.print("Yaw0:");Serial.print(yaw0);Serial.print(" Pitch0:");Serial.print(pitch0);Serial.print(" Roll0:");Serial.println(roll0);}voidreceiveData(){wmpSendZero();//send zero before each request (same as nunchuck)Wire.requestFrom(0x52,6);//request the six bytes from the WM+for(inti=0;i<6;i++){data[i]=Wire.read();}if(bitRead(data[3],1)==1)yaw=(((data[3]>>2)<<8)+data[0]-yaw0)/steps_per_deg_slow;//see http://wiibrew.org/wiki/Wiimote/Extension_Controllers#Wii_Motion_Pluselseyaw=(((data[3]>>2)<<8)+data[0]-yaw0)/steps_per_deg_fast;if(bitRead(data[3],0)==1)pitch=(((data[4]>>2)<<8)+data[1]-pitch0)/steps_per_deg_slow;//for info on what each byte representselsepitch=(((data[4]>>2)<<8)+data[1]-pitch0)/steps_per_deg_fast;if(bitRead(data[4],1)==1)roll=(((data[5]>>2)<<8)+data[2]-roll0)/steps_per_deg_slow;elseroll=(((data[5]>>2)<<8)+data[2]-roll0)/steps_per_deg_fast;}floattrapIntegrate(inty2,inty1,floatdeltax){floatarea=0;area=(y2+y1)/2*deltax/1000;returnarea;}floatrk4Integrate(inty4,inty3,inty2,inty1,floatdeltax){floatarea=0;area=((y4+2*y3+2*y2+y1)/6)*deltax/1000;returnarea;}voidsetup(){Serial.begin(57600);Serial.println("WM+ Tuning");Wire.begin();wmpOn();//turn WM+ oncalibrateZeroes();//calibrate zeroesdelay(1000);//yawServo.attach(8);//pitchServo.attach(9);pinMode(4,INPUT);// Initialize timer1, this is required for all features that use Timer1// (PPMIn/PPMOut/ServoIn/ServoOut) rc::Timer1::init();// fill input buffer, convert raw values to microsecondsfor(uint8_ti=0;i<CHANNELS;++i){if(i==2)g_input[i]=2000;// throttle channelelseg_input[i]=1500;}// 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(){receiveData();//receive data and calculate yaw pitch and rolltime=millis();delta_t=(time-last_time);/* Runge-kutta 4th Order Integration */yaw_deg+=rk4Integrate(yaw,last_yaw[0],last_yaw[1],last_yaw[2],delta_t);pitch_deg+=rk4Integrate(pitch,last_pitch[0],last_pitch[1],last_pitch[2],delta_t);roll_deg+=rk4Integrate(roll,last_roll[0],last_roll[1],last_roll[2],delta_t);last_yaw[2]=last_yaw[1];last_pitch[2]=last_pitch[1];last_roll[2]=last_roll[1];last_yaw[1]=last_yaw[0];last_pitch[1]=last_pitch[0];last_roll[1]=last_roll[0];last_yaw[0]=yaw;last_pitch[0]=pitch;last_roll[0]=roll;last_time=time;/* Runge-kutta 4th Order Integration */if(digitalRead(4)==1){last_yaw[2]=0;last_pitch[2]=0;last_roll[2]=0;last_yaw[1]=0;last_pitch[1]=0;last_roll[1]=0;last_yaw[0]=0;last_pitch[0]=0;last_roll[0]=0;yaw=0;pitch=0;roll=0;yaw_deg=0;pitch_deg=0;roll_deg=0;}yawServoVal=map(yaw_deg,-90,90,0,179);if(yawServoVal<0){yawServoVal=0;};if(yawServoVal>179){yawServoVal=179;};//yawServo.write(yawServoVal);//delay(10);pitchServoVal=map(roll_deg,-90,90,0,179);if(pitchServoVal<0){pitchServoVal=0;};if(pitchServoVal>179){pitchServoVal=179;};//pitchServo.write(pitchServoVal);//delay(10);g_input[5]=map(yawServoVal,0,179,1000,2000);g_input[6]=map(pitchServoVal,0,179,1000,2000);g_PPMOut.update();// tell PPMOut there are new values available in the input bufferSerial.print("Yaw:");Serial.print(yawServoVal);Serial.print(" Pitch:");Serial.print(pitchServoVal);Serial.print(" Roll:");Serial.println(roll_deg);delay(10);}
unfortunately it didnt work... thank you for your help.. i really appreciated that... i think i will have to work on this a little bit by myself... i bothered you a lot... i will post this project to Arduino site if i succeed...
Dincer
Last edit: dvdouden 2013-04-15
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
You're welcome and sorry we couldn't get it to work. Which type of Arduino are you using by the way?
If I were you I'd start with testing whether PPMOut is outputting anything at all, use the timer1 debug mode and an LED on the PPMOut output pin. It should look something like this: http://www.youtube.com/watch?v=KikSzL0Yilo
I admit it's a bit difficult to debug without a scope though... I've also used a second Arduino with PPMIn to catch the signal and output its values.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2013-04-15
thank you again... i am planning to do that now.. i will somehow monitor ppmout at pin9... first i will try your led trick... monitoring pin9 using a second arduino may be a good choice too... i have various arduinos at hand, i love them... :) arduino duemillanove, boardino328, arduino uno, ardweeny, arduino nano and some other clones which i made (ardupilot boards etc)... the one i am using for this project is a Boardino328 (adafruit one)... as u may have noticed from the code i changed config of tx to ch6&ch7 because i plan to use ch8 for Ardupilot autupilot switching on/off later...
Dincer
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ah cool. I'm asking because I've only tested ArduinoRCLib on Atmega168/328 devices, so I'm not sure whether it works on a Mega or Leonardo (it's on my todo list).
Anyway, good luck, and feel free to ask any questions you have!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2013-04-15
did some research and found out something about + or - ppm population... which one are we creating here? while browsing RCGroups forums i found at Dennis Frie diy headtracker thread that turnigy9x uses - ppm population, like Futaba Jr atc, unlike Graupner... can this be my problem? are we creating -ppm population with this RClibrary?..
Dincer
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I think (can't remember exactly) that we're using negative PPM here, you can invert the signal by using a second parameter on the start function
g_PPMOut.start(9, true); // inverts the PPM signal
you could give that a try.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2013-04-16
i am happy to inform you that i managed my headtracker work last night after few hrs of mindstorming... i am also happy to inform you thatyour rc lib is working flawlessly... i was linking my tx to the HT from trainer port at first. later i realized that tx is not seeing the new ppm signal from there. i rewired the HT totally from inside and made a dedicated plug for the new ht and it worked... :) some points to mention though. your rc lib is creating -ppm which is fine for my T9X. the ppm must be a sum of full channels. mine is 8ch as we have done in the last version of the code. i.e populate all 8ch and then only update the necessarry 2ch... thks for your assistance... one thing i couldnt solve is the yaw and pitch is working reversed and i cant change them from tx. when i reverse the 2ch which im using nothing changes... :(
Dincer
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Glad to hear you got it working! I noticed the following:
pitchServoVal = map(roll_deg, -90, 90, 0, 179);
shouldn't that be roll_deg?
You could also clamp the source value first like this:
if (pitch_deg < -90){pitch_deg = -90;}
if (pitch_deg > 90){pitch_deg = 90;};
If you want to invert the channel you'd just to
pitch_deg = -pitch_deg;
and then map it directly to g_input
g_input[6] = map(pitch_deg, -90, 90, 1000, 2000);
Glad to be of help!
Last edit: dvdouden 2013-04-16
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2013-04-16
forgot to give you my mail address to you in case you want to contact me... want to hear about updates on RClib... thks again and wish u a nice day...
Dincer Hepguler
dhepguler@hotmail.com
Last edit: dvdouden 2013-04-16
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
You can also subscribe to the project (I think there's a button on the main project page). Then you'll automatically receive an e-mail when new updates are released.
Last edit: dvdouden 2013-04-16
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2013-04-16
thank you again for the reversing tip... will do that now...i didnt write the whole code but collected bits of code from various sources, adding some code by myself for my needs and compiled, the roll_deg variable is actually the pitch_deg... the programmer who wrote the wiiMplus reading routine established it wrong and i kept it like that, only swapped the axis for my needs...
dincer
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2013-04-16
unfortunately reversing by assigning -val to yaw and pitch didnt work... indeed headtracker stopped working... after few trials on the code i gave up and decided to use the wiiMplus rotated... :) i hold the wiiMplus reversed on power up (or reset) and the axes zero calibration remembers the position and it works on normal axes.. left is left, up is up etc... :)
Dincer
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
hi,
thanks for your work about this RC lib. i am trying to control pan-tilt cam on my rc rover with wiiMplus (trying to make a headtracker basically). i am reading wiiMPlus and can control 2 servos for pan-tilt. now i am trying to integrate my T9X transmitter and send mixed PPMout signals to the trainer port of my tx using your RC Lib. here is my code:
i am not a master on neither programming nor electronics, just an experienced hobbyist. i couldnt get the system working. on serial monitor i can see good pan-tilt angles but cant send ppm through tx. is there a way to see whether the code is creating valid ppm data? or is there something wrong with my code... this old hobbyist is awaiting help... :)
Dincer
Last edit: dvdouden 2013-04-15
Thanks for your interest in ArduinoRCLib! I can see at least one issue in your code:
should have been
Right now you're writing out of bounds (and probably directly into the work buffer of PPMOut.
There's also still a bug in PPMOut which needs fixing. I haven't had time to release a patch yet, but it's easy to fix by hand.
Open PPMOut.h (it's in the ArduinoRCLib directory) and find the line which says
replace it with
Then try again and see if it works :)
Good luck!
PS.
By initializing timer1 like this:
You can slow down the PPM output by a factor 256. If you then attach an LED (with the right resistor) to pin 9 you should be able to actually see the PPM signal. Just don't forget to revert the timer1 init when you're done.
Last edit: dvdouden 2013-04-15
many thks for your assistance... this lib is really easy to use releiving us from burdens of many libes of code... i will make the changes you have pointed and try again... thks also for the tip you have given about monitoring the ppm out. it will be helpful because i dont have an osciloscope. i was just wondering about the timing of setPulseLenght and setPauseLenght for my particular tx which is Turnigy9x which is said to have a 22us gap btw ppm pulses... thks again and i will post results here... hoping to be helpful for others...
Dincer
You're welcome!
My experience with PPM is that most transmitters/receivers aren't particularly picky about pulse and pause lengths. It's the time between the start of two pulses that actually matters, not the length of the pulse. See also: https://sourceforge.net/p/arduinorclib/wiki/PPM%20Signal/
I'm not familiar with the Turnigy 9X though...
changed the g_input() lines as you said to 0,1 and changed the #define line in ppmout.h but still no luck... :( cant utilize the ppmout to my tx trainer port. i am using 2 aux channels on my tx for pan-tilt servos, i can move them with two knobs on my tx at trainer mode. but cant move them with ppm which i send from trainer port... serial monitor shows perfect control with wiimplus but cant pass to tx... :(
i will now try to monitor pin9 for ppmout using the led trick you have mentioned but i dont think there is a bad connection. i am frustrated with this project... :( maybe i should revert to a dedicated imu like, gy-85 9dof and a arduino nano328...
dincer
One possible reason could be that the transmitter expects at least 4 or 6 channels instead of two. You could try increasing CHANNELS and initializing all channels to 1500 in the setup function.
i dont think that can help.. i am customizing trainer input and restricting to 2 channells i want in the trainer menu of my tx. i will try your point anyway.. 'initializing all channels to 1500 in the setup function.' what you mean by that? sorry i didnt understand, do you mean making values in g-input() statements 1500?
thks for your help and patience and understanding this 56yr old hobbyist... :)
dincer
It's just as you think. Set CHANNELS to 6 and add the following to the setup function:
and make sure you disconnect any motor you have on channel 3, just to be safe ;)
The TX is usually expecting a full 4, 6 or 9 channel signal on the trainer port. Its firmware will filter out any channels you've disabled, but it'll still expect the other channels as input. At least that's how it works on a Futaba radio.
And no problem, glad to be of help :)
Last edit: dvdouden 2013-04-15
thank you i will try that... but T9X is a 9ch radio, indeed 8 ch on ppm. then i must set CHANNELS to 8 and set them 1500 except throttle ch. which will be 2000... but still dont understand why we are setting all channels to 1500? where will be our g_input servoVAL values?
Because 1500 (microseconds, or 1.5 milliseconds) is the center value for a channel (servo center). We need to set them because by default it will be initialized to 0, and 0 microseconds is not a valid channel value.
For Futaba (and a lot of other brands) the channels are mapped like this:
CH1 (g_input[0]) = aileron
CH2 (g_input[1]) = elevator
CH3 (g_input[2]) = throttle
CH4 (g_input[3]) = rudder
CH5 (g_input[4]) = gyro/gear
CH6 (g_input[5]) = pitch/flaps
CH7 (g_input[6]) = AUX1
CH8 (g_input[7]) = AUX2
CH9 (g_input[8]) = AUX3
I've just looked it up in a manual for the Turnigy 9X, and it seems to use the same channel mapping.
g_input contains the values for each channel, and PPMOut uses those values to generate a PPM signal containing those values. So by setting CHANNELS to 8, it will generate an 8 channel PPM signal using the values it finds in g_input. Of course you will need to specify values that make sense, that's why we set all channels to 1500. Throttle is set to 2000 since the throttle channel is usually inverted, so that means 0 throttle (1000 would be full throttle).
In the loop function you overwrite the values for the channels you want to use (in this case we've mapped yaw to channel 1 (g_input[0]) and pitch to channel 2 (g_input[1]), if you want to put them on AUX 1 and 2 you'll have to use g_input[6] and g_input[7]. After you've set the channel values you can tell g_PPMOut that new values are available in g_input by calling update, this will cause PPMOut to read all the channel values and start generating a PPM signal from those values.
No way... :( it didnt work that way either... this is the last version of the code after i made changes for a complete 8ch ppmout build up:
unfortunately it didnt work... thank you for your help.. i really appreciated that... i think i will have to work on this a little bit by myself... i bothered you a lot... i will post this project to Arduino site if i succeed...
Dincer
Last edit: dvdouden 2013-04-15
You're welcome and sorry we couldn't get it to work. Which type of Arduino are you using by the way?
If I were you I'd start with testing whether PPMOut is outputting anything at all, use the timer1 debug mode and an LED on the PPMOut output pin. It should look something like this: http://www.youtube.com/watch?v=KikSzL0Yilo
I admit it's a bit difficult to debug without a scope though... I've also used a second Arduino with PPMIn to catch the signal and output its values.
thank you again... i am planning to do that now.. i will somehow monitor ppmout at pin9... first i will try your led trick... monitoring pin9 using a second arduino may be a good choice too... i have various arduinos at hand, i love them... :) arduino duemillanove, boardino328, arduino uno, ardweeny, arduino nano and some other clones which i made (ardupilot boards etc)... the one i am using for this project is a Boardino328 (adafruit one)... as u may have noticed from the code i changed config of tx to ch6&ch7 because i plan to use ch8 for Ardupilot autupilot switching on/off later...
Dincer
Ah cool. I'm asking because I've only tested ArduinoRCLib on Atmega168/328 devices, so I'm not sure whether it works on a Mega or Leonardo (it's on my todo list).
Anyway, good luck, and feel free to ask any questions you have!
did some research and found out something about + or - ppm population... which one are we creating here? while browsing RCGroups forums i found at Dennis Frie diy headtracker thread that turnigy9x uses - ppm population, like Futaba Jr atc, unlike Graupner... can this be my problem? are we creating -ppm population with this RClibrary?..
Dincer
I think (can't remember exactly) that we're using negative PPM here, you can invert the signal by using a second parameter on the start function
you could give that a try.
i am happy to inform you that i managed my headtracker work last night after few hrs of mindstorming... i am also happy to inform you thatyour rc lib is working flawlessly... i was linking my tx to the HT from trainer port at first. later i realized that tx is not seeing the new ppm signal from there. i rewired the HT totally from inside and made a dedicated plug for the new ht and it worked... :) some points to mention though. your rc lib is creating -ppm which is fine for my T9X. the ppm must be a sum of full channels. mine is 8ch as we have done in the last version of the code. i.e populate all 8ch and then only update the necessarry 2ch... thks for your assistance... one thing i couldnt solve is the yaw and pitch is working reversed and i cant change them from tx. when i reverse the 2ch which im using nothing changes... :(
Dincer
Glad to hear you got it working! I noticed the following:
shouldn't that be roll_deg?
You could also clamp the source value first like this:
If you want to invert the channel you'd just to
and then map it directly to g_input
Glad to be of help!
Last edit: dvdouden 2013-04-16
forgot to give you my mail address to you in case you want to contact me... want to hear about updates on RClib... thks again and wish u a nice day...
Dincer Hepguler
dhepguler@hotmail.com
Last edit: dvdouden 2013-04-16
You're welcome! And fixed that typo for ya ;)
You can also subscribe to the project (I think there's a button on the main project page). Then you'll automatically receive an e-mail when new updates are released.
Last edit: dvdouden 2013-04-16
thank you again for the reversing tip... will do that now...i didnt write the whole code but collected bits of code from various sources, adding some code by myself for my needs and compiled, the roll_deg variable is actually the pitch_deg... the programmer who wrote the wiiMplus reading routine established it wrong and i kept it like that, only swapped the axis for my needs...
dincer
unfortunately reversing by assigning -val to yaw and pitch didnt work... indeed headtracker stopped working... after few trials on the code i gave up and decided to use the wiiMplus rotated... :) i hold the wiiMplus reversed on power up (or reset) and the axes zero calibration remembers the position and it works on normal axes.. left is left, up is up etc... :)
Dincer