Electric Turbine With ESP32

Introduction: Electric Turbine With ESP32

About: Do you like technology? Follow my channel on Youtube and my Blog. In them I put videos every week of microcontrollers, arduinos, networks, among other subjects.

Today, I’ll be discussing an electric turbine with ESP32. The assembly has a part that was printed in 3D. I will present a PWM function of the ESP32 that is suitable for controlling electric motors. This will be used in a DC motor. I will also demonstrate the operation of this MCPWM (Motor Control PWM) in a practical application.

I used ESP32 LoRa in this project, and I think it is important to note here that this microcontroller has two blocks inside it. These blocks are capable of controlling three motors each. Thus, it is possible to control up to six motors with PWM, all independently. This means that the control I’ll use here is not the standard (which is something similar to the Arduino). Instead, the control is the chip itself, which guarantees the ESP32 a lot of flexibility with respect to motor control.

Step 1: Demonstration

Step 2: PWM Motor Control

General Diagram:

• The MCPWM function of the ESP32 can be used to control various types of electric motors. It has two units.

• Each unit has three PWM output pairs.

• Each output A / B pair can be synchronized with one of three synchronization timers 0, 1, or 2.

• One Timer can be used to synchronize more than one PWM output pair

Full Diagram:

• Each unit is also capable of collecting input signals as SYNCHRONIZATION SIGNS;

• Detect FAULT SIGNS for overcurrent or motor overvoltage;

• Obtain feedback with CAPTURE SIGNALS, such as the position of the Engine

Step 3: Resources Used

• Jumpers for connection

• Heltec Wifi LoRa 32

• Common DC motor

• Bridge H - L298N

• USB cable

• Protoboard

• Power supply

Step 4: ESP 32 Dev Kit - Pinout

Step 5: Turbine Mounting

Step 6: Circuit - Connections

Step 7: Measurement on Oscilloscope

Step 8: Source Code

Header

#include <Arduino.h> //Não é necessário caso use Arduino IDE
#include "driver/mcpwm.h" //inclui a biblioteca "Motor Control PWM" nativa do ESP32 #include <Wire.h> // Necessário apenas para o Arduino 1.6.5 e posterior #include "SSD1306.h" // o mesmo que #include "SSD1306Wire.h" //OLED_SDA -- GPIO4 //OLED_SCL -- GPIO15 //OLED_RST -- GPIO16 #define SDA 4 #define SCL 15 #define RST 16 SSD1306 display(0x3c, SDA, SCL, RST); //Instanciando e ajustando os pinos do objeto "display" #define GPIO_PWM0A_OUT 12 //Declara GPIO 12 como PWM0A #define GPIO_PWM0B_OUT 14 //Declara GPIO 14 como PWM0B

Setup

