Contrôle moteur CC par PWM

Bonjour bonjour,

Dans l'optique de commander deux moteurs CC (12V), j'utilise la carte moteur DFRobot (neuve).
http://www.dfrobot.com/wiki/index.php/DC_Motor_Driver_2x15A_Lite_(SKU:_DRI0018)

Cette carte est commandée par deux sorties PWM provenant d'un Arduino Micro (pin 9 & 13).

Or, lorsque je règle ma consigne PWM à 50% (128), la tension mesurée aux bornes de mes moteurs est largement supérieure aux 6V "théoriques". Et il en est de même pour le reste des mesures ... Les moteurs sont alimentés à la tension batterie à partir de pwm=100.

Tout cela me pose des problèmes pour mettre en place une régulation.

Est-ce normal ? Une idée sur la cause de cette erreur de mesure ?

Merci d'avance !

pierre-guillon:
Or, lorsque je règle ma consigne PWM à 50% (128), la tension mesurée aux bornes de mes moteurs est largement supérieure aux 6V "théoriques". Et il en est de même pour le reste des mesures ... Les moteurs sont alimentés à la tension batterie à partir de pwm=100.

Tout cela me pose des problèmes pour mettre en place une régulation.

Bonsoir
ta question n'est pas claire
je crois que tu n'a pas compris le principe du PWM.
Si tes moteurs sont alimentés en 12V , la tension aux bornes de tes moteurs sera toujours de 0 ou 12V, c'est le rapport cyclique qui change.
Ton voltmetre integre et voit ce qu'il a envie de voir en fonction de ses caracteristiques propres :grin:

pour le PWM voir
http://eskimon.fr/237-arduino-403-et-les-sorties-analogiques-enfin-presque

Bonsoir,
Si le voltmètre est configuré en mesure continu il donnera la valeur moyenne du signal d'alimentation du moteur. Si le rapport cyclique est de 50% la tension moyenne pour une tension max de 12V doit être de 6V, non ?

Moi ce que je ne comprend pas dans le préambule de la question c'est [Les moteurs sont alimentés à la tension batterie à partir de pwm=100]. pourquoi pwm 100% pour une alimentation ? A priori j'ai cru comprendre que la carte de droite doit être alimenteé sous 12V bornier du milieu en haut.

Ma commande PWM est en 8bit (0-255)
La tension max d'alimentation que je peux fournir au moteur est celle que me délivre ma batterie, soit 12V.
Je commande la carte moteur via deux ports (9 et 13) de la carte Arduino Micro avec une plage entre 0 et 255 pour chacun des deux moteurs (avec les PINS EN 0/1 pour les sens de rotation).
Théoriquement si je commande 255, je doit avoir un rapport cyclique de 1 avec 12V aux bornes de mes moteurs. Si je commande à 127 je devrais avoir un rapport cyclique de 0.5 avec 6V en vision DC avec mon Voltmètre aux bornes de mes moteurs. Or le fait est que si je commande à 127, j'obtient réélement 11V environ aux bornes des MO..

Nota : la carte Moteur accepte les tension de 0-35V. Les résultats sont les mêmes avec une alimentation à 24V (22V pour 127).

Cela peut-il éventuellement provenir de la fréquence de commande en PWM entre la Micro et la carte Moteur ? (Cette dernière accepte jusqu'à 25kHz en Input). ??

Merci de vos réponses !

:slight_smile:

pierre-guillon:
...
Théoriquement si je commande 255, je doit avoir un rapport cyclique de 1 avec 12V aux bornes de mes moteurs. Si je commande à 127 je devrais avoir un rapport cyclique de 0.5 ]avec 6V en vision DC avec mon Voltmètre aux bornes de mes moteurs. Or le fait est que si je commande à 127, j'obtient réélement 11V environ aux bornes des MO..

Peut etre bien que oui, peut etre bien que non ! :grin:

Ce que tu lis depend des seules caraceristiques de ton voltmetre , et surtout de ses capacités à integrer le "PWM"
toutes les lectures entre 0 et 12V sont possibles, aucune ne sera fausse, mais aucune ne sera réelle 8)

Artouste:
Peut etre bien que oui, peut etre bien que non ! :grin:

