RC_Simulator.....By Jafar Qutteineh with mods to connect my Futaba 9C to \'RC Helicopter\' by http://www.alphamacsoftware.com/

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "usbhid.h"
00003 
00004 
00005 /* RC_Simulator.....By Jafar Qutteineh*/
00006 /* This program takes the PPM Singal(Pulse Position Modulation) from your RC transmitter
00007    and emulate it as a USB HID Joystick.
00008    Currently, program configured to accept Throttle, Rudder, Elevator, Ailerons and 
00009    2 buttons. It can be adjusted easily to read other channels as well.
00010    The current state of code is just a proof of concept. It's rough and not clean,
00011    once you understand how it work, customize to your like*/
00012    
00013 /*Credit goes to Phil Wright for USB HID code and to Shinichiro Oba Joystiq work*/
00014 
00015 /*Setup: Just connect the GND and PPM singal of your transmitter to the GND and P5 respectivly.*/
00016 
00017 /*How it works: 
00018     -P5 is configured as InturreptIn pin. whenever the PPM signal goes down Inturrept SignalFall() is fired.
00019     -SignalFall keep track of timing:
00020         a) If Pulse width is <300 uS it's most probably a glitch.
00021         b) If pulse width is >300 uS but less than < 2000 uS this is a correct channel. Read it and wait for next channel
00022         c) If Pulse width is >8000 uS this is a new frame, start again.
00023         d) Timing will be different from transmitter to another, you may want to play a little bit here
00024     -Once a complete frame is read the values are feedback to our USB HID Joysick class.
00025 */   
00026    
00027 
00028 
00029 InterruptIn PPMsignal(p5); // connect PPM signal to this, you can change to anyother pin
00030 Serial PC(USBTX,USBRX);   // I used this for debuging
00031 USBJoystick joystick;     /* This is basicly Shinichiro joystiq, I've only adjusted the Report descriptor to my needs.   
00032                               for more help on this check:
00033                               -http://frank.circleofcurrent.com/cache/hid_tutorial_1.htm
00034                               -http://helmpcb.com/electronics/usb-joystick */
00035                               
00036 
00037 int TimeElapsed =0; //Keeps track of time between inturrepts
00038 Timer timer;        
00039 unsigned char CurChannel=0; //This will point to the current channel in PPM frame. My PPM signal looks like 10 channels and 1 start frame
00040                             // yours could be different
00041 unsigned char Channels[11]={0,0,0,0,0,0,0,0,0,0,0}; //This where channels value is stored until frame is complete.
00042 unsigned short Times[11]={0,0,0,0,0,0,0,0,0,0,0}; //This where channels value is stored until frame is complete.
00043 bool CanUpdate=false;       // Once PPM frame is complete this will be true
00044 
00045 //Raise_Error is just a function that helped me in development process. You can ignore it all togather.
00046 void Raise_Error (unsigned char Err_Code, int info) {
00047     switch (Err_Code) {
00048         case 0:
00049             PC.printf ("%i\n",info);
00050             break;
00051         case 1:
00052             PC.printf ("Broke@ %i\n",info);
00053             break;
00054         case 2:
00055             PC.printf ("Set ok\n");
00056             break;
00057         case 3:
00058             PC.printf ("%i\n",info);
00059             break;
00060         case 255:
00061             PC.printf("Initalized sucessfully \n");
00062             break;
00063         default:
00064             PC.printf("I shouldn't be here \n");
00065     }
00066 
00067 }
00068 
00069 //Here were all the work takeplace
00070 void SignalFall() {
00071     TimeElapsed = timer.read_us();
00072     if (TimeElapsed <300) { 
00073         //Raise_Error(0,TimeElapsed);
00074         return; //ignore, it's a glitch. Dont move to the next channel
00075     }
00076     __disable_irq();
00077     timer.reset();  
00078      //Raise_Error(0,TimeElapsed);
00079     if ((TimeElapsed > 8000 ) && (CurChannel != 0)) {   //somehow before reaching the end of PPM frame you read   "New" frame signal???
00080                                                          //Ok, it happens. Just ignore this frame and start a new one        
00081         //Raise_Error (1,CurChannel);          //incomplete channels set
00082         CurChannel=0;              
00083     }
00084    if ((TimeElapsed < 8000 ) && (CurChannel == 0)) {
00085         //Raise_Error (1,CurChannel);          //incomplete channels set
00086       __enable_irq();       // This is good. You've received "New" frame signal as expected
00087         return;
00088     }
00089 
00090     // Process current channel. This is a correct channel in a correct frame so far
00091     //if (CurChannel==4) Raise_Error(3,TimeElapsed);
00092     Channels[CurChannel]= (TimeElapsed-1000)*255/1000; // Normalize reading (Min: 900us Max: 1900 us). This is my readings, yours can be different
00093     Times[CurChannel] = TimeElapsed;
00094     CurChannel++;
00095     
00096     if (CurChannel==9 ) {      // great!, you've a complete correct frame. Update Joystick and star a new frame
00097         CurChannel=0;
00098         //Raise_Error(3,0);
00099         CanUpdate= true;
00100     }
00101     __enable_irq();
00102 }
00103 
00104 void Initalize () {
00105     __disable_irq();
00106     PC.baud(115200); // set baude rate
00107     PPMsignal.mode (PullUp);
00108     PPMsignal.fall(&SignalFall); //Attach SignalFall routine to handle PPMsignal fall
00109     timer.start();
00110     Raise_Error(255,0); // return successful
00111     timer.reset();
00112     __enable_irq();
00113 
00114 }
00115 
00116 int main() {
00117     //unsigned short *pOut = Times;
00118     unsigned char *pOut = Channels;
00119     
00120     Initalize();
00121     //wait(5);
00122     
00123 
00124     while (1) {
00125         if (CanUpdate) {        // update joystick here
00126             CanUpdate=false;
00127             joystick.joystick(Channels[1],Channels[4],Channels[3],Channels[2],Channels[7],Channels[8]);  //update joystick state (Throttle, Rudder, X,Y, Button 1, Button 2)
00128             PC.printf("% 4d,% 4d,% 4d,% 4d\r",pOut[1],pOut[2],pOut[3],pOut[4]); // Raise_Error(3,Channels[1]);
00129               //Channel 5 : PIT
00130               //Channel 6: PLT
00131         }
00132     }
00133 
00134 }
00135