void setup() {
Serial.begin(115200); display.init(); //display.flipScreenVertically(); //Vira a tela verticalmente display.clear(); //ajusta o alinhamento para a esquerda display.setTextAlignment(TEXT_ALIGN_LEFT); //ajusta a fonte para Arial 16 display.setFont(ArialMT_Plain_16); //mcpwm_gpio_init(unidade PWM 0, saida A, porta GPIO) => Instancia o MCPWM0A no pino GPIO_PWM0A_OUT declarado no começo do código mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT); //mcpwm_gpio_init(unidade PWM 0, saida B, porta GPIO) => Instancia o MCPWM0B no pino GPIO_PWM0B_OUT declarado no começo do código mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, GPIO_PWM0B_OUT); mcpwm_config_t pwm_config; pwm_config.frequency = 1000; //frequência = 500Hz, pwm_config.cmpr_a = 0; //Ciclo de trabalho (duty cycle) do PWMxA = 0 pwm_config.cmpr_b = 0; //Ciclo de trabalho (duty cycle) do PWMxb = 0 pwm_config.counter_mode = MCPWM_UP_COUNTER; //Para MCPWM assimetrico pwm_config.duty_mode = MCPWM_DUTY_MODE_0; //Define ciclo de trabalho em nível alto //Inicia(Unidade 0, Timer 0, Config PWM) mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //Define PWM0A & PWM0B com as configurações acima }

Functions

//Função que configura o MCPWM operador A (Unidade, Timer, Porcentagem (ciclo de trabalho))
static void brushed_motor_forward(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num , float duty_cycle) { //mcpwm_set_signal_low(unidade PWM(0 ou 1), Número do timer(0, 1 ou 2), Operador (A ou B)); => Desliga o sinal do MCPWM no Operador B (Define o sinal em Baixo) mcpwm_set_signal_low(mcpwm_num, timer_num, MCPWM_OPR_B); //mcpwm_set_duty(unidade PWM(0 ou 1), Número do timer(0, 1 ou 2), Operador (A ou B), Ciclo de trabalho (% do PWM)); => Configura a porcentagem do PWM no Operador A (Ciclo de trabalho) mcpwm_set_duty(mcpwm_num, timer_num, MCPWM_OPR_A, duty_cycle); //mcpwm_set_duty_tyoe(unidade PWM(0 ou 1), Número do timer(0, 1 ou 2), Operador (A ou B), Nível do ciclo de trabalho (alto ou baixo)); => define o nível do ciclo de trabalho (alto ou baixo) mcpwm_set_duty_type(mcpwm_num, timer_num, MCPWM_OPR_A, MCPWM_DUTY_MODE_0); //Nota: Chame essa função toda vez que for chamado "mcpwm_set_signal_low" ou "mcpwm_set_signal_high" para manter o ciclo de trabalho configurado anteriormente } //Função que configura o MCPWM Do operador B (Unidade, Timer, Porcentagem (ciclo de trabalho)) static void brushed_motor_backward(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num , float duty_cycle) { mcpwm_set_signal_low(mcpwm_num, timer_num, MCPWM_OPR_A); //Desliga o sinal do MCPWM no Operador A (Define o sinal em Baixo) mcpwm_set_duty(mcpwm_num, timer_num, MCPWM_OPR_B, duty_cycle); //Configura a porcentagem do PWM no Operador B (Ciclo de trabalho) mcpwm_set_duty_type(mcpwm_num, timer_num, MCPWM_OPR_B, MCPWM_DUTY_MODE_0); //define o nível do ciclo de trabalho (alto ou baixo) } //Função que para o MCPWM de ambos os Operadores static void brushed_motor_stop(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num) { mcpwm_set_signal_low(mcpwm_num, timer_num, MCPWM_OPR_A); //Desliga o sinal do MCPWM no Operador A mcpwm_set_signal_low(mcpwm_num, timer_num, MCPWM_OPR_B); //Desliga o sinal do MCPWM no Operador B }

Loop

void loop() {
//Move o motor no sentido horário brushed_motor_forward(MCPWM_UNIT_0, MCPWM_TIMER_0, 50.0); oled("50"); delay(2000); //Para o motor brushed_motor_stop(MCPWM_UNIT_0, MCPWM_TIMER_0); oled("0"); delay(2000); //Move o motor no sentido antihorário brushed_motor_backward(MCPWM_UNIT_0, MCPWM_TIMER_0, 25.0); oled("25"); delay(2000); //Para o motor brushed_motor_stop(MCPWM_UNIT_0, MCPWM_TIMER_0); oled("0"); delay(2000); // Aceleracao i de 1 a 100 for(int i=10;i<=100;i++){ brushed_motor_forward(MCPWM_UNIT_0, MCPWM_TIMER_0, i); oled(String(i)); delay(200); } // Desaceleração i de 100 a 1 delay(5000); for(int i=100;i>=10;i--){ brushed_motor_forward(MCPWM_UNIT_0, MCPWM_TIMER_0, i); oled(String(i)); delay(100); } delay(5000); }

Step 9: ​Download the Files

1 Person Made This Project!

Recommendations

  • For the Home Contest

    For the Home Contest
  • Make It Bridge

    Make It Bridge
  • Big and Small Contest

    Big and Small Contest

2 Comments

0
ingalf83
ingalf83

7 weeks ago

Olá Fernando,para o meu projeto, fui inspirado pelo seu código de exemplo para pilotar dois motores de 24V reduzidos para preencher ou esvaziar reatores de água, julgam um esp32 Wroom 32 e um L298N.
Operação: Se os motores voltarem para a esquerda, encheremos o lastro direito e esquerdo e, se eles voltarem para a direita, esvaziaremos os reatores da direita e da esquerda.
Meu problema é que não consigo sincronizar os dois motores para ter as informações dos dois codificadores exatamente iguais, exemplo:
Reatores à direita e esquerda vazios e o valor dos dois codificadores 15000.
Reatores retos e esquerdo valor total dos dois codificadores 0
Exemplo do seu código modificado:

/*
01 fevrier 2023

UART RX IO TX IO CTS RTS
UART0 GPIO3 GPIO1 N/A N/A Ne pas utiliser pour les projets !
-------------------------------------------------------------------------
UART RX IO TX IO CTS RTS
UART1 GPIO9(SD2) GPIO10(SD3) GPIO6 GPIO11 Utilisable par le code utilisateur
UART2 GPIO16 GPIO17 GPIO8 GPIO7 Utilisable par le code utilisateur
*/

#include <Arduino.h> // Necessaire si on utilise l'IDE Arduino
#include "driver/mcpwm.h" // Inclue la bibliothéque "Motor Control PWM" native du ESP32
#include <Wire.h> // Necessaire si utilisation de IDE Arduino version 1.6.5 et posterieure
#include <Bounce2.h>

// Moteur 1 (Moteur Gauche)
#define GPIO_PWM0A_OUT_G 18 // Declaration GPIO 18 comme PWM0A IN1
#define GPIO_PWM0B_OUT_G 5 // Declaration GPIO 5 comme PWM0B IN2

// Moteur 2 (Moteur Droit)
#define GPIO_PWM0A_OUT_D 17 // Declaration GPIO 17 comme PWM0A IN3
#define GPIO_PWM0B_OUT_D 16 // Declaration GPIO 16 comme PWM0B IN4

//********* Moteur Gauche ***************************************
// Fonction qui configure l'opérateur MCPWM A (Unité, Temps, Pourcentage (cycle de travail))
static void brushed_motor_forward_G(mcpwm_unit_t mcpwm_num_G, mcpwm_timer_t timer_num_G , float duty_cycle_G)
{
//mcpwm_set_signal_low(Unité PWM(0 ou 1), Numero du timer(0, 1 ou 2), Operateur (A ou B)); => Éteindre le signal MCPWM sur l'opérateur B (définit le signal vers le niveau bas)
mcpwm_set_signal_low(mcpwm_num_G, timer_num_G, MCPWM_OPR_B);

//mcpwm_set_duty(Unité PWM(0 ou 1), Numero du timer(0, 1 ou 2), Operateur (A ou B), Cycle de travail (% du PWM)); => Configure le pourcentage de PWM dans l'opérateur A (cycle de travail)
mcpwm_set_duty(mcpwm_num_G, timer_num_G, MCPWM_OPR_A, duty_cycle_G);

//mcpwm_set_duty_type(Unité PWM(0 ou 1), Numero du timer(0, 1 ou 2), Operateur (A ou B), Niveau du cycle de travail (haut ou bas)); => Définit le niveau du cycle de travail (haut ou bas)
mcpwm_set_duty_type(mcpwm_num_G, timer_num_G, MCPWM_OPR_A, MCPWM_DUTY_MODE_0);
// Nota: Appel de cette fonction qui s'appelle "mcpwm_set_signal_low" ou "mcpwm_set_signal_high" pour maintenir le cycle de travail configuré plus haut
}

// Fonction qui configure le MCPWM de l'opérateur B (Unité, Temps, Pourcentage (cycle de travail))
static void brushed_motor_backward_G(mcpwm_unit_t mcpwm_num_G, mcpwm_timer_t timer_num_G, float duty_cycle_G)
{
mcpwm_set_signal_low(mcpwm_num_G, timer_num_G, MCPWM_OPR_A); // Désactiver le signal MCPWM sur l'opérateur A (définit le signal ci-dessous)
mcpwm_set_duty(mcpwm_num_G, timer_num_G, MCPWM_OPR_B, duty_cycle_G); // Configure le pourcentage de PWM dans l'opérateur B (cycle de travail)
mcpwm_set_duty_type(mcpwm_num_G, timer_num_G, MCPWM_OPR_B, MCPWM_DUTY_MODE_0); // Définit le niveau du cycle de travail (haut ou bas)
}

// Fonctionne que pour le MCPWM des deux opérateurs
static void brushed_motor_stop_G(mcpwm_unit_t mcpwm_num_G, mcpwm_timer_t timer_num_G)
{
mcpwm_set_signal_low(mcpwm_num_G, timer_num_G, MCPWM_OPR_A); // Désactiver le signal MCPWM sur l'opérateur A
mcpwm_set_signal_low(mcpwm_num_G, timer_num_G, MCPWM_OPR_B); // Désactiver le signal MCPWM sur l'opérateur B
}
//********* Fin Moteur Gauche ***************************************

//********* Moteur Droit ***************************************
// Fonction qui configure l'opérateur MCPWM A (Unité, Temps, Pourcentage (cycle de travail))
static void brushed_motor_forward_D(mcpwm_unit_t mcpwm_num_D, mcpwm_timer_t timer_num_D , float duty_cycle_D)
{
//mcpwm_set_signal_low(Unité PWM(0 ou 1), Numero du timer(0, 1 ou 2), Operateur (A ou B)); => Éteindre le signal MCPWM sur l'opérateur B (définit le signal vers le niveau bas)
mcpwm_set_signal_low(mcpwm_num_D, timer_num_D, MCPWM_OPR_B);

//mcpwm_set_duty(Unité PWM(0 ou 1), Numero du timer(0, 1 ou 2), Operateur (A ou B), Cycle de travail (% du PWM)); => Configure le pourcentage de PWM dans l'opérateur A (cycle de travail)
mcpwm_set_duty(mcpwm_num_D, timer_num_D, MCPWM_OPR_A, duty_cycle_D);

//mcpwm_set_duty_tyoe(Unité PWM(0 ou 1), Numero du timer(0, 1 ou 2), Operateur (A ou B), Niveau du cycle de travail (haut ou bas)); => Définit le niveau du cycle de travail (haut ou bas)
mcpwm_set_duty_type(mcpwm_num_D, timer_num_D, MCPWM_OPR_A, MCPWM_DUTY_MODE_0);
// Nota: Appel de cette fonction qui s'appelle "mcpwm_set_signal_low" ou "mcpwm_set_signal_high" pour maintenir le cycle de travail configuré plus haut
}

// Fonction qui configure le MCPWM de l'opérateur B (Unité, Temps, Pourcentage (cycle de travail))
static void brushed_motor_backward_D(mcpwm_unit_t mcpwm_num_D, mcpwm_timer_t timer_num_D, float duty_cycle_D)
{
mcpwm_set_signal_low(mcpwm_num_D, timer_num_D, MCPWM_OPR_A); // Désactiver le signal MCPWM sur l'opérateur A (définit le signal ci-dessous)
mcpwm_set_duty(mcpwm_num_D, timer_num_D, MCPWM_OPR_B, duty_cycle_D); // Configure le pourcentage de PWM dans l'opérateur B (cycle de travail)
mcpwm_set_duty_type(mcpwm_num_D, timer_num_D, MCPWM_OPR_B, MCPWM_DUTY_MODE_0); // Définit le niveau du cycle de travail (haut ou bas)
}

// Fonctionne que pour le MCPWM des deux opérateurs
static void brushed_motor_stop_D(mcpwm_unit_t mcpwm_num_D, mcpwm_timer_t timer_num_D)
{
mcpwm_set_signal_low(mcpwm_num_D, timer_num_D, MCPWM_OPR_A); // Désactiver le signal MCPWM sur l'opérateur A
mcpwm_set_signal_low(mcpwm_num_D, timer_num_D, MCPWM_OPR_B); // Désactiver le signal MCPWM sur l'opérateur B
}
//********* Fin Moteur Droit ***************************************

// Encodeur moteur droit
int PinEncodeurAMoteurDroit = 22; // Fil jaune
int PinEncodeurBMoteurDroit = 23; // Fil vert
volatile int lastEncodedMoteurDroit = 0;
volatile long encoderValueMoteurDroit = 0;
int CompteurEncodeurMoteurDroit;

// Encodeur moteur gauche
int PinEncodeurAMoteurGauche = 35; // Fil vert
int PinEncodeurBMoteurGauche = 32; // Fil jaune
volatile int lastEncodedMoteurGauche = 0;
volatile long encoderValueMoteurGauche = 0;
int CompteurEncodeurMoteurGauche;

// Touches TTP223
#define Touche1 12 // Remplir les ballasts a vitesse normale rotation a gauche vers compteur 0
#define Touche2 13 // Vider les ballasts a vitesse normale rotation a droite vers compteur 15000
#define Touche3 14 // Vider les ballasts a vitesse rapide rotation a droite vers compteur 15000

// Valeur des boutons
int RemplirBallastsNormal; // 12
int ViderBallastsNormal; // 13
int ViderBallastsRapide; // 14

Bounce debouncer1 = Bounce();
Bounce debouncer2 = Bounce();
Bounce debouncer3 = Bounce();

void setup() {

Serial.begin(115200);

pinMode(Touche1, INPUT);
debouncer1.attach(Touche1); // 12
debouncer1.interval(5); // interval in ms

pinMode(Touche2, INPUT); // 13
debouncer2.attach(Touche2);
debouncer2.interval(5); // interval in ms

pinMode(Touche3, INPUT);
debouncer3.attach(Touche3); // 14
debouncer3.interval(5); // interval in ms

//******************** Encodeurs *****************************************
pinMode(PinEncodeurAMoteurDroit, INPUT_PULLUP); // Pin encodeur "A" 23 Jaune doit être connectée à la broche interruption
pinMode(PinEncodeurBMoteurDroit, INPUT_PULLUP); // Pin encodeur "B" 22 Vert doit être connectée à la broche interruption
pinMode(PinEncodeurAMoteurGauche, INPUT_PULLUP); // Pin encodeur "A" 35 Jaune doit être connectée à la broche interruption
pinMode(PinEncodeurBMoteurGauche, INPUT_PULLUP); // Pin encodeur "B" 32 Vert doit être connectée à la broche interruption

digitalWrite(PinEncodeurAMoteurDroit, HIGH);
digitalWrite(PinEncodeurBMoteurDroit, HIGH);

digitalWrite(PinEncodeurAMoteurGauche, HIGH);
digitalWrite(PinEncodeurBMoteurGauche, HIGH);

// Appeler la procedure EncoderMoteurDroit() quand un changement HIGH/LOW est detecté
// Sur l'interruption 0 (pin 2), ou interruption 1 (pin 3)
attachInterrupt(PinEncodeurAMoteurDroit, EncoderMoteurDroit, CHANGE);
attachInterrupt(PinEncodeurBMoteurDroit, EncoderMoteurDroit, CHANGE);

// Appeler la procedure EncoderMoteurGauche() quand un changement HIGH/LOW est detecté
attachInterrupt(PinEncodeurAMoteurGauche, EncoderMoteurGauche, CHANGE);
attachInterrupt(PinEncodeurBMoteurGauche, EncoderMoteurGauche, CHANGE);
//***************************************************************************************

//********* Moteur Gauche ***************************************
//mcpwm_gpio_init(Unité PWM 0, Sortie A, Port GPIO)
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT_G);

//mcpwm_gpio_init(Unité PWM 0, Sortie B, Port GPIO)
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, GPIO_PWM0B_OUT_G);

mcpwm_config_t pwm_config_G;

pwm_config_G.frequency = 3333; // Frequence = 500Hz, 1000 defaut
pwm_config_G.cmpr_a = 0; // Cycle de travail (duty cycle) du PWMxA = 0
pwm_config_G.cmpr_b = 0; // Cycle de travail (duty cycle) du PWMxB = 0
pwm_config_G.counter_mode = MCPWM_UP_COUNTER; // Pour MCPWM asymétrique
pwm_config_G.duty_mode = MCPWM_DUTY_MODE_0; // Définit le cycle de travail du niveau haut

// Initialisation (Unité 0, Temps 0, Config PWM)
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config_G); // Definit PWM0A & PWM0B avec les paramètres ci-dessus
//********* Fin Moteur Gauche ***************************************

//********* Moteur Droit ***************************************
//mcpwm_gpio_init(Unité PWM 0, Sortie A, Port GPIO)
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT_D);

