Generate PPM
-
Hi all, I would like to send a PPM to this transmitter to control gimbal axes (PAN,TILT,ROL) with M5Stack gyro remotely.
the only sketch I found to generate PPM is for Arduino and use timer interrupt//https://forum.arduino.cc/index.php/topic,163199.msg1220724.html#msg1220724 // Started 18 Apr 2013 - the loco chassis is more or less ready for testing. // // This is a test program to drive a loco on R/C channel 1 based on the position of a potentiometer. // // The centre connection of the pot is connected to pin A2 // The control signal from the Arduino to the transmitter is on Pin D7. // // I intend that parts of this program will be used in the computer controlled version. // // The R/C receiver is programmed to treat the centre value (128?) as off with 0 and 255 representing // full forward and full reverse. Some experimentation will probably be necessary to determine the // correct 0 point. // The transmitter can receive a sequence of pulses for 2 to 7 channels. For this program pulses will be // prepared for 7 channels with channels 2 to 7 being values that correspond to centre off. // The receiver would not work with only 3 channels - it needs at least 4.. // // The Transmitter expects a sequence of pulses each of whose width (duration) conveys the // speed setting. The pulse lengths must vary between 1.0 and 2.0 millisecs with 1.5ms representing // centre off. Each pulse must be separated by a short pulse of 0.3ms and there must be a long pulse // to separate the groups of pulses. Ideally the group of pulses should repeat every 22ms // So, 2.0 + 0.3ms for 7 pulses takes 16.1ms thus requiring a separating pulse of 5.9ms. // // The pulses are generated by timer1 (16 bit) interrupts and to simpify matters when the computer is // controlling things the numbers needed to produce the sequence of pulse lengths will be stored // in an array. At each interrupt the next value in the array is used to set the duration for the // following interrupt. For this program the values in the array position corresponding to channel 3 // will be derived from the potentiometer position. (The Rx seems to be programmed to drive the motor // on ch3). // // Timer1 is used because the longer periods afforded by the 16bits are needed. The prescaler is set // to divide the CPU clock by 64 giving a timer clock of 250khz or 4 microsecs (4us). // On that basis 0.3ms requires a delay of 75 clock steps // 1.0 250 // 1.5 375 // 2.0 500 // 5.9 1475 // 15.1 3775 // // This program only communicates with the PC for program testing. // Data variables unsigned int ppm[16]; // the array of values for the timer1 interrupt timings unsigned int potVal; // value read from potemtiometer int curPpm = 0; // the position in the array of timings byte curPpmMax; // the actual number of timer steps char pulsePin = 7; // the digital pin for sending pulses to the transmitter char debugPin = 13; // something to watch to check things are working char potPin = 2; // the analog pin for the potentiometer byte loopCount = 0; // a crude substitute for delay() int analogIn; // for reading potentiometer position boolean testing = true; void setup() { if (testing) { Serial.begin(9600); Serial.println("Starting TrainRadioPot"); } // set the pin directions pinMode(pulsePin, OUTPUT); // pinMode(debugPin, OUTPUT); // set the timing values ppm[0] = 1475; //3775; // long pulse - see notes above ppm[1] = 75; // short dividing pulse ppm[2] = 305; // loco1 ch1 ppm[3] = 75; // short ppm[4] = 305; // loco2 ch2 ppm[5] = 75; // short ppm[6] = 305; // loco3 ch3 ppm[7] = 75; // short ppm[8] = 305; // loco4 ch4 ppm[9] = 75; // short ppm[10] = 305; // loco5 ch5 ppm[11] = 75; // short ppm[12] = 305; // loco6 ch6 ppm[13] = 75; // short ppm[14] = 305; // loco7 ch7 ppm[15] = 75; // short curPpmMax = 16; // the number of timer values curPpm = 0; // the starting position in the array of timings // setup and start timer interrupts // ppm is achieved by sending different delays to the timer interrupt noInterrupts(); TCCR1A = 0; // set entire TCCR1A register to 0 TCCR1B = 0; // same for TCCR1B // set compare match register to desired timer count: OCR1A = 1000; // It works by causing an interrupt when TCNT2 counts up to this number // This number will be set from the ppm array when the program is running digitalWrite(pulsePin, 0); // start with pin low // turn on CTC mode: Clear Timer on Compare bitSet(TCCR1B, WGM12); // Set CS10 and CS11 bits for 64 prescaler: 10, 12 = 1024 bitSet(TCCR1B, CS10); bitSet(TCCR1B, CS11); bitClear(TCCR1B, CS12); // enable timer compare A interrupt: bitSet(TIMSK1, OCIE1A); interrupts(); } void loop() { if (loopCount == 1) { analogIn = analogRead(potPin); // the reading must be converted from the range 0 - 1023 to the range 250 - 500 // which means dividing by 4 and adding 180 to give 305 at the centre potVal = (analogIn >> 2) + 180; // if (potVal > 302 && potVal < 308) { if (potVal > 280 && potVal < 320) { potVal = 305; // to create an off space without jitter } // ppm[2] = potVal; // ppm[8] = potVal;// } CH4 ROL STABE // ppm[4] = potVal; // CH2 PAN STABE YAW ppm[6] = potVal; // CH3 TILT STABE PICH } // loopCount = 0; // for testing - so analog read is ignored loopCount = loopCount + 1; // it will roll over to zero automatically // the purpose of loopCount is so that the pot isn't read every loop } // interrupt routine that is triggered when the timer counts up to the preset value ISR(TIMER1_COMPA_vect) { noInterrupts(); digitalWrite(pulsePin, !digitalRead(pulsePin)); // change the state of the pin OCR1A = ppm[curPpm]; // set the value for the next time interval curPpm = ((curPpm + 1) % curPpmMax); // move the index on // the modulus operator makes the index roll over to the start interrupts(); }
I also found this function (not yet tested with the transmitter)
//this programm will put out a PPM signal //////////////////////CONFIGURATION/////////////////////////////// #define chanel_number 8 //set the number of chanels #define default_servo_value 1500 //set the default servo value #define PPM_FrLen 22500 //set the PPM frame length in microseconds (1ms = 1000µs) #define PPM_PulseLen 300 //set the pulse length #define onState 1 //set polarity: 1 is positive, 0 is negative #define sigPin 10 //set PPM signal pin on the arduino ////////////////////////////////////////////////////////////////// /*this array holds the servo values for the ppm signal change theese values in your code (usually servo values are between 1000 and 2000)*/ int ppm[chanel_number]; void setup(){ //initiallize default ppm values for(int i=0; i<chanel_number; i++){ ppm[i]= default_servo_value; } pinMode(sigPin, OUTPUT); digitalWrite(sigPin, !onState); //set the PPM signal pin to the default state (off) } void loop(){ //put main code here ppmWrite(); } void ppmWrite(){ //generate PPM signal static unsigned long lastFrLen; static unsigned long lastServo; static unsigned long lastPulse; static boolean PPM_run; static boolean pulse; static boolean pulseStart = true; static byte counter; static byte part = true; if(micros() - lastFrLen >= PPM_FrLen){ //start PPM signal after PPM_FrLen has passed lastFrLen = micros(); PPM_run = true; } if(counter >= chanel_number){ PPM_run = false; counter = 0; pulse = true; //put out the last pulse } if(PPM_run){ if (part){ //put out the pulse pulse = true; part = false; lastServo = micros(); } else{ //wait till servo signal time (values from the ppm array) has passed if(micros() - lastServo >= ppm[counter]){ counter++; //do the next channel part = true; } } } if(pulse){ if(pulseStart == true){ //start the pulse digitalWrite(sigPin, onState); pulseStart = false; lastPulse = micros(); } else{ //will wait till PPM_PulseLen has passed and finish the pulse if(micros() - lastPulse >= PPM_PulseLen){ digitalWrite(sigPin, !onState); pulse = false; pulseStart = true; } } } }
I really don't know how to port all of this to M5Stack.
I'm trying to merge the first sketch with a timer interrupt sketch for esp32volatile int interruptCounter; int totalInterruptCounter; hw_timer_t * timer = NULL; portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; void IRAM_ATTR onTimer() { portENTER_CRITICAL_ISR(&timerMux); interruptCounter++; portEXIT_CRITICAL_ISR(&timerMux); } void setup() { Serial.begin(115200); timer = timerBegin(0, 80, true); timerAttachInterrupt(timer, &onTimer, true); // timerAlarmWrite(timer, 1000000, true); timerAlarmWrite(timer, 22000, true); PER IL PPM ?? ?? timerAlarmEnable(timer); } void loop() { if (interruptCounter > 0) { portENTER_CRITICAL(&timerMux); interruptCounter--; portEXIT_CRITICAL(&timerMux); totalInterruptCounter++; Serial.print("An interrupt as occurred. Total number: "); Serial.println(totalInterruptCounter); } }
I'm very confused....
-
Hi
do you find a solution ? also interest by this.
Thx