2

I've run into problems using pigpio's wave generator in combination with hardware PWM.

Currently I'm working on a motion control with acceleration/sustain/deceleration phases. The phases are saved in waveforms. Speed should be sustained for a few seconds. The transitions weren't exactly very smooth. So I used hardware PWM for that, which worked way better.

The pigpio library states that each one will cancel the other out, if in use.

Well, when calling gpioHardwarePWM, any kind of waveform coming from gpioWaveChain or gpioWaveTxSend is cancel out correctly and instantly. However, for some reason it's not working the other way around.

The GPIO pins seem to be somehow occupied. Only when using gpioSetMode, they are freed at the expense of valuable time.

Maybe someone has run into a similar problem.

Help is very much appreciated!

Thanks in advance!

Max

Edit:


#include <pigpio.h>
#include <iostream>
#include <unistd.h>
#include <cmath>
#include <cstdlib>
#include <cstring>

// Front left
#define DIR_FL  26
#define STEP_FL 19
#define EN_FL   21

using namespace std;

// Declare velocity functions
double f_v1(double, float, double);
double f_v2(double, float, double);
double f_v3(double, float, float, float, double);

// Declare conversion functions
double vel2freq(double);
double freq2puls(double);
double puls2freq(double);
double freq2vel(double);
double vel2puls(double);
double puls2vel(int);

using namespace std;

int calculatePulses(double * pulses) {

    // Set time constants
    float t0 = 0;
    float t1 = 0.3;
    float t2 = 0.7;
    float t3 = 1;

    // Set velocities
    double v_max = 0.5;
    double v;

    //  Calculate maximal acceleration
    double a_max = t1 / (t1 * t2 + t1 * t3 + t0 * t0 - t1 * t1);

    // Calculate pulses
    int counter = 0;
    double currentTime = 0;

    // Initial pulse at velocity = 0.001 m/s
    pulses[counter] = 50000;
    currentTime = pulses[counter] / 1000000;

    while(currentTime < t3) {

        // Increase counter
        counter += 1;

        // Calculate velocity for current phase
        if(currentTime < t1) {

            v = f_v1(currentTime, t1, a_max);
        }
        else if (currentTime < t2) {

            v = f_v2(currentTime, t1, a_max);
        }
        else if (currentTime < t3) {

            v = f_v3(currentTime, t1, t2, t3, a_max);
        }
        else {

            v = v_max;
        }

        // Round and save pulse
        pulses[counter] = static_cast<int>(round(vel2puls(v)));

        // Update current time
        currentTime += (pulses[counter] / 1000000);
    }

    // Edit absolute number of pulses
    counter += 1;

    cout << "Counter: " << counter << endl;

    return counter;
}

// Velocity function for phase 1 (linear acceleration)
double f_v1(double t, float t1, double a_max) {

    double t0 = 0;

    double v = (a_max * (t * t + t0 * t0)) / (2 * t1);

    return v;
}

// Velocity function for phase 2 (constant acceleration)
double f_v2(double t, float t1, double a_max) {

    double t0 = 0;

    double v = a_max * t + (a_max * (t0 * t0 - t1 * t1)) / (2 * t1);

    return v;
}

// Velocity function for phase 3 (negative linear acceleration)
double f_v3(double t, float t1, float t2, float t3, double a_max) {

    double t0 = 0;

    double v = (a_max * (t * t * t1 - 2 * t3 * t * t1 + t0 * t0 * t2 - t3 * t0
    * t0 - t1 * t1 * t2 + t3 * t1 * t1 + t1 * t2 * t2)) / (2 * t1 * (t2 - t3));

    return v;
}

// Convert velocity to pulse length
double vel2puls(double velocity) {

    double pulse = (1000000 * 0.082 * M_PI / 3200) / velocity;

    return pulse;
}

// Convert velocity to pulse length
double puls2vel(int pulse) {

    return pulse = (1000000 * 0.082 * M_PI / 3200) / pulse;
}

double vel2freq(double velocity) {

    return 3200 * velocity / (M_PI * 0.082);
}

double freq2vel(double frequency) {

    return (frequency * M_PI * 0.082) / 3200;
}

