Pilgrimz progress

Phoebe Is Losing Gravity Readings; Integration’s Mauled Zoe

Sorry it’s been quiet for a few days; I’ve been trying to get to the bottom of the manic leap-into-the-air problems I’ve had with Phoebe and Zoe.  It’s not solved yet, but I’m getting a better idea of why it might be happening.  The symptoms are the same, but I believe the cause is different.

With Zoe, the manic climb only happened when I put on the carbon props; with the floppy props all was ok.  She was running with the accelerometer scale set to ±2g.  The flexibility of the floppy props softened vertical acceleration sufficiently to prevent any peaks above 2g during ascent.  My speculation is that with the carbon props, she did breach the 2g limit.  That means she’d be under reading acceleration leading to the integrated vertical velocity being lower than it actually was, meaning the PIDs turned up the props speeds, and off she shot.  However, I’ve not had the chance to test this theory as I’ve been waiting for some replacement parts – props, arm, slimline set of connectors and a new MPU to build a much sleeker HoG for her.  I’ll post again when this is done, and hopefully be able to show off the improvement.

Phoebe’s case is different; for her she’s getting FIFO overflows.  At the start of the flight, she gets one good read of data, and then every further read is shifted by 4 bytes so the codes believes each FIFO data batch consists of ax, ay, az, gx, gy, gz, but what it’s actually getting is az, gx, gy, gz, ax, ay.  I now have lots of error checking to ignore such batches and this has revealed that I only get one good batch of sample data before the code spots the next batch is corrupt and aborts the flight.  It seems the code isn’t running fast enough to stop the FIFO overflowing; I’ve been doing various tweaks to the code to ensure the code is synchronized with the sensors, and that time usage is optimized – calls to time.time() have gone, as are a lot of the diagnostics.  The one remaining thing is that the FIFO is filled at the sampling rate, not the register update rate; Phoebe’s been running at 500Hz but her sampling is 1kHz.  With Zoe, both are set to 1kHz.  Next step is to try that and see what happens.

I’ll update you when there’s something worth sharing about both Phoebe and Zoes’ progress.

5 thoughts on “Pilgrimz progress

  1. Hmm I see that you’re reading from the FIFO to empty it. I remember trying this and it did work for a while but once in a while – rarely – I still got slicing.
    After a lot of testing I realized that the data is not written atomically in the FIFO. So the fifo size does not increase in sample_length increments. For this reason, sometimes when you empty the fifo you might empty a fragment of a new fresh sample being pushed on top.
    For me the solution was to reset the fifo which first disabled the fifo so no new samples are pushed in and then empties it.

    Also, I think there is a way to configure the fifo to hold 4096 bytes worth of data. The 512 bytes is only if you’re using the on-board processor to compute quaternions or smth (I don’t remember exactly). Here’s my config
    res &= mpu_write_u8(buses, MPU_REG_ACCEL_CONFIG2, MPU_BIT_FIFO_SIZE_4096 | 0x8 | a_dlpf, CONFIG_REGISTER_SPEED);
    I don’t know what the 0x8 is, I took the code from somewhere and I remember it was important 🙂

    https://github.com/jeanleflambeur/silkopter/blob/master/silkopter/brain/src/source/MPU9250.cpp

    Cheers!

      • I am using the IMU FIFO, but I’ve configured it to contain only raw sensor data – 6 shorts of ax, ay, az, gx, gy, gz. When I come to read it, I read the length of the FIFO contents first and then only read int(size /12) i.e I get an exact number of batches of ax, ay, az, gx, gy, gz and leave size % 12 on the FIFO for next time. So I don’t get any slicing. I’d know if I did because I have the FIFO overflow interrupt enabled – if triggered, the code hard-kills the flight immediately

        512 bytes is fine for me – my motion processing takes a couple of ms, and to fill 512 bytes takes about 42ms – plenty of time to do other stuff like reading other sensors.

        Works for me, have a look at the newer posts for more details – things have moved pretty quickly since my i2c errors vanished. I wasted a year trying to work round these but a new PCB, and the move to Jessie, and they vanished overnight, Don’t know which of the two and don’t care; with the FIFO I’m now in control of time, and can use it to read other sensors etc as long as I take <42ms to do so – that's a very long time in my code even running python!

  2. Hi,
    The FIFO is indeed updated at the sampling rate, so at 1Khz. If you read at 500Hz it will overflow quickly and when it does it will pop parts of the oldest samples resulting in the slicing that you’re seeing.
    In my tests, once the buffer overflows there is no sensible way to recover and I just reset it. This is because of the slicing and the fact that I have no way of knowing how many samples have overflown to calculate the new sample boundary.
    The main cause of this is (as far as I could tell) that your sample size (12) is not a divisor of the FIFO size.
    The fifo reset code was also tricky as it wasn’t always doing its job so I ended up with this:
    void MPU9250::reset_fifo(Buses& buses)
    {
    QLOG_TOPIC(“mpu9250::reset_fifo”);

    mpu_write_u8(buses, MPU_REG_USER_CTRL, m_user_ctrl_value | MPU_BIT_FIFO_RST, CONFIG_REGISTER_SPEED);
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
    mpu_write_u8(buses, MPU_REG_FIFO_EN, 0, CONFIG_REGISTER_SPEED);
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
    mpu_write_u8(buses, MPU_REG_USER_CTRL, m_user_ctrl_value | MPU_BIT_FIFO_RST, CONFIG_REGISTER_SPEED);
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
    mpu_write_u8(buses, MPU_REG_FIFO_EN, MPU_BIT_GYRO_XO_UT | MPU_BIT_GYRO_YO_UT | MPU_BIT_GYRO_ZO_UT | MPU_BIT_ACCEL, CONFIG_REGISTER_SPEED);
    }

    BTW – you could read all samples from the fifo in one i2c transaction instead one-by-one. This will take less time since the address byte has to be sent only once per transaction instead of once per sample.

    The code I used for the last year with no issues is this:

    uint16_t fifo_count;
    auto res = mpu_read_u16(buses, MPU_REG_FIFO_COUNTH, fifo_count, MISC_REGISTER_SPEED);
    if (!res)
    {
    m_stats.bus_failures++;
    }

    if (res && fifo_count >= 12)
    {
    if (fifo_count >= 4000)
    {
    QLOGW(“Resetting FIFO: {}”, fifo_count);
    reset_fifo(buses);
    fifo_count = 0;
    }
    else
    {
    size_t sample_count = fifo_count / 12;
    size_t to_read = sample_count * 12;
    QASSERT(sample_count >= 1);

    m_fifo_buffer.resize(to_read);
    if (mpu_read(buses, MPU_REG_FIFO_R_W, m_fifo_buffer.data(), m_fifo_buffer.size(), MISC_REGISTER_SPEED))
    {
    //..use data
    }
    }
    }

    • Hi Jean, long time no hear!

      I got mine working in the end. Have a look at the code on GitHub/PiStuffing/Quadcopter/Quadcopter.py. flushFIFO stops the data stream to the FIFO but does _not_ reset the FIFO. The code then reads the FIFO size and reads that number of the bytes from the FIFO. It then check the FIFO size again just to make sure it’s zero (it always is), and then it restarts the data stream into the FIFO.

      Sampling at 1kHz with 12 byte batches means that as long as I empty the FIFO every 42ms (max) then the FIFO never overflows – it’s 512 bytes long. I do have an interrupt just in case but it never gets triggered now.

      Hove

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.