Adapter soft gyroscope à un seul servo (Nano + MPU6050)

Bonjour à tous,

Je suis un grand débutant avec Arduino, je cherche à me fabriquer un gyroscope suivant un seul axe (avec un seul servo donc)

J’ai tenté un code trouvé sur le net, qui a été conçu pour une stabilisation suivant deux axes (avec 2 servos), voici le schéma de montage et le code fourni :

// 2 servo planar stabilization system
// Copyright (c) 2016 woojay poynter

#include <Servo.h>
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif

#define LED_PIN 13
bool blinkState = true;

Servo Servo1;   // First Servo off the chassis
Servo Servo2;   // Second Servo off the chassis

int Servo1Pos = 0;
int Servo2Pos = 0;

float mpuPitch = 0;
float mpuRoll = 0;
float mpuYaw = 0;


// define MPU instance
MPU6050 mpu;                    // class default I2C address is 0x68; specific I2C addresses may be passed as a parameter here

// MPU control/status vars
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
Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector

// relative ypr[x] usage based on sensor orientation when mounted, e.g. ypr[PITCH]
#define PITCH   1     // defines the position within ypr[x] variable for PITCH; may vary due to sensor orientation when mounted
#define ROLL  2     // defines the position within ypr[x] variable for ROLL; may vary due to sensor orientation when mounted
#define YAW   0     // defines the position within ypr[x] variable for YAW; may vary due to sensor orientation when mounted

// ================================================================
// ===                      INITIAL SETUP                       ===
// ================================================================

void setup()
{

  Servo1.attach(10);  // attaches the servo on D11 to the servo object
  Servo2.attach(11);  // Second servo on D11
  delay(50);
  Servo1.write(0); // These are command checks to see if the servos work and
  Servo2.write(60); // to help w/ the initial installation.
  delay(500); // Make sure these movements are clear from the rest of the chassis.
  Servo1.write(180);
  Servo2.write(120);
  delay(500);
  Servo1.write(0);
  Servo2.write(90);
  delay(500);

  // join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
  Wire.begin();
  TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
  Fastwire::setup(400, true);
#endif

  Serial.begin(115200);
  while (!Serial);      // wait for Leonardo enumeration, others continue immediately

  // initialize device
  Serial.println(F("Initializing I2C devices..."));
  mpu.initialize();

  // verify connection
  Serial.println(F("Testing device connections..."));
  Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

  // load and configure the DMP
  Serial.println(F("Initializing DMP"));
  devStatus = mpu.dmpInitialize();


  // INPUT CALIBRATED OFFSETS HERE; SPECIFIC FOR EACH UNIT AND EACH MOUNTING CONFIGURATION!!!!

  mpu.setXGyroOffset(118);
  mpu.setYGyroOffset(-44);
  mpu.setZGyroOffset(337);
  mpu.setXAccelOffset(-651);
  mpu.setYAccelOffset(670);
  mpu.setZAccelOffset(1895);

  // 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)"));
    mpuIntStatus = mpu.getIntStatus();

    // 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.println(devStatus);
  }

  // configure LED for output
  pinMode(LED_PIN, OUTPUT);

} // setup()



// ================================================================
// ===                    MAIN PROGRAM LOOP                     ===
// ================================================================

void loop(void)
{
  processAccelGyro();
}   // loop()



// ================================================================
// ===                    PROCESS ACCEL/GYRO IF AVAILABLE       ===
// ================================================================

void processAccelGyro()
{

  // Get INT_STATUS byte
  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)
  {
    // reset so we can continue cleanly
    mpu.resetFIFO();
    Serial.println(F("FIFO overflow!"));
    return;
  }

  if (mpuIntStatus & 0x02)  // otherwise continue processing
  {
    // check for correct available data length
    if (fifoCount < packetSize)
      return; //  fifoCount = mpu.getFIFOCount();

    // read a packet from FIFO
    mpu.getFIFOBytes(fifoBuffer, packetSize);

    // track FIFO count here in case there is > 1 packet available
    fifoCount -= packetSize;

    // flush buffer to prevent overflow
    mpu.resetFIFO();

    // display Euler angles in degrees
    mpu.dmpGetQuaternion(&q, fifoBuffer);
    mpu.dmpGetGravity(&gravity, &q);
    mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
    mpuPitch = ypr[PITCH] * 180 / M_PI;
    mpuRoll = ypr[ROLL] * 180 / M_PI;
    mpuYaw  = ypr[YAW] * 180 / M_PI;

    // flush buffer to prevent overflow
    mpu.resetFIFO();

    // blink LED to indicate activity
    blinkState = !blinkState;
    digitalWrite(LED_PIN, blinkState);

    // flush buffer to prevent overflow
    mpu.resetFIFO();

    Servo1.write(-mpuPitch + 90);
    Servo2.write(mpuRoll + 90);
    //delay(10);

    // flush buffer to prevent overflow
    mpu.resetFIFO();

  } // if (mpuIntStatus & 0x02)
}  // processAccelGyro()