//mcpwm_gpio_init(Unité PWM 0, Sortie B, Port GPIO)
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, GPIO_PWM0B_OUT_D);


mcpwm_config_t pwm_config_D;

pwm_config_D.frequency = 3333; // Frequence = 500Hz, 1000 defaut
pwm_config_D.cmpr_a = 0; // Cycle de travail (duty cycle) du PWMxA = 0
pwm_config_D.cmpr_b = 0; // Cycle de travail (duty cycle) du PWMxB = 0
pwm_config_D.counter_mode = MCPWM_UP_COUNTER; // Pour MCPWM asymétrique
pwm_config_D.duty_mode = MCPWM_DUTY_MODE_0; // Définit le cycle de travail du niveau haut

// Initialisation (Unité 0, Temps 0, Config PWM)
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config_D); // Definit PWM0A & PWM0B avec les paramètres ci-dessus
//********* Fin Moteur Droit ***************************************

// Arreter le moteur gauche
//brushed_motor_stop_G(MCPWM_UNIT_0, MCPWM_TIMER_0);

// Arreter le moteur droit
//brushed_motor_stop_D(MCPWM_UNIT_0, MCPWM_TIMER_0);

// Le programme demarre avec les ballasts vides don compteur 15000
//CompteurEncodeurMoteurDroit = 15000;
//CompteurEncodeurMoteurGauche = 15000;