Ce que tu lis depend des seules caraceristiques de ton voltmetre , et surtout de ses capacités à integrer le "PWM"
toutes les lectures entre 0 et 12V sont possibles, aucune ne sera fausse, mais aucune ne sera réelle 8)

Je comprends bien ce que tu me dis, l'utilisation de 2 Voltmètres différents m'ont donnés les mêmes indications et me permettent "d'imager" mon problème. Le fait est que le moteur tourne effectivement à sa vitesse casi-max avec une commande à 127 (Mesuré avec un codeur incrémental).
Pour 255 => 0.50 m/s
Pour 127 => 0.50 m/s
=> D'où la mesure avec le voltmètre.

pierre-guillon:

Artouste:
Peut etre bien que oui, peut etre bien que non ! :grin:

Ce que tu lis depend des seules caraceristiques de ton voltmetre , et surtout de ses capacités à integrer le "PWM"
toutes les lectures entre 0 et 12V sont possibles, aucune ne sera fausse, mais aucune ne sera réelle 8)

Je comprends bien ce que tu me dis, l'utilisation de 2 Voltmètres différents m'ont donnés les mêmes indications et me permettent "d'imager" mon problème. Le fait est que le moteur tourne effectivement à sa vitesse casi-max avec une commande à 127 (Mesuré avec un codeur incrémental).
Pour 255 => 0.50 m/s
Pour 127 => 0.50 m/s
=> D'où la mesure avec le voltmètre.

utilise le juge de paix :grin:
un "petit" oscillo 2 voies
Voie A sur la sortie PWM du MCU (2V/div)
Voie B aux bornes du moteur (5V/div)
et regarde le comportement des signaux

Moi pauvre peau-rouge, moi pas avoir oscilloscope!

Mais Excel, avec lequel les courbes suivantes sont tracées (en PJ). Et on voit bien que la différence entre une commande de 255 et de 127 est ridicule ...

pierre-guillon:
Moi pauvre peau-rouge, moi pas avoir oscilloscope!

Mais Excel, avec lequel les courbes suivantes sont tracées (en PJ). Et on voit bien que la différence entre une commande de 255 et de 127 est ridicule ...

Peut etre que oui, peut etre que non :grin:
les valeurs injectées dans ton graphe son issues d'où ?
les axes correspondent à quoi ?

bonjour,
j'ai du merdouiller tout à l'heure en postant.
si tu montrais ton code déjà :wink:

les valeurs injectées dans ton graphe son issues d'où ?

Elles proviennent de la mesure de vitesse issue des encodeurs rotatifs positionnés sur des roues folles.

les axes correspondent à quoi ?

L'axe x est le temps (par pas de 50ms)
L'axe y est la vitesse linéaire de la roue codeuse (en m/s)

si tu montrais ton code déjà smiley-wink

  //#include <SimpleTimer.h>
#include <HTCL2032.h>
#include "stdio.h"
#include "stdlib.h"
#include <math.h>
#include <avr/interrupt.h>
/* ======================================================
CONSTANTES et BROCHES
==========================================================*/
//GENERAL
#define TEMPS_ECHANTILLONAGE_REGULATION 50 //ms
//DIMENSIONS
#define MM_TICK				0.138		//Le nombre de mm pour 1 tick 
#define RRoueCodeuse		263 //mm
//ENCODEURS
#define X 0			//Encodeur Droit
#define Y 1			// Encodeur Gauche
// MOTEUR
#define M1_PWMN  9     //M1_EN Speed Control
#define M2_PWMN  13     //M2_EN Speed Control
#define M1_EN  0     //M1_EN Direction Control
#define M2_EN  1     //M2_EN Direction Control

/* ======================================================
DECLARATION STRUCTURES
==========================================================*/
typedef struct
{
	long gauche;
	long droit;
	long oldDroit;
	long oldGauche;
} Encodeur;

typedef struct
{
    float reelleD;
	float reelleG;
} Vit;


typedef struct
{
	unsigned long tempsOld;
	unsigned long temps;
}		TempoMillis;

