Bonjour,
je suis en train de réaliser une tourelle motorisée avec moteurs pap unipolaires et controleurs ULN2003, commandée via un autre arduino avec joystick et une liaison xbee (série),
la liaison série se passe bien, j'envoi la commande de vitesse entre 0 et 100 et un bit pour le sens.
Seulement, le moteur pas a pas ne prend pas ses tours, comme s'il manquait une phase, ou la commande qui ne serait pas continu,
j'ai donc essayé une autre librairie (accelStepper) et j'ai toujours les mêmes soucis.
J'ai essayé un programme de test fournis par AccelStepper (Nommé bounce) et la aucun souci, le moteur accélère comme il faut et se comporte parfaitement.
Voici ci-dessous mon code coté tourelle, si vous voyer quelque chose qui vous choque ?
// ianoo, camturret-base v13-07-15.
#include <AccelStepper.h>
//#include <IRremote.h>
//IRsend irsend;
// indiquer ici le N° de la tourelle :
int adresse = 1;
AccelStepper tilt(4, 6, 8, 7, 9); //Phases inversées pour que cela fonctionne correctement
AccelStepper pan(4, 10, 12, 11, 13);
int idcam;
int zoom;
int dezoom;
int senstilt;
int speedtilt;
int senspan;
int speedpan;
int RevTilt = 1;
int RevPan = 1;
void setup() {
Serial.begin(9600);
Serial1.begin(9600); // Prévu pour un dfRobot léonardo avec deux ports séries, Serial1 étant le Xbee)
tilt.setMaxSpeed(600);
tilt.setSpeed(0);
pan.setMaxSpeed(600);
pan.setSpeed(0);
}
void loop() {
// Si des données arrivent par la liaison série:
while (Serial1.available()>0) {
// Des qu'on lit le caractere < on ecris chaque entier dans une variable
if (Serial1.read() == '<') {
idcam = Serial1.parseInt();
zoom = Serial1.parseInt();
dezoom = Serial1.parseInt();
senstilt = Serial1.parseInt();
speedtilt = Serial1.parseInt();
senspan = Serial1.parseInt();
speedpan = Serial1.parseInt();
}
}
// Si les donnees séries sont bien adressées a cette tourelle
//if (idcam == adresse) {
// Gestion du moteur haut/bas
if (senstilt == 1) {
RevTilt = 1;
}
else{
RevTilt = -1 ;
}
if (speedtilt > 2) { // gestion de la deadband, on commande le moteur si la valeur est au dessus de 2
tilt.setSpeed(speedtilt * 5 * senstilt);
tilt.runSpeed();
}
// Gestion du moteur gauche/droite
if (senspan == 1) {
senspan = 1;
}
else{
senspan = -1;
}
if (speedpan > 2) {
pan.setSpeed(speedpan * 5 * senspan);
pan.runSpeed();
}
// Gestion du zoom
//if (zoom == 0) {
// for (int i = 0; i < 3; i++) {
// irsend.sendNEC(0xA16E0CF3, 32); // Canon TV power code, a remplacer par la bonne valeur pour le zoom
// delay(40);
// }
//}
//if (dezoom == 0) {
// for (int i = 0; i < 3; i++) {
// irsend.sendNEC(0xA16E0CF3, 32); // Canon TV power code
// delay(40);
// }
//}
//}
}
EDIT: je viens de modifier une partie du code, j'avais laissé des valeurs de test pas forcément cohérentes.
Pour ma part j'ai réussi à limiter les saccades en retournant à la librairie série d'arduino et en jouant sur les valeurs pas par tour, vitesse et nbre de pas commandés...
Mais ce n'est toujours pas aussi fluide que lorsque la commande est fixe (nbre de pas prédéfinis), certainement un souci avec la liaison série, ou une mauvaise gestion du moteur en mode commande par vitesse, quelqu'un a t'il déja résolu ce genre de souci ?
Je viens de me rendre compte qu'une partie du problème vient du fait que j'ai deux moteurs pap, et que lorsque je commande les deux en même temps cela cré des saccades du fait que le programme fait une pause lors de la commande de l'un des moteurs, le 2nd est donc a l’arrêt le temps que le 1er termine sa course...
c'est ce que j'ai voulu faire sur mon code avec la librairie stepper d'arduino, mais pas fabuleux.
Depuis, je me suis pris un contrôleur en i2c d'adafruit, pensant qu'il suffirait d'envoyer la commande une fois et que cela ne bloquerait pas le programme, erreur ! ça ne marche pas comme ça
j'ai donc cumulé :
le shield adafruit :Adafruit Motor/Stepper/Servo Shield for Arduino v2 Kit [v2.3] : ID 1438 : $19.95 : Adafruit Industries, Unique & fun DIY electronics and kits
avec la librairie AccelStepper,
puis en amont j'ai arrêté d'envoyer les valeurs en continu sur le port série, j'envoi la trame de valeur uniquement quand l'une d'entre elle a changée,
de plus je ne commande plus en vitesse, je commande en position ! je pars de la position 0 et j'y ajoute la valeur du joystick (de 0 a 100) et une fois a position, j'ajoute la valeur du joystick a la valeur de la position actuelle, sa marche super, sans acoup, mais qu'est ce que c'est lent !
visiblement j'ai beau mettre de très grosses valeurs de vitesse max et accélération, ça se lambine
si quelqu'un avait une explication, voir une solution, ce serait super !
// ianoo, camturret-base v25-07-5.
#include <AccelStepper.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
#include <IRremote.h>
IRsend irsend;
// indiquer ici le N° de la tourelle :
int adresse = 1;
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_StepperMotor *tilt = AFMS.getStepper(4000, 1);
Adafruit_StepperMotor *pan = AFMS.getStepper(4000, 2);
void forwardstep1() {
tilt->onestep(FORWARD, SINGLE);
}
void backwardstep1() {
tilt->onestep(BACKWARD, SINGLE);
}
// wrappers for the second motor!
void forwardstep2() {
pan->onestep(FORWARD, SINGLE);
}
void backwardstep2() {
pan->onestep(BACKWARD, SINGLE);
}
AccelStepper tilt1(forwardstep1, backwardstep1);
AccelStepper pan1(forwardstep2, backwardstep2);
int idcam;
int zoom;
int dezoom;
int senstilt;
int speedtilt;
int senspan;
int speedpan;
int RevTilt;
int RevPan;
int postilt = 0;
int pospan = 0;
void setup() {
Serial.begin(9600);
Serial1.begin(9600); // Prévu pour un dfRobot léonardo avec deux ports séries, Serial1 étant le Xbee)
AFMS.begin();
tilt1.setMaxSpeed(1000);
tilt1.setAcceleration(10000);
tilt1.moveTo(0);
pan1.setMaxSpeed(1000);
pan1.setAcceleration(10000);
pan1.moveTo(0);
}
void loop() {
// Si des données arrivent par la liaison série:
while (Serial1.available() > 0) {
// Des qu'on lit le caractere < on ecris chaque entier dans une variable
if (Serial1.read() == '<') {
idcam = Serial1.parseInt();
zoom = Serial1.parseInt();
dezoom = Serial1.parseInt();
senstilt = Serial1.parseInt();
speedtilt = Serial1.parseInt();
senspan = Serial1.parseInt();
speedpan = Serial1.parseInt();
}
}
// Si les donnees séries sont bien adressées a cette tourelle
if (idcam == adresse) {
// Gestion du moteur haut/bas
if (senstilt == 1) {
RevTilt = 1;
}
else{
RevTilt = -1 ;
}
if (speedtilt > 10) { // gestion de la deadband, on commande le moteur si la valeur est au dessus de 2
if (tilt1.distanceToGo() == 0){
postilt = RevTilt * speedtilt /10 + postilt;
tilt1.moveTo(postilt);
}
}
// Gestion du moteur gauche/droite
if (senspan == 1) {
RevPan = 1;
}
else{
RevPan = -1;
}
if (speedpan > 10) {
if (pan1.distanceToGo() == 0){
pospan = RevPan * speedpan /10 + pospan;
pan1.moveTo(pospan);
}
}
// Gestion du zoom
//if (zoom == 0) {
// for (int i = 0; i < 3; i++) {
// irsend.sendNEC(0xA16E0CF3, 32); // Canon TV power code, a remplacer par la bonne valeur pour le zoom
// delay(40);
// }
//}
//if (dezoom == 0) {
// for (int i = 0; i < 3; i++) {
// irsend.sendNEC(0xA16E0CF3, 32); // Canon TV power code
// delay(40);
// }
//}
}
tilt1.run();
pan1.run();
// Données pour le moniteur série
Serial.print(idcam);
Serial.print(",");
Serial.print(zoom);
Serial.print(",");
Serial.print(dezoom);
Serial.print(",");
Serial.print(senstilt);
Serial.print(",");
Serial.print(speedtilt);
Serial.print(",");
Serial.print(senspan);
Serial.print(",");
Serial.print(speedpan);
Serial.print(",");
Serial.print(postilt);
Serial.print(",");
Serial.println(pospan);
delay(1);
}
Pour finir : j'ai essayé avec un servomoteur plutôt qu'un moteur pas à pas, c'est le jour et la nuit ! c'est plus simple a gérer , pas besoin de contrôleur, et surtout ça fait ce que je lui demande !
je laisse tomber le pas a pas, en tout cas pour ce projet ce n'est visiblement pas ce qu'il faut.