// Forcer la mise a 15000 au demarrage du programme
//if (CompteurEncodeurMoteurGauche <= 0 or CompteurEncodeurMoteurGauche >= 0) {
// Le programme demarre avec les ballasts vides donc compteur 15000
CompteurEncodeurMoteurGauche = 15000;
//}

// Forcer la mise a 15000 au demarrage du programme
//if (CompteurEncodeurMoteurDroit <= 0 or CompteurEncodeurMoteurDroit >= 0) {
// Le programme demarre avec les ballasts vides donc compteur 15000
CompteurEncodeurMoteurDroit = 15000;
//}
} // Fin setup()

void loop() {

// Sert pour le relachement des boutons pour arreter les moteurs
// Arreter le moteur gauche
brushed_motor_stop_G(MCPWM_UNIT_0, MCPWM_TIMER_0);

// Arreter le moteur droit
brushed_motor_stop_D(MCPWM_UNIT_0, MCPWM_TIMER_0);

// Rotation du moteur gauche dans le sens horaire a 60% de puissance (Vu coté axe)
//brushed_motor_forward_G(MCPWM_UNIT_0, MCPWM_TIMER_0, 60.0);

// Rotation du moteur droit dans le sens horaire a 60% de puissance (Vu coté axe)
//brushed_motor_forward_D(MCPWM_UNIT_0, MCPWM_TIMER_0, 60.0);
//delay(5000);

// Arreter le moteur gauche
//brushed_motor_stop_G(MCPWM_UNIT_0, MCPWM_TIMER_0);

// Arreter le moteur droit
//brushed_motor_stop_D(MCPWM_UNIT_0, MCPWM_TIMER_0);
//delay(2000);

// Rotation du moteur gauche dans le sens anti-horaire a 60 % de puissance (Vu coté axe)
//brushed_motor_backward_G(MCPWM_UNIT_0, MCPWM_TIMER_0, 60.0);

// Rotation du moteur droit dans le sens anti-horaire a 60 % de puissance (Vu coté axe)
//brushed_motor_backward_D(MCPWM_UNIT_0, MCPWM_TIMER_0, 60.0);
//delay(5000);

// Arreter le moteur gauche
//brushed_motor_stop_G(MCPWM_UNIT_0, MCPWM_TIMER_0);
//delay(2000);

// Arreter le moteur droit
//brushed_motor_stop_D(MCPWM_UNIT_0, MCPWM_TIMER_0);
//delay(2000);


// Accélération i de 1% a 100% de puissance dans le sens horaire
//for(int i=10;i<=100;i++){
//brushed_motor_forward(MCPWM_UNIT_0, MCPWM_TIMER_0, i);
//Serial.println(String(i));
//delay(200);
//}

// Déccélération i de 100% a 1% de puissance dans le sens horaire
//delay(5000); // Mise en attente
//for(int i=100;i>=10;i--){
//brushed_motor_forward(MCPWM_UNIT_0, MCPWM_TIMER_0, i);
//Serial.println(String(i));
//delay(100);
//}

debouncer1.update();
debouncer2.update();
debouncer3.update();

RemplirBallastsNormal = debouncer1.read(); // Rotation a gauche vers 0 (12)
ViderBallastsNormal = debouncer2.read(); // Rotation a droite vers 15000 (13)
ViderBallastsRapide = debouncer3.read(); // Rotation a droite vers 15000 (14)


if (RemplirBallastsNormal == HIGH)
{
// Rotation du moteur gauche dans le sens horaire a 60% de puissance (Vu coté axe)
brushed_motor_forward_G(MCPWM_UNIT_0, MCPWM_TIMER_0, 60.0);

// Rotation du moteur droit dans le sens horaire a 60% de puissance (Vu coté axe)
brushed_motor_forward_D(MCPWM_UNIT_0, MCPWM_TIMER_0, 60.0);

if (CompteurEncodeurMoteurDroit <= 0) {
// Arreter le moteur droit
brushed_motor_stop_D(MCPWM_UNIT_0, MCPWM_TIMER_0);
CompteurEncodeurMoteurDroit = 0;
}

if (CompteurEncodeurMoteurGauche <= 0) {
// Arreter le moteur droit
brushed_motor_stop_D(MCPWM_UNIT_0, MCPWM_TIMER_0);
CompteurEncodeurMoteurGauche = 0;
}

}

if (ViderBallastsNormal == HIGH)
{
// Rotation du moteur gauche dans le sens anti-horaire a 60 % de puissance (Vu coté axe)
brushed_motor_backward_G(MCPWM_UNIT_0, MCPWM_TIMER_0, 60.0);

// Rotation du moteur droit dans le sens anti-horaire a 60 % de puissance (Vu coté axe)
brushed_motor_backward_D(MCPWM_UNIT_0, MCPWM_TIMER_0, 60.0);
//delay(1);
}

if (ViderBallastsRapide == HIGH)
{
// Rotation du moteur gauche dans le sens anti-horaire a 100 % de puissance (Vu coté axe)
brushed_motor_backward_G(MCPWM_UNIT_0, MCPWM_TIMER_0, 100.0);

// Rotation du moteur droit dans le sens anti-horaire a 100 % de puissance (Vu coté axe)
brushed_motor_backward_D(MCPWM_UNIT_0, MCPWM_TIMER_0, 100.0);
//delay(1);
}

Serial.print("Compteur droit ");
//Serial.print(encoderValueMoteurDroit);
Serial.print(CompteurEncodeurMoteurDroit);
Serial.print(" ");
Serial.print("Compteur gauche ");
//Serial.println(encoderValueMoteurGauche);
Serial.println(CompteurEncodeurMoteurGauche);
} // Fin loop()