/* ======================================================
VARIABLES GLOBALES
==========================================================*/
Encodeur encodeur;
TempoMillis tempoMillis;
Vit vitesse;




/* ======================================================
FONCTIONS
==========================================================*/
void stop(void)                    //Stop
{
  digitalWrite(M1_PWMN,0);
  digitalWrite(M1_EN,LOW);   
  digitalWrite(M2_PWMN,0);  
  digitalWrite(M2_EN,LOW);   
}  
void advanceG(char a)          //Move forward
{
  analogWrite (M1_PWMN,a);
  digitalWrite(M1_EN,LOW);  
} 
void advanceD(char b)          //Move forward
{ 
  analogWrite (M2_PWMN,b);   
  digitalWrite(M2_EN,LOW);
} 
void back_offG (char a)          //Move backward
{
  analogWrite (M1_PWMN,a);      //PWM Speed Control
  digitalWrite(M1_EN,HIGH);   
}
void back_offD (char b)          //Move backward
{ 
  analogWrite (M2_PWMN,b);   
  digitalWrite(M2_EN,HIGH);
}


/* ======================================================
SETUP
==========================================================*/ 
void setup(void)
{
//----------------DEBUG MODE------------------
Serial.begin(9600);
delay(100);
//----------------------------------------------
 
  //IO
  pinMode(M1_PWMN, OUTPUT); 
  pinMode(M1_EN, OUTPUT); 
  pinMode(M2_PWMN, OUTPUT); 
  pinMode(M2_EN, OUTPUT); 
  digitalWrite(M1_PWMN,LOW);  
  digitalWrite(M2_PWMN,LOW);
  //INIT
  init_hctl ( );
}
/* ======================================================
LOOP
==========================================================*/  
void loop(void)
{
	
	delay(5000);
        advanceD(127);
        advanceG(127);

        lecture();
	
}

void lecture()                  
{
  	do
	{
		tempoMillis.temps=millis();
		if((tempoMillis.temps-tempoMillis.tempsOld)>=TEMPS_ECHANTILLONAGE_REGULATION)
		{
			        feedback();


			tempoMillis.tempsOld=tempoMillis.temps;
		}
	}while(1);
}  

void feedback()                  
{
// Sauvegarde des anciennes valeurs des encodeurs
	encodeur.oldDroit=encodeur.droit;
	encodeur.oldGauche=encodeur.gauche;
// Récupérer la valeur des codeurs
	hctl_Query(X); 
	hctl_Query(Y);

	// Calculer la vitesse D et G en mm
	vitesse.reelleD=((encodeur.droit-encodeur.oldDroit)*MM_TICK)/TEMPS_ECHANTILLONAGE_REGULATION;
	vitesse.reelleG=((encodeur.gauche-encodeur.oldGauche)*MM_TICK)/TEMPS_ECHANTILLONAGE_REGULATION;


	// Debug
	//Serial.print("VD : ");// Mesure en mm/ms
//Serial.print(i);
//	Serial.print("\t");	
        //Serial.print(vitesse.reelleD);
	//Serial.print("\t");
	//Serial.print("VG : ");
	Serial.println( (vitesse.reelleG+vitesse.reelleD)/2 );
}


