Welcome to EnviroDIY, a community for do-it-yourself environmental science and monitoring. EnviroDIY is part of WikiWatershed, a web toolkit designed to help citizens, conservation practitioners, municipal decision-makers, researchers, educators, and students advance knowledge and stewardship of fresh water. New to EnviroDIY? Start here

LSM303 Accelerometer + Compass library integration into ModularSensors

Home Forums Mayfly Data Logger LSM303 Accelerometer + Compass library integration into ModularSensors

This topic contains 8 replies, has 2 voices, and was last updated by  Sara Damiano 4 months ago.

  • Author
    Posts
  • #12844

    Greg Cutrell
    Participant

    While getting the Mayfly into the water quality buoy world we got a couple LSM303’s to calculate the compass direction at which the mayfly is facing. It uses I2C and is really easy to get running using the tutorial at https://learn.adafruit.com/lsm303-accelerometer-slash-compass-breakout/coding. Adafruit’s library for the sensor at https://github.com/adafruit/Adafruit_LSM303.

    The code works fine until I start to bring in sensors from the Modular library with a logger instance. If I create a new event right before calling dataLogger.logData(); in the void loop() I receive a “good” compass reading the first time but afterwards returns 0.0’s. After a while of trial and error I’m guessing since the adafruit code isn’t a part of the ModuleSensors sensor class there are issues with addressing and setting bits.

    What I’m wondering is there a simple-ish way to integrate the existing adafruit code into Mayfly’s modular library? Or maybe there is another workaround to obtain data using Adafruit’s library and store it as a sensor variable? Any guidance would be greatly appreciated!

  • #12846

    Sara Damiano
    Moderator

    I’m sure the LSM303 could be integrated into ModularSensors. You should also be able to use it along with ModularSensors without actually integrating it. You might not be able to use the “logData” function though – you might have to break it up some.

    So, do you have your program somewhere I could look at? Are you turning off the power to the sensor between reading? (Is your I2C port set to switched power?) Are you sure the sensor is powered when you’re trying to read it? Did you try putting a begin() for the LSM303 right before it’s read? In that library it looks like the begin() function sends an activate command which it may need after every power up (or even after every time I2C is disconnected).

  • #12851

    Greg Cutrell
    Participant

    Thanks Sara! My I2C port is not switched and confirmed that it had 3.3V. I didn’t think about looking into what the begin() function is actually doing. It turns out applying the begin() before every compass object creating did the trick!

    As for actually saving the compass data could I create a constructor for a calculated variable where the value for the ‘float (*calcFxn)()’ calls a function that then gets data from the compass? I’m guessing the downside would be I could not do averages and I would just receive one reading per logging interval?

    I have not gotten calculated variable method to work for my compass but I think it is because of an error in my code or maybe a bug in ModularLibrary 19.6 I’m working on. Anytime I add the variable pointer to the variable array (like in https://github.com/EnviroDIY/ModularSensors/blob/master/examples/baro_rho_correction/baro_rho_correction.ino) it makes the MayFly reset going through all the initial checks again and setting up sensors ever sampling interval. I might just need to update to the most recent master version 21.1.

  • #12855

    Sara Damiano
    Moderator

    You definitely want to update for calculated variables. There’s a big bug in 0.19.6 in the “completeUpdate” function in run inside the “logData” function that will make any calculated variables crash.

    After you update, adding the compass as a “calculated” variable should work just as you described. That is, you could call the begin and update to return a float in the calcFxn – and you would not be able to get averages or multiple readings without writing it yourself in the function. The calculated variable function are not called until after all the sensors have completed all measurements and gone to sleep.

    You could look at the BME’s code if you want to try and write it as a new sensor. I need to write up better documentation on how to create a new sensor.

  • #12856

    Greg Cutrell
    Participant

    Thanks for the update confirmation and information about when the calculated variable takes place. I’ll see how much time I can spend on the best way to integrate the compass. The best way to is to call it in a custom .cpp file for the wind sensor, which is SDI-12. That way every every time the wind data is requested from the sdi-12 sensor the compass offset is applied before saving it to the variable array. Hopefully in the next week I’ll put in a pull request for this new sdi-12 (METER ATMOS22) wind sensor. A great very low power sensor for a relatively low price (~$500 – $600) for an acoustic wind sensor. Thanks again!

  • #12857

    Greg Cutrell
    Participant

    On the topic of averaging. It seems the averaging parameter takes a number of consecutive measurements. I thought the measurement_time variable might offset each consecutive measurements but it doesn’t seem to work that way, just the initial measurement. Is this correct? I have been playing around in the SDI12Sensors.cpp file and was sure if I might have had effected this.

    I was thinking this might be an easy way to average higher frequency logging to a longer average. For example take a measurement every minute but we really want to save/send out every 10 minutes. Is there a way already in-place to complete a task like this?

  • #12858

    Sara Damiano
    Moderator

    If you’re averaging multiple measurements, the first measurement is started stabilizationTime_ms after wake up and the result requested measurementTime_ms later, or as close to that time as the sensor is checked in iterating through all variables. The second measurement is begun in the next loop after the first measurement result is collected, so nearly immediately after the first measurement is completed. The result is requested measurementTime_ms later. Same for all subsequent measurements.

    If there was only one sensor with three readings, it would go about like this:

    main processsor wakes -> sensor powerUp() -> wait warmUpTime_ms -> sensor wake() -> wait stabilizationTime_ms -> startSingleMeasurement() -> wait measurementTime_ms -> addSingleMeasurementResult() -> startSingleMeasurement() -> wait measurementTime_ms -> addSingleMeasurementResult() -> startSingleMeasurement() -> wait measurementTime_ms -> addSingleMeasurementResult() -> sensor sleep() -> sensor powerDown() -> calculated variables calculated -> data written to SD -> data published to remotes -> mcu goes to sleep.

    The reality is a little different if there are multiple sensors because each step takes a non-zero amount of time and the millis() function gets called a lot which in itself wastes processor time, but it shouldn’t be far off the above. If you’re seeing something much different, that’s a problem/bug.

    So, right now there’s now way to average readings between multiple wake/sleep sessions. So if you wanted to average 10 readings 1 minute apart, the mcu and sensor would be awake the whole time and murder your battery. You could create two logger instances, one logging at 1 minute and another logging at 10 minutes and only attach a publisher to the longer logging interval, but the data going out would only be from that 1 measurement, not the last 10. You’d want to optimize your loop to do this; DON’T just use logData(). If you look in the definitions for the dataPublishers, there are arguments for a send frequency and offset, but those are just place-holders right now – they’re not actually implemented in any way in the code.

    If you’re making a new SDI-12 sensor, you shouldn’t modify the SDI12Sensors.cpp. Create a new cpp/h pair defining a sub-class of SDI-12 sensor. Look at the Decagon5TM as an example – it follows the “normal” SDI12 sensor in everything except “addSingleMeasurementResult” which is defined separately.

  • #12859

    Greg Cutrell
    Participant

    Thanks! Bummer about not being able to average out samples over a period of time but I understand the power limitations for a normal mayfly system.

    The double logger was going to be my fall back so we can at least save some higher frequency data. I was using the Decagon5TM sensor as an example but was getting an warning on the addSingleMeasurementResult and startMeasurement function overrides (something about a version issue). So I just started to edit the SDI12Sensors code just to make sure my routine would work and then put that code in the new sensor .cpp file.

    BTW this ATMOS22 would work perfect for the mayfly since it averages internally until you request another measurement. Only issue for us is we need to use the compass to offset a platform direction which is always moving.

  • #12860

    Sara Damiano
    Moderator

    You can completely ignore the error “override controls (override/final) only available with -std=c++1 or -std=gnu++11” I’m not sure why it always comes up. I can’t imagine your compiler version isn’t high enough to support it.

You must be logged in to reply to this topic.