void EncoderMoteurDroit(){

int MSB = digitalRead(PinEncodeurAMoteurDroit); // MSB = bit le plus important
int LSB = digitalRead(PinEncodeurBMoteurDroit); // LSB = bit le moins significatif

int encodedMoteurDroit = (MSB << 1) |LSB; // Conversion de la valeur des 2 broches en un seul nombre
int sum = (lastEncodedMoteurDroit << 2) | encodedMoteurDroit; // Ajout à la valeur codée précédente

if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValueMoteurDroit --;
if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValueMoteurDroit ++;

lastEncodedMoteurDroit = encodedMoteurDroit; // Stocker cette valeur pour la prochaine fois
//CompteurEncodeurMoteurDroit = abs(encoderValueMoteurDroit);
CompteurEncodeurMoteurDroit = encoderValueMoteurDroit;

//if (CompteurEncodeurMoteurDroit >= 15000) {
//// Arreter le moteur droit
//brushed_motor_stop_D(MCPWM_UNIT_0, MCPWM_TIMER_0);
//CompteurEncodeurMoteurDroit = 15000;
//}
//
//if (CompteurEncodeurMoteurDroit <= 0) {
//// Arreter le moteur droit
//brushed_motor_stop_D(MCPWM_UNIT_0, MCPWM_TIMER_0);
//CompteurEncodeurMoteurDroit = 0;
//}

}


