simondlevy / Hackflight

Minimalist flight-control toolkit for makers
GNU General Public License v3.0
285 stars 82 forks source link

EM7180 USFS - Magnetometer ID not recognized #55

Closed danieladugyan closed 4 years ago

danieladugyan commented 4 years ago

I'm having issues with using the USFS. I've followed every step in the wiki, including calibration, and the USFS_Master test example is working perfectly. However, uploading the Hackflight firmware results in the error Magnetometer ID not recognized being printed to the serial monitor. Curiously, this error message only shows sometimes, although the actual error persists (GCS always gives the error No response from board). In my case, I got the board to print the error by adding Serial.println("USFS initializing"); just before calling _sentral.begin() in usfs.hpp.

I can't for the life of me understand why this error occurs, since the code in Hackflight's usfs.hpp seems identical to MasterTest.ino, and as I said, MasterTest.ino works perfectly.

simondlevy commented 4 years ago

I've attempted to reproduce this error, but without success. To try and help you figure out what's going on, I've added a simple sketch that uses just the USFS (no receiver or motors to worry about). Try this out and let me know what you find.

danieladugyan commented 4 years ago

I just tried out your code, but still no success. However, I had to modify the code slightly to be able to use it. Below is the version of the code that I uploaded.

#include "hackflight.hpp"
#include "boards/realboards/arduino.hpp"
#include "receivers/mock.hpp"
#include "actuators/mixers/quadxcf.hpp"
#include "motors/mock.hpp"
#include "imus/usfs.hpp"

hf::Hackflight h;

hf::MockReceiver rc;

hf::MixerQuadXCF mixer;

hf::USFS imu;

hf::MockMotor motor1;
hf::MockMotor motor2;
hf::MockMotor motor3;
hf::MockMotor motor4;

hf::Motor * motors[4] = { &motor1, &motor2, &motor3, &motor4 };

void setup(void)
{
    h.init(new hf::ArduinoBoard(2), &imu, &rc, &mixer, motors);
}

void loop(void)
{
    h.update();
}

And my USFS.hpp file:

#pragma once

#include <Wire.h>
#include <USFS_Master.h>
#include "imu.hpp"

namespace hf {

    class USFS : public IMU {

        private:

            // Tunable USFS parameters
            static const uint8_t  MAG_RATE       = 100;  // Hz
            static const uint16_t ACCEL_RATE     = 330;  // Hz
            static const uint16_t GYRO_RATE      = 330;  // Hz
            static const uint8_t  BARO_RATE      = 50;   // Hz
            static const uint8_t  Q_RATE_DIVISOR = 5;    // 1/5 gyro rate

            USFS_Master _sentral = USFS_Master(MAG_RATE, ACCEL_RATE, GYRO_RATE, BARO_RATE, Q_RATE_DIVISOR);

            void checkEventStatus(void)
            {
                _sentral.checkEventStatus();

                if (_sentral.gotError()) {
                    while (true) {
                        Serial.print("ERROR: ");
                        Serial.println(_sentral.getErrorString());
                    }
                }
            }

        protected:

            // Handle upside-down mounting
            virtual void adjustGyrometer(float & gx, float & gy, float & gz) { (void)gx; (void)gy; (void)gz;  }
            virtual void adjustQuaternion(float & qw, float & qx, float & qy, float & qz) { (void)qw; (void)qx; (void)qy; (void)qz;  }

        public:

            virtual bool getGyrometer(float & gx, float & gy, float & gz) override
            {
                // Since gyro is updated most frequently, use it to drive SENtral polling
                checkEventStatus();

                if (_sentral.gotGyrometer()) {

                    // Returns degrees / sec
                    _sentral.readGyrometer(gx, gy, gz);

                    // Convert degrees / sec to radians / sec
                    gx = radians(gx);
                    gy = radians(gy);
                    gz = radians(gz);

                    adjustGyrometer(gx, gy, gz);

                    return true;
                }

                return false;
            }

            virtual bool getQuaternion(float & qw, float & qx, float & qy, float & qz, float time) override
            {
                (void)time;

                if (_sentral.gotQuaternion()) {

                    _sentral.readQuaternion(qw, qx, qy, qz);

                    adjustQuaternion(qw, qx, qy, qz);

                    return true;
                }

                return false;
            }

            virtual void begin(void) override
            {
                Serial.println("USFS initializing");

                // Start the USFS in master mode, no interrupt
                if (!_sentral.begin()) {
                    while (true) {
                        Serial.println(_sentral.getErrorString());
                    }
                }
            }

    }; // class USFS

} // namespace hf

The only difference in USFS.hpp is Serial.println("USFS initializing"); Without that line, I don't get any error message in the Serial monitor, but the code still does not work.

danieladugyan commented 4 years ago

I managed to figure it out! I realised that changing from TinyPico to ArduinoBoard had to be the problem. It turns out that ArduinoBoard doesn't start I2C communication with Wire.begin(). That took me way too long to realise. Thanks for making me realise the simple error!

Perhaps Wire.begin() should be added below RealBoard::init() in arduino.hpp (and of course, #include <Wire.h>)?

simondlevy commented 4 years ago

Great, I'm glad you figured it out!

I avoid putting Wire.begin() in arduino.hpp, because different boards use different versions of that call; for example: Butterfly

Feel free to close the issue if you've got it working.