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

    Generate PPM

    Scheduled Pinned Locked Moved Arduino
    2 Posts 2 Posters 5.5k Views 2 Watching
    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 Offline
      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....

      ? 1 Reply Last reply Reply Quote 0
      • ? Offline
        A Former User @cepics
        last edited by

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

        1 Reply Last reply Reply Quote 0

        Hello! It looks like you're interested in this conversation, but you don't have an account yet.

        Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

        With your input, this post could be even better 💗

        Register Login
        • First post
          Last post