void EncoderMoteurGauche(){

int MSB = digitalRead(PinEncodeurAMoteurGauche); // MSB = bit le plus important
int LSB = digitalRead(PinEncodeurBMoteurGauche); // LSB = bit le moins significatif

int encodedMoteurGauche = (MSB << 1) |LSB; // Conversion de la valeur des 2 broches en un seul nombre
int sum = (lastEncodedMoteurGauche << 2) | encodedMoteurGauche; // Ajout à la valeur codée précédente

if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValueMoteurGauche ++;
if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValueMoteurGauche --;

lastEncodedMoteurGauche = encodedMoteurGauche; // Stocker cette valeur pour la prochaine fois
//CompteurEncodeurMoteurGauche = abs(encoderValueMoteurGauche);
CompteurEncodeurMoteurGauche = encoderValueMoteurGauche;

//if (CompteurEncodeurMoteurGauche >= 15000) {
//// Arreter le moteur gauche
//brushed_motor_stop_G(MCPWM_UNIT_0, MCPWM_TIMER_0);
//CompteurEncodeurMoteurGauche = 15000;
//}
//
//if (CompteurEncodeurMoteurGauche <= 0) {
//// Arreter le moteur gauche
//brushed_motor_stop_G(MCPWM_UNIT_0, MCPWM_TIMER_0);
//CompteurEncodeurMoteurGauche = 0;
//}

}