int main() {

    if(gpioInitialise() > 0) {

        // Set pins
        gpioSetMode(DIR_FL, PI_OUTPUT);
        gpioSetMode(STEP_FL, PI_OUTPUT);
        gpioSetMode(EN_FL, PI_OUTPUT);
        gpioWrite(DIR_FL, 0);
        gpioWrite(EN_FL, 1);

        double pulses[5000];
        int counter = calculatePulses(pulses);
        double pulsesInv[counter];

        // Invert pulse array for decceleration
        for(int i = 0; i < counter; i++) {

            pulsesInv[i] = pulses[(counter - 1) - i];
        }

        int n = counter;

        gpioPulse_t pulse[2 * n];
        gpioPulse_t pulseInv[2 * n];
        gpioPulse_t pulseRun[2 * n];

        // Save pulses into pulse chain for acceleration
        for(int i = 0; i < counter; i++) {

            pulse[i * 2].gpioOn = (1 << STEP_FL);
            pulse[i * 2].gpioOff = 0;
            pulse[i * 2].usDelay = static_cast<int>(0.5 * pulses[i]);

            pulse[i * 2 + 1].gpioOn = 0;
            pulse[i * 2 + 1].gpioOff = (1 << STEP_FL);
            pulse[i * 2 + 1].usDelay = static_cast<int>(0.5 * pulses[i]);
        }

        // Generate pulse chain for steady velocity
        for(int i = 0; i < counter; i++) {

            pulseRun[i * 2].gpioOn = (1 << STEP_FL);
            pulseRun[i * 2].gpioOff = 0;
            pulseRun[i * 2].usDelay = static_cast<int>(0.5 * pulses[counter - 1]);

            pulseRun[i * 2 + 1].gpioOn = 0;
            pulseRun[i * 2 + 1].gpioOff = (1 << STEP_FL);
            pulseRun[i * 2 + 1].usDelay = static_cast<int>(0.5 * pulses[counter - 1]);
        }

        // Invert pulse chain for decceleration
        for(int i = 0; i < counter; i++) {

            pulseInv[i * 2].gpioOn = (1 << STEP_FL);
            pulseInv[i * 2].gpioOff = 0;
            pulseInv[i * 2].usDelay = static_cast<int>(0.5 * pulsesInv[i]);

            pulseInv[i * 2 + 1].gpioOn = 0;
            pulseInv[i * 2 + 1].gpioOff = (1 << STEP_FL);
            pulseInv[i * 2 + 1].usDelay = static_cast<int>(0.5 * pulsesInv[i]);
        }

        int wid[3];

        gpioWrite(EN_FL, 0);

        gpioWaveAddNew();
        gpioWaveAddGeneric(2 * n, pulse);
        wid[0] = gpioWaveCreate();
        cout << "ID: " << wid[0] << endl;
        gpioWaveTxSend(wid[0], PI_WAVE_MODE_ONE_SHOT_SYNC);
        while(gpioWaveTxBusy()) gpioDelay(1);
        gpioWaveDelete(wid[0]);
        gpioWaveClear();

        // Not very smooth transition (Uncomment)
//        gpioWaveAddNew();
//        gpioWaveAddGeneric(2 * n, pulseRun);
//        wid[1] = gpioWaveCreate();
//        cout << "ID: " << wid[1] << endl;
//        gpioWaveTxSend(wid[1], PI_WAVE_MODE_REPEAT_SYNC);
//        sleep(1);
//        gpioWaveTxStop();
//        gpioWaveDelete(wid[1]);

        // Very smooth transiton from acceleration to sustain phase
        gpioHardwarePWM(STEP_FL, vel2freq(0.5), 250000);
        sleep(1);

        gpioWaveAddNew();
        gpioWaveAddGeneric(2 * n, pulseInv);
        wid[2] = gpioWaveCreate();
        cout << "ID: " << wid[2] << endl;
        gpioWaveTxSend(wid[2], PI_WAVE_MODE_ONE_SHOT_SYNC);
        while(gpioWaveTxBusy()) gpioDelay(1);
        gpioWaveDelete(wid[2]);
        gpioWaveClear(); 

        gpioWrite(EN_FL, 1);
    }

    gpioTerminate();

    return 0;
}
  • Could you give a complete program which shows the problem? gpioDelay(1) is a busy wait, anything less than 100 microseconds is a busy wait. You don't need to use a wave chain to send a single wave. Why not use gpioWaveTxSend(wid[1], PI_WAVE_MODE_ONE_SHOT) instead? – joan Jun 18 at 17:29
  • I hope that helps. Thanks! – Nyge Jun 18 at 17:59
  • Unfortunately that didn't do the trick. There are two issues: 1.) There's a short break during the transition from one waveform to another, which is audible 2.) Although the transition from waveform and to PWM signal is seamless, going back to a waveform clogs up the stepper motor entirely. My guess: The function gpioHardwarePWM seems to occupy the GPIO pin, holding it on LOW the entire time. – Nyge Jun 19 at 9:33
  • I will look at this - but I'm not sure when I will have the time - so no time soon. – joan Jun 19 at 17:12
  • Okay, thanks Joan! There might be something wrong in your stopHardwarePWM function. Something else: Is there a way to increase the maximum number of pulses per wave? gpioWaveGetMaxPulses says 120000. Thanks again! – Nyge Jun 21 at 18:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.