#141
Posté 02 mars 2018 - 08:52
Par contre il tremble beaucoup, il nest pas stable. Je vais essayé de recommencer le process plus sérieusement pour voir si ca réduit les vibrations.
Je peux aussi jouer sur le temps de computation, ca a lair de beaucoup jouer sur ce problème
#142
Posté 06 mars 2018 - 09:43
Bonjour à tous,
Je pense avoir atteint le mieux que je puisse faire pour la partie "Balancement". BurnBot tient vraiment bien à l'équilibre, j'ai amélioré sa stabilité, il ne tremble presque plus ![]()
Grâce au traceur j'ai pu me rendre plus fidèlement compte du comportement de mon PID et j'ai trouvé les bons paramètre que je vous partage ici :
Temps de computation : 5 ms
OutputLimits : -3000, 3000 (quasiment les valeurs max de mes moteurs pas à pas)
SetPoint : 0.2
Kp : 500
Ki : 15000
Kd : 0.8
Voici une petite vidéo encore pour illustrer tout ça :
Maintenant je me concentre sur comment le déplacer et comme je vous l'ai dit j'ai quelques difficultés sur ce point la. Pour le faire tourner à droite ou a gauche c'est facile, il me suffit de créer une différence entre la vitesse des deux moteurs. Comme vous pouvez le voir dans la vidéo ça marche plutôt bien, je vais juste créer un décalage plus important pour qu'il tourne plus vite.
Pour avancé et reculé c'est vraiment plus compliqué ! J'ai essayé en mettant +500 (par exemple) aux vitesses des deux moteurs, sauf que le robot compense tout seul en baissant la vitesse pour maintenir sa consigne d'équilibre (bah oui je l'ai trop bien conçu
).
Du coup l'idée que j'ai depuis le début c'est de jouer sur la consigne (setpoint). Là elle est à 0.2° (consigne d'équilibre) et pour moi si je la met à 10° le robot devrait se déplacer vers l'avant car il serait constamment entrain de tomber. Et pourtant comme vous pouvez le voir dans la vidéo, je l'incline à +10° et -10° et la seule chose qu'il fait s'est de se pencher sans reculer n'y avancer....
Est-ce les câbles qui l’empêche de bouger ou mon idée qui n'est carrément pas la bonne ? Pas facile en tout cas ![]()
#143
Posté 06 mars 2018 - 02:14
Ce sont les mêmes moteurs qui font avancer le robot et qui le maintiennent en équilibre.
C'est peut-être stupide ce que je vais dire, mais pour moi, il faut d'abord avancer puis rétablir l'équilibre.
Quand je dis avancer, je pense à 5° ou 10°.
Ma chaine YouTube : https://www.youtube..../oracid1/videos
#144
Posté 07 mars 2018 - 04:13
Bonjour à tous,
C'est bon, j'arrive en fin à faire déplacer BurnBot ! Mon idée de jouer sur le SetPoint de mon PID était bonne, il fallait juste qu'au lieu de passer radicalement d'une valeur à une autre (de 0 à 10° d'un coup par exemple), que j'incrémente/décrémente le Setpoint progressivement pour avoir un comportement souple (et non brusque).
Du coup ça marche plutôt bien comme vous pouvez le voir dans cette vidéo :
Bon pour le coup les cables gènes un peu et empêche d'avoir quelque chose de parfaitement fluide, et il faudrait que je peaufine un peu tout ça mais je suis satisfait du résultat.
J'ai encore travaillé/amélioré la stabilité du robot et j'ai vraiment un très bon comportement aux perturbations :
C'est ainsi que je pense clore mon expérience avec BrunBot
J'ai atteins tous les objectifs que je mettais fixé, je suis super satisfait du résultat et je ne souhaite pas pousser le robot plus loin pour l'instant. J'ai commandé de quoi faire un futur robot de type "Self balancing" que je détaillerais dans un autre post. Les objectifs seront de miniaturiser au maximum le robot, de le munir d'une batterie (plus aucun cable) et de le commander à distance grâce à une télécommande home made.
Voilà, BurnBot m'a permit de me familiariser avec les PID, les moteurs pas à pas, l'impression 3D et arduino en générale, je le retravaillerais surement un jour mais je préfère tourner mes futurs objectifs vers un robot encore plus efficaces, qui aura de plus une réelle fonction (autre que de rouler et tenir à l'équilibre) mais ça je vous en parlerez plus tard ![]()
PS : Je ferais surement une dernière vidéo ou je jouerais avec des parois inclinées, ou il franchira des obstacles etc...
#145
Posté 07 mars 2018 - 05:49
Super projet, mené à son terme !
Ma chaine YouTube : https://www.youtube..../oracid1/videos
#147
Posté 07 mars 2018 - 07:15
Moi, j'aimerais bien jeter un petit coup d'œil au code, complet... ![]()
Ma chaine YouTube : https://www.youtube..../oracid1/videos
#150
Posté 08 mars 2018 - 09:35
Pour ceux que ça intéresse ![]()
//Ce programme permet de régler le premier PID de BurnBot, je me suis rendu compte qu'il fonctionnait très bien avec seulement un PID pour le moment donc j'ai abandonné l'idée d'en combiner deux
#include "I2Cdev.h"
#include<Wire.h> // librairie pour le gyroscope
#include <PID_v1.h> // librairie pour le PID
#include "MPU6050_6Axis_MotionApps20.h" // librairie pour le gyroscope
#include <AccelStepper.h> // librairie pour les moteurs pas à pas
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu;
//MPU6050 mpu(0x69); // <-- use for AD0 high
float vitesse; //Vitesse des moteurs
int incomingByte = 0; //Byte utilisé dans le serial.read
char CharByte;
int Controle = 0; //Variable contenant l'instruction de direction
double i = 0; //Coefficient pour le controle du robot
int vit1 = 0; //Différence de vitesse pour faire tourner le robot
int vit2 = 0;
unsigned long temps = 0; //Variable utilisée dans certains calcul sur excel
AccelStepper roueD(1, 9, 6); //9 sortie digital avec laquelle on contrôle la vitesse, le 6 la même pour le sens de rotation.
AccelStepper roueG(1, 8, 5);
double Setpoint, Input, Output; //Variales du PID
double Kp=300, Ki=15000, Kd=1; //Coefficients du PID //500 600 2.85 //500 750 5 //450, 15000, 0.8 (valeur très correct)
float Pas3 = 0.1; //Variables permettant de régler le PID
float Pas2 = 5;
float Pas1 = 5;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); //Définition du PID
#define OUTPUT_READABLE_YAWPITCHROLL
#define ARDUINO_BOARD
#define LED_PIN 13 // (Galileo/Arduino is 13)
bool blinkState = false;
// MPU control/status vars
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
// orientation/motion vars
VectorFloat gravity; // [x, y, z] gravity vector
Quaternion q; // [w, x, y, z] quaternion container
float euler[3]; // [psi, theta, phi] Euler angle container
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
// ================================================================
// === INTERRUPT DETECTION ROUTINE ===
// ================================================================
// This function is not required when using the Galileo
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
mpuInterrupt = true;
}
// ================================================================
// === INITIAL SETUP ===
// ================================================================
void setup() {
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
int TWBR; // 400kHz I2C clock (200kHz if CPU is 8MHz)
TWBR = 24;
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
Serial.begin(115200);
while (!Serial);
// initialize device
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(F("MPU6050 connection "));
Serial.print(mpu.testConnection() ? F("successful") : F("failed"));
// wait for ready
Serial.println(F("\nSend any character to begin DMP programming and demo: "));
//while (Serial.available() && Serial.read()); // empty buffer
// while (!Serial.available()); // wait for data
// while (Serial.available() && Serial.read()); // empty buffer again
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(45); //A qualibrer avec l'autre programme pour l'offset du MPU
mpu.setYGyroOffset(38);
mpu.setZGyroOffset(29);
mpu.setZAccelOffset(1758); // 1688 factory default for my test chip
// make sure it worked (returns 0 if so)
if (devStatus == 0) {
// turn on the DMP, now that it's ready
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// enable Arduino interrupt detection
Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
attachInterrupt(0, dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
// set our DMP Ready flag so the main loop() function knows it's okay to use it
Serial.println(F("DMP ready! Waiting for first interrupt..."));
dmpReady = true;
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
// configure LED for output
pinMode(LED_PIN, OUTPUT);
roueD.setMaxSpeed(3500); // Vitesse max du moteur en nombre de pas par seconde
//roueD.setAcceleration(1000); //en step par seconde
roueG.setMaxSpeed(3500); // Vitesse max du moteur en nombre de pas par seconde
//roueG.setAcceleration(1000); //en step par seconde
vitesse = 0; //Initialisation de la vitesse à 0
Setpoint = 0.2; //Point d'équilibre parfait
myPID.SetMode(AUTOMATIC); //Initialisation du PID en mode automatique
myPID.SetOutputLimits(-3500, 3500); //définition des limites du PID
myPID.SetTunings(Kp, Ki, Kd); //Application des coefficients
myPID.SetSampleTime(5); //La computation est executé toutes les 5ms
delay(5000); //Delai de 5 seconde pour attendre que le MPU se calibre
}
// ================================================================
// === MAIN PROGRAM LOOP ===
// ================================================================
void loop() {
roueD.runSpeed();
roueG.runSpeed();
if (Serial.available() > 0) { //Changement Manuel des coefficients du PID + ordre de déplacement
incomingByte = Serial.read();
CharByte = incomingByte;
if (CharByte == 49)
{
Kp = Kp + Pas1;
}
if (CharByte == 50)
{
Kp = Kp - Pas1;
}
if (CharByte == 52)
{
Ki = Ki + Pas2;
}
if (CharByte == 53)
{
Ki = Ki - Pas2;
}
if (CharByte == 55)
{
Kd = Kd + Pas3;
}
if (CharByte == 56)
{
Kd = Kd - Pas3;
}
if (CharByte == 122)
{
Controle = 1; //avant
}
if (CharByte == 115)
{
Controle = 2; //arrière
}
if (CharByte == 113)
{
Controle = 4; //droite
}
if (CharByte == 100)
{
Controle = 3; //gauche
}
if (CharByte == 97)
{
Controle = 0; //rien faire
}
//Serial.println(incomingByte);
myPID.SetTunings(Kp, Ki, Kd); //On applique les nouveau coefficients
roueD.runSpeed();
roueG.runSpeed();
}
// if programming failed, don't try to do anything
if (!dmpReady) return;
roueD.runSpeed();
roueG.runSpeed();
// wait for MPU interrupt or extra packet(s) available
#ifdef ARDUINO_BOARD
while (!mpuInterrupt && fifoCount < packetSize) {
roueD.runSpeed();
roueG.runSpeed();
}
#endif
// reset interrupt flag and get INT_STATUS byte
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
// get current FIFO count
fifoCount = mpu.getFIFOCount();
// check for overflow (this should never happen unless our code is too inefficient)
if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
roueD.runSpeed();
roueG.runSpeed();
// reset so we can continue cleanly
mpu.resetFIFO();
//Serial.println(F("FIFO overflow!")); //C'est moi qui l'ai mis en commentaire
// otherwise, check for DMP data ready interrupt (this should happen frequently)
} else if (mpuIntStatus & 0x02) {
roueD.runSpeed();
roueG.runSpeed();
// wait for correct available data length, should be a VERY short wait
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
roueD.runSpeed();
roueG.runSpeed();
// read a packet from FIFO
mpu.getFIFOBytes(fifoBuffer, packetSize);
// track FIFO count here in case there is > 1 packet available
// (this lets us immediately read more without waiting for an interrupt)
fifoCount -= packetSize;
#ifdef OUTPUT_READABLE_YAWPITCHROLL
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
roueD.runSpeed();
roueG.runSpeed();
#endif
if (Controle == 2) { //Toute cette partie avec les if sert au contrôle du robot
i = 0;
Setpoint = Setpoint + 0.05;
if (Setpoint >= 6)Setpoint = 6;
}
if (Controle == 1) {
i = 0;
Setpoint = Setpoint - 0.05;
if (Setpoint <= -6)Setpoint = -6;
}
if (Controle == 3) {
vit1 = 700;
vit2 = -700;
}
if (Controle == 4) {
vit1 = -700;
vit2 = 700;
}
if (Controle == 0) {
vit1 = 0;
vit2 = 0;
Setpoint = Setpoint-i*Setpoint;
i = i + 0.01;
if(i >= 1)i = 1;
}
//Serial.print(Controle); Serial.print(" "); Serial.println(Setpoint);
// blink LED to indicate activity
blinkState = !blinkState;
digitalWrite(LED_PIN, blinkState);
Input = (ypr[1] * 180/M_PI); //On change l'input
myPID.Compute(); //On compute le pid
vitesse = Output; // On applique l'output à la vitesse
roueD.setSpeed(vitesse+vit1);
roueD.runSpeed();
roueG.setSpeed(-1*(vitesse+vit2)); //On inverse la vitesse du deuxième moteur
roueG.runSpeed();
Serial.print(roueD.currentPosition()); Serial.print("\t");
Serial.print(roueG.currentPosition()); Serial.print("\t");
Serial.print(Input); Serial.print("\t");
Serial.print(vitesse); Serial.print("\t");
Serial.print(Kp); Serial.print("\t");
Serial.print(Ki); Serial.print("\t");
Serial.println(Kd);
temps = millis();
//Serial.print(temps); Serial.print("\t");
// Serial.print(Setpoint); Serial.print(", ");
// Serial.print(Input-Setpoint);
// Serial.println();
}
}
#151
Posté 08 mars 2018 - 09:46
- Budet aime ceci
Ma chaine YouTube : https://www.youtube..../oracid1/videos
#153
Posté 14 janvier 2019 - 09:55
Hola je déterre un peu le sujet, j'ai ressorti le robot dernièrement pour jouer avec, je vous avez promis en testant son équilibre dans des pentes et il s'en sort plutôt bien !
Je travaille sur un nouveau projet vraiment complexe j'aimerai vous en parler plus mais je vais attendre qu'il soit un peu plus aboutie
#154
Posté 14 janvier 2019 - 10:00
Je travaille sur un nouveau projet vraiment complexe j'aimerai vous en parler plus mais je vais attendre qu'il soit un peu plus aboutie
Nous tease pas plus ! Vas y balance tout ce que tu sais déjà
pas besoin d'attendre que ça soit plus abouti ! ^^
Hola je déterre un peu le sujet, j'ai ressorti le robot dernièrement pour jouer avec, je vous avez promis en testant son équilibre dans des pentes et il s'en sort plutôt bien !
Je kiffe ce genre de détérage
Par contre il faudrait modifier un chouilla le comportement pour qu'il soit " asservi en position " et que si il se déplace il cherche ensuite à se remettre là où il était =)
Si mon commentaire vous a plus laissez nous un avis ! ![]()
Nouveau sur Robot Maker ?
Jetez un oeil aux blogs, aux tutoriels, aux ouvrages, au robotscope aux articles, à la boutique et aux différents services disponible !
En attendant qu'une bibliothèque de fichiers 3D soit mise en place n'hésitez pas à demander si vous avez besoin du fichier 3D d'un des produits de la boutique... On l'a peut être !
Si vous souhaitez un robot pilotable par internet n'hésitez pas à visiter www.vigibot.com et à lire le sous forum dédié à vigibot!
#155
Posté 14 janvier 2019 - 10:17
Oui en effet un asservissement en position serait type top, il faudrait que je me replonge dans le code de Burnbot, un dimanche quand je saurais pas quoi faire
Répondre à ce sujet
Aussi étiqueté avec au moins un de ces mots-clés : balancing, equilibre, pas à pas
1 utilisateur(s) li(sen)t ce sujet
0 members, 1 guests, 0 anonymous users