/* ======================================================
FONCTIONS SUPPORT
==========================================================*/  
/*------------------------------------------------------------------------------
Fonction : hctl_Query
Description : Permet de mettre à jour la valeur de l'encodeur demandé
Argument :	channel --> Encodeur Droit ou encodeur Gauche
Retour :
--------------------------------------------------------------------------------*/
void hctl_Query ( int channel )
{
	long data = 0;
	int i;
	
	digitalWrite(PIN_X_Y, channel); //Selection de la voie
	delay (1);

	digitalWrite(PIN_OE,LOW); //Demande de lecture
	delay (1);

	//DEBUT LECTURE

	// lecture de MSB
	digitalWrite(PIN_SEL1, LOW);
	digitalWrite(PIN_SEL2, HIGH);

	for( i = 7 ; i > -1 ; i-- )
	{
		data += digitalRead ( tabPinDataHCTL[i] ) ;
		data = data << 1;
	}

	// lecture du 3eme bytes
	digitalWrite(PIN_SEL1, HIGH);

	for( i = 7 ; i > -1 ; i-- )
	{
		data += digitalRead ( tabPinDataHCTL[i] ) ;
		data = data << 1;
	}

	// lecture du 2eme bytes
	digitalWrite(PIN_SEL1, LOW);
	digitalWrite(PIN_SEL2, LOW);

	for( i = 7 ; i > -1 ; i-- )
	{
		data += digitalRead ( tabPinDataHCTL[i] ) ;
		data = data << 1;
	}

	// lecture de LSB
	digitalWrite(PIN_SEL1, HIGH);
	digitalWrite(PIN_SEL2, LOW);

	for( i = 7 ; i > 0 ; i-- )
	{
		data += digitalRead ( tabPinDataHCTL[i] ) ;
		data = data << 1;
	}

	data += digitalRead ( PIN_D0 ) ;

	digitalWrite(PIN_OE,HIGH); //Arret lecture

	//FIN DE LECTURE

	if ( channel == X )//voie X
	{
		encodeur.droit = data ;
	}
	else //voie Y
	{
		encodeur.gauche = data ;
	}
}

/*------------------------------------------------------------------------------
Fonction : init_hctl
Description : Initialise le compteur_decompteur incrémental
Argument :	
Retour :
--------------------------------------------------------------------------------*/
void init_hctl ()
{
 tabPinDataHCTL[0] = PIN_D0;
 tabPinDataHCTL[1] = PIN_D1;
 tabPinDataHCTL[2] = PIN_D2;
 tabPinDataHCTL[3] = PIN_D3;
 tabPinDataHCTL[4] = PIN_D4;
 tabPinDataHCTL[5] = PIN_D5;
 tabPinDataHCTL[6] = PIN_D6;
 tabPinDataHCTL[7] = PIN_D7;
// Serial.println(tabPinDataHCTL[7]); 

  //Codeur incrémental et compteur
  pinMode(PIN_D0, INPUT);
  pinMode(PIN_D1, INPUT);
  pinMode(PIN_D2, INPUT);
  pinMode(PIN_D3, INPUT);
  pinMode(PIN_D4, INPUT);
  pinMode(PIN_D5, INPUT);
  pinMode(PIN_D6, INPUT);
  pinMode(PIN_D7, INPUT);
  pinMode(PIN_RSTNX, OUTPUT);
  pinMode(PIN_RSTNY, OUTPUT);
  pinMode(PIN_OE, OUTPUT);
  pinMode(PIN_SEL1, OUTPUT);
  pinMode(PIN_SEL2, OUTPUT);
  pinMode(PIN_X_Y, OUTPUT);
  /*pinMode(PIN_TEST, OUTPUT);
  pinMode(PIN_U_DX, INPUT);
  pinMode(PIN_U_DY, INPUT);*/
  reset_hctl(X);
  reset_hctl(Y);
  encodeur.droit=0;
  encodeur.gauche=0;
  encodeur.oldDroit=0;
  encodeur.oldGauche=0;

}
/*------------------------------------------------------------------------------
Fonction : reset_hctl_X
Description : Reset les deux voies
Argument :	
Retour :
--------------------------------------------------------------------------------*/
void reset_hctl (int channel)
{
  if ( channel == X  )	  //X = DROIT	
  {
	  //Serial.println("ResetX");
	  digitalWrite ( PIN_RSTNX, LOW );
	  delay ( 5 );
	  digitalWrite ( PIN_RSTNX, HIGH );
	  delay ( 5 );
	  encodeur.droit=0;
  }else if (channel == Y) 
  {
	  //Serial.println("ResetY");
	  digitalWrite ( PIN_RSTNY, LOW );
	  delay ( 5 );
	  digitalWrite ( PIN_RSTNY, HIGH );
	  delay ( 5 );
	  encodeur.gauche=0;
  }
  //Configuration du mode de l
// digitalWrite(PIN_EN1, HIGH);
  //delay (25);
  //digitalWrite(PIN_EN2, HIGH); //lecture mode 4X
  //delay (25);
}

soit j'ai de la merdouille dans les yeux soit ca correspond en rien au schéma du début