0
Pepito_2
Pepito_2

Question 1 year ago on Introduction

Hi Fernando,
thanks for the very helpful and compact explanation of the MCPWM unit of the ESP32.
I have to measure the distance of 2 independent signals, trying to use the capture functionality. Should work with highest possible resolution. What I'm trying to do ....
1.) prescaler crystal clock / 2 = 20MHz ( input clock for MCPWM )
2.) set duty to 50% ( because I do not need PWM functionality )
3.) activate CAP0 and CAP1 to capture on pos edge
4.) create ISR to do required calculations
At the moment it sucks already with MCPWM clock setting .... 1MHz is possible ... not more. Based on the information out of the data sheet it should work up to crystal clock / 2 ... as long duty is 50% fix.

I modified your code to try out the limit ( watch serial output ).
As long the MCPWM unit is not running with expected clock speed, it makes no sense to think about capture ... would like to set it up step by step .... to get a working platform for the next step .....
In the past I made similar things with BeagleBone ( PRU Units ) and MSP430, this is my first little project with ESP32. Up to now it's really great.
What do you think? Did I forget anything?
Thanks in advance
Pepito

The modified code:
/* *************************************************************** */
#include <Arduino.h> //Não é necessário caso use Arduino IDE
#include "driver/mcpwm.h" //inclui a biblioteca "Motor Control PWM" nativa do ESP32
// #include <Wire.h> // Necessário apenas para o Arduino 1.6.5 e posterior
// #include "SSD1306.h" // o mesmo que #include "SSD1306Wire.h"

//OLED_SDA -- GPIO4
//OLED_SCL -- GPIO15
//OLED_RST -- GPIO16

// #define SDA 4
// #define SCL 15
// #define RST 16

// SSD1306 display(0x3c, SDA, SCL, RST); //Instanciando e ajustando os pinos do objeto "display"

#define GPIO_PWM0A_OUT 12 //Declara GPIO 12 como PWM0A
#define GPIO_PWM0B_OUT 14 //Declara GPIO 14 como PWM0B
static uint32_t frequenz;

//Função que configura o MCPWM operador A (Unidade, Timer, Porcentagem (ciclo de trabalho))
static void brushed_motor_forward(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num , float duty_cycle)
{
//mcpwm_set_signal_low(unidade PWM(0 ou 1), Número do timer(0, 1 ou 2), Operador (A ou B)); => Desliga o sinal do MCPWM no Operador B (Define o sinal em Baixo)
mcpwm_set_signal_low(mcpwm_num, timer_num, MCPWM_OPR_B);

//mcpwm_set_duty(unidade PWM(0 ou 1), Número do timer(0, 1 ou 2), Operador (A ou B), Ciclo de trabalho (% do PWM)); => Configura a porcentagem do PWM no Operador A (Ciclo de trabalho)
mcpwm_set_duty(mcpwm_num, timer_num, MCPWM_OPR_A, duty_cycle);

//mcpwm_set_duty_tyoe(unidade PWM(0 ou 1), Número do timer(0, 1 ou 2), Operador (A ou B), Nível do ciclo de trabalho (alto ou baixo)); => define o nível do ciclo de trabalho (alto ou baixo)
mcpwm_set_duty_type(mcpwm_num, timer_num, MCPWM_OPR_A, MCPWM_DUTY_MODE_0);
//Nota: Chame essa função toda vez que for chamado "mcpwm_set_signal_low" ou "mcpwm_set_signal_high" para manter o ciclo de trabalho configurado anteriormente
}