En téléchargeant les bibliothèques nécessaires j’ai donc réussi à compiler et téléverser le code vers mon arduino nano, en reprenant le montage décrit avec un seul servo, voici mon montage :

Le souci étant qu’une fois téléversé, rien ne se passe
Le moteur devrait au moins tourner pour se calibrer, mais rien ne se passe
Pareil, lorsque je bouge le gyroscope : rien

Comme je vous ai dit je débute, j’ai grillé les étapes en collant le code tout fait, du coup je sais pas trop de quel côté chercher
Est-ce que quelqu’un saurait me donner une piste ?

Merci ! :slight_smile:

Bonjour,

Peux-tu donner les références de ton "servo" ? Je mets les guillemets car je trouve qu'il a une tête bizarre. Je n'y connais rien en modélisme mais ça me fait plutôt penser à un moteur brushless.

addesign: Comme je vous ai dit je débute, j'ai grillé les étapes .....

Tu n'as peut-être pas grillé que les étapes. C'est un moteur brushless. Il faut une carte spécifique pour le piloter dans ce genre là. Ces cartes se pilotent comme des servos (avec le même type de signaux).

Oui c'est un "12 Pole Three-Phase Brushless DC Motor" sans doute

Désolé pour le temps de réponse, semblerait que je n'ai pas reçu les alertes email pour me tenir informé Entre temps je continue d'apprendre petit à petit ::)

Je me suis renseigné auprès de la personne, et effectivement c'est parcequ'il s'agit d'un moteur brushless que ça ne fonctionne pas

J'ai donc commandé des servos pour tester dans les mêmes conditions que le code d'origine, et je verrai après pour adapter

fdufnews : les cartes que tu proposes servent d'adaptateur direct ? Car quand j'ai parlé avec la personne qui a réalisé le code de base il avait l'air de me dire qu'il tentait justement d'adapter son code a du brushless :relaxed:

Merci !

si vous lisez l'anglais il y a un bon papier ici sur les BLDC

Merci je vais lire tout ça ;)

Hello,

Avant de rentrer plus dans les détails avec le gimbal j'ai voulu voir si tout fonctionnait déjà avec des servos J'ai reçu deux servos 9g aujourd'hui, j'ai donc pu refaire le montage à l'identique du tuto de départ

Mais j'ai un souci : j'arrive à uploader le code dans la puce sans soucis, tous les cablages semblent ok, mais quand je branche l'arduino à une source : rien ne se passe, alors que les servos devraient tourner pour se calibrer Idem si je bouge la MPU6050 : rien ne bouge

Quelqu'un aurait une piste ?

Merci

Peux-tu envoyer ton code qui est censé faire bouger les servos ?

Bonjour, effectivement les intervenants ont raisons, c'est d'un moteur brushless dont il s'agit, et c'est compliqué de faire une carte pour le piloter (voir sur internet DIY ESC BRUSHLESS) pour s'en rendre compte.

Par contre coté programmation, je te proposerais bien la bibliothèque que j'ai développé dans laquelle ce que tu demandes est juste très simple à faire comparé aux bibliothèques concurrentes:

#include "../module/Mpu6050.h"
#include "../module/PwmWrite.h"
#include "../module/Math.h"

int main()
{
    Mpu6050 gyroscope = Mpu6050 (0x68);
    PwmWrite servoDeTanguage = PwmWrite (1, 0, 1000, 2000);
    PwmWrite servoDeRoulis = PwmWrite (2, 0, 1000, 2000);

    PwmWrite::start (50);

    while (true)
    {
        gyroscope.readRotation();

        servoDeTanguage.us (Math::curve (-500, gyroscope.rx, 500, 1000, 2000, 0));
        servoDeRoulis.us (Math::curve (-500, gyroscope.ry, 500, 1000, 2000, 0));
    }

    return 0;
}

En quelques lignes c'est réglé, et c'est le plus performant de ce que tu peux obtenir avec l'ATmega328P en C++, si jamais tu es intéressé n'hésites pas à me demander plus d'infos, je me ferais un plaisir de t'aider en ce sens.