🤖Have you ever tried Chat.M5Stack.com before asking??😎
    M5Stack Community
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Register
    • Login

    Generate PPM

    Arduino
    2
    2
    4.9k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • C
      cepics
      last edited by

      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 esp32

      volatile 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....

      A 1 Reply Last reply Reply Quote 0
      • A
        amn @cepics
        last edited by

        Hi
        do you find a solution ? also interest by this.
        Thx

        amn

        1 Reply Last reply Reply Quote 0
        • First post
          Last post