//Função que configura o MCPWM Do operador B (Unidade, Timer, Porcentagem (ciclo de trabalho))
static void brushed_motor_backward(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num , float duty_cycle)
{
mcpwm_set_signal_low(mcpwm_num, timer_num, MCPWM_OPR_A); //Desliga o sinal do MCPWM no Operador A (Define o sinal em Baixo)
mcpwm_set_duty(mcpwm_num, timer_num, MCPWM_OPR_B, duty_cycle); //Configura a porcentagem do PWM no Operador B (Ciclo de trabalho)
mcpwm_set_duty_type(mcpwm_num, timer_num, MCPWM_OPR_B, MCPWM_DUTY_MODE_0); //define o nível do ciclo de trabalho (alto ou baixo)
}

//Função que para o MCPWM de ambos os Operadores
static void brushed_motor_stop(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
{
mcpwm_set_signal_low(mcpwm_num, timer_num, MCPWM_OPR_A); //Desliga o sinal do MCPWM no Operador A
mcpwm_set_signal_low(mcpwm_num, timer_num, MCPWM_OPR_B); //Desliga o sinal do MCPWM no Operador B
}

void setup() {
Serial.begin(115200);

// display.init();

//display.flipScreenVertically(); //Vira a tela verticalmente
// display.clear();
//ajusta o alinhamento para a esquerda
// display.setTextAlignment(TEXT_ALIGN_LEFT);
//ajusta a fonte para Arial 16
// display.setFont(ArialMT_Plain_16);

//mcpwm_gpio_init(unidade PWM 0, saida A, porta GPIO) => Instancia o MCPWM0A no pino GPIO_PWM0A_OUT declarado no começo do código
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT);

//mcpwm_gpio_init(unidade PWM 0, saida B, porta GPIO) => Instancia o MCPWM0B no pino GPIO_PWM0B_OUT declarado no começo do código
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, GPIO_PWM0B_OUT);

mcpwm_config_t pwm_config;

pwm_config.frequency = 2000; //frequência = 500Hz,
pwm_config.cmpr_a = 0; //Ciclo de trabalho (duty cycle) do PWMxA = 0
pwm_config.cmpr_b = 0; //Ciclo de trabalho (duty cycle) do PWMxb = 0
pwm_config.counter_mode = MCPWM_UP_COUNTER; //Para MCPWM assimetrico
pwm_config.duty_mode = MCPWM_DUTY_MODE_0; //Define ciclo de trabalho em nível alto
//Inicia(Unidade 0, Timer 0, Config PWM)
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //Define PWM0A & PWM0B com as configurações acima
frequenz = 10000; // Initialwert
}

void loop() {
// uint32_t frequenz;
float duty;
uint8_t tmp[4];
frequenz = frequenz + 10000;

mcpwm_set_frequency(MCPWM_UNIT_0, MCPWM_TIMER_0, frequenz);
//Move o motor no sentido horário
brushed_motor_forward(MCPWM_UNIT_0, MCPWM_TIMER_0, 50.0);
// oled("50");
frequenz = mcpwm_get_frequency(MCPWM_UNIT_0, MCPWM_TIMER_0);
tmp[0] = frequenz >> 24;
tmp[1] = frequenz >> 16;
tmp[2] = frequenz >> 8;
tmp[3] = frequenz;
// sprintf( tmp, "%u",frequenz); // causes problems
Serial.print(tmp[0],HEX);
Serial.print(tmp[1],HEX);
Serial.print(tmp[2],HEX);
Serial.print(tmp[3],HEX);
Serial.print(" ");
Serial.print(frequenz,DEC);
Serial.println("Hz");
duty = mcpwm_get_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A);
Serial.print("A: ");
Serial.print(duty);
Serial.println("%");
duty = mcpwm_get_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B);
Serial.print("B: ");
Serial.print(duty);
Serial.println("%");

delay(2000);
/*
//Para o motor
brushed_motor_stop(MCPWM_UNIT_0, MCPWM_TIMER_0);
// oled("0");
delay(2000);

//Move o motor no sentido antihorário
brushed_motor_backward(MCPWM_UNIT_0, MCPWM_TIMER_0, 25.0);
// oled("25");
delay(2000);

//Para o motor
brushed_motor_stop(MCPWM_UNIT_0, MCPWM_TIMER_0);
// oled("0");
delay(2000);

// Aceleracao i de 1 a 100
for(int i=10;i<=100;i++){
brushed_motor_forward(MCPWM_UNIT_0, MCPWM_TIMER_0, i);
// oled(String(i));
delay(200);
}

// Desaceleração i de 100 a 1
delay(5000);
for(int i=100;i>=10;i--){
brushed_motor_forward(MCPWM_UNIT_0, MCPWM_TIMER_0, i);
// oled(String(i));
delay(100);
}
delay(5000);
*/
}