// MOTEUR
#define M1_PWMN  9     //M1_EN Speed Control
#define M2_PWMN  13     //M2_EN Speed Control
#define M1_EN  0     //M1_EN Direction Control
#define M2_EN  1     //M2_EN Direction Control

pin 0 -1 c'est les analog?

pourquoi ne pas faire comme sur le schéma démo?

pierre-guillon:

les valeurs injectées dans ton graphe son issues d'où ?

Elles proviennent de la mesure de vitesse issue des encodeurs rotatifs positionnés sur des roues folles.

Oui mais qui te dit que FréquenceDeRotation = f(PWM) est une linéaire ? Et je peux déjà te donner la réponse: non :slight_smile:

La vitesse de rotation n'est pas non plus linéaire en fonction de la tension d'alimentation (en considérant simplement un moteur à vide).

Tension = f(PWM) --> devrait être linéaire non ?
FrequenceDeRotation = f(Tension) --> non linéaire (caractéristiques du moteur).

Mon problème est sur la 1ere relation.

pourquoi ne pas faire comme sur le schéma démo?

Voici le code basique correspondant au schéma du début. Mêmes résultats ...

int M1_PWM = 5; //M1 Speed Control
int M2_PWM = 6; //M2 Speed Control
int M1 = 4; //M1 Direction Control
int M2 = 7; //M1 Direction Control
int counter=0;
void stop(void) //Stop
{
digitalWrite(M1_PWM,0);
digitalWrite(M1,LOW);
digitalWrite(M2_PWM,0);
digitalWrite(M2,LOW);
}
void advance(char a,char b) //Move forward
{
analogWrite (M1_PWM,a); //PWM Speed Control
digitalWrite(M1,LOW);
analogWrite (M2_PWM,b);
digitalWrite(M2,LOW);
}
void back_off (char a,char b) //Move backward
{
analogWrite (M1_PWM,a);
digitalWrite(M1,HIGH);
analogWrite (M2_PWM,b);
digitalWrite(M2,HIGH);
}


void setup(void)
{
  
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);

digitalWrite(M1_PWM,LOW);
digitalWrite(M2_PWM,LOW);

}
void loop(void)
{
  advance(255,255);
  delay(10000);
  stop();
  delay(1000);
  back_off(127,127);
  delay(10000);
  
}

pierre-guillon:
Tension = f(PWM) --> devrait être linéaire non ?
FrequenceDeRotation = f(Tension) --> non linéaire (caractéristiques du moteur).

Mon problème est sur la 1ere relation.

Oui mais la mesure au voltmètre d'un PWM, comme évoqué c'est très dépendant du voltmètre. Le mieux pour en avoir le coeur net c'est de mettre un circuit RC dessus pour lisser et tu verras ce que ça donne.

Ensuite comment as-tu fait ta mesure ? As-tu regardé côté sortie de l'Arduino directement ?

Côté arduino, sur un cycle à 0.5 la sortie est à 2.4V environ et à 4.9V sur un cycle de 1 (ce qui semblerait cohérent !?).

Jusqu'ici oui, preuve que le PWM en lui-même fonctionne bien :wink:

Côté carte c'est plus compliqué, avec l'inductance du moteur notamment. Pour moi tout ton problème semble lié aux caractéristiques du moteur tout simplement. Il tourne dans le vide ?

Je ne pense pas ... Ce sont des moteurs Maxon (2ans d'âge) amax26g_gp026b http://store.mdpmotor.fr/amax26g-gp026b-1267.html

On a testé avec d'autres moteurs, ça donne pareil!

Pour info, même si celà n'a pas entièrement résolu le problème, le point suivant a contribué à le rendre "acceptable".

En changeant la fréquence du PWM de sortie de la PIN PWM de l'arduino (jusqu'à 16kHz), nous avons obtenus une plage d'utilisation du moteur plus importante et une variation de tension aux bornes de ce dernier et de vitesse meilleure que celle obtenu avant la modification. Le problème doit plus ou moins résider dans la fréquence du PWM minimal et nécessaire pour piloter au mieux le moteur CC.

En espérant que ces nouvelles infos puissent aider d'autres personnes qui pourraient rencontrer des difficultés similaires.