Home › Forums › Mayfly Data Logger › Sleep code not working with Maxbotix 7389
Tagged: maxbotix, SoftwareSerial
- This topic has 10 replies, 4 voices, and was last updated 2020-01-08 at 7:13 PM by Sara Damiano.
-
AuthorPosts
-
-
2019-12-06 at 5:45 PM #13444
We have a project which requires only reading a Maxbotix 7389 and using the result to trigger taking a water sample.
With cold weather we have started getting bad (300 mm) data values sometimes. We were using pin 18 to supply the Maxbotix power and pin 19 to read. Sleep code worked fine. But, we would like to test supplying power to sensor continuously from an external power pack. This resulted in the sleep code not working. The sensor just takes data one point after another and does not sleep. Have installed the new EnviroDIY_SoftwareSerial_PCINT12 and EnviroDIY_Sodaq_PCINT0 libraries (removed old libraries) but whenever the sensor is supplied continuous power, the board still will not execute sleep code). Any suggestions?
-
2019-12-07 at 1:01 AM #13448
Sara is probably the best one to comment on the code aspect of your question, but hardware-wise, you might want to try a different pair of pins for connecting the sensor. D19 is used as the status pin of the Xbee socket, and is used in all of the code examples we use for radio, wifi, and cellular telemetry. D18 is kind of reserved for being used as either the card detect pin of the microSD card socket (if you enable SJ10), or you can use it for reading a trigger from the RTC via SJ6. So picking a pair of pins that’s totally free would be good in case you want to add telemetry or other features to your board. D4, D5, D6, D7, D10, and D11 are free, which is why I put them on the Grove sockets. The other digital pins that are available on the 20-pin header are bought out for compatibility with things you might put on a protoshield, but aren’t necessarily free for any sort of output or input from a sensor or other device.
-
2019-12-09 at 12:50 PM #13451
Can you post your code? I can’t help much with the sleeping issue without seeing your code.
The issue with getting those 300mm values back from the sonar is an issue with the sensor/installation itself not the code. The sonar will report its blanking distance (300 or 500 depending on the model) anytime something is too close to it to get a real reading. Usually the thing too close to the sonar is condensation on the sonar itself. You’re probably seeing it a lot more in the winter because of the difference in temperature between the sonar/Mayfly box and the outside air. Having the sonar in a pipe over the water might make it even worse. It’s also possible that the sensor is just dirty, but if it’s alternating between blanking distance and good values, it’s probably condensation. In most of our newer code I re-read the sonar up to 25 times if it’s reporting 300/500, but if there’s really too much condensation on the sensor there’s nothing any code can do to change it. I’m pretty sure the “self-cleaning” feature available on some of the MaxBotix models is a heater to prevent condensation.
I also strongly recommend switching from the Arduino IDE to PlatformIO. Library management is much easier in PlatformIO – you can keep set up different groups of libraries for each program and not worry about an old sketch breaking because you updated the libraries to use in a different sketch. I know VSCode and PlatformIO can seem a lot scarier up-front, but I promise it’s easier to use in the long run!
-
2019-12-09 at 3:12 PM #13452
Sensor works much better in open air suspended over water on a boom. We are now testing taking 10 separate reads at each time interval- for trouble shooting information. Although occasional intervals give 300 for all 10 reads, most of the time bad data occurs in only the first 2 or 3 reads at any interval. We are seeing intervals with some bad data values at a frequency of maybe once per day. We will test going up to 25 reads to see if that solves the problem.
The code used for testing is in the attached file. This works as desired (sleep code works) when sonar power is on D18 and signal read is on D19. Alternatively works on D10 (power) and D11 (signal). However, the sleep code does not work if sonar power is provided continuously from the 3.3 V rail. We wanted to test effect of leaving power applied to the sonar all the time to see the effect (might clear off condensation from the face?).
-
2019-12-09 at 3:12 PM #13453123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430#include <SoftwareSerial_PCINT12.h>#include <Sodaq_PcInt_PCINT0.h>//sketch to log sonar data on Mayfly//this one uses either board power or a battery pack to continuously power Maxbotix#include <Wire.h>#include <avr/sleep.h>#include <avr/wdt.h>#include <SPI.h>#include <SdFat.h>SdFat SD;#include <RTCTimer.h>#include <Sodaq_DS3231.h>// const int SonarExcite = 11; // turns on switched powerSoftwareSerial sonarSerial(19, -1);boolean stringComplete = false;#define READ_DELAY 1// RTC TimerRTCTimer timer;String dataRec = "";int currentminute;long currentepochtime = 0;float boardtemp = 0.0;int batteryPin = A6; // select the input pin for the potentiometerint batterysenseValue = 0; // variable to store the value coming from the sensorfloat batteryvoltage;int range_mm1;int range_mm2;int range_mm3;int range_mm4;int range_mm5;int range_mm6;int range_mm7;int range_mm8;int range_mm9;int range_mm10;int range_mm;// RTC Interrupt pin#define RTC_PIN A7#define RTC_INT_PERIOD EveryMinute#define SD_SS_PIN 12// The data log file#define FILE_NAME "SonicLog.txt"// Data header#define LOGGERNAME "Ultrasonic Maxbotix Sensor Datalogger"#define DATA_HEADER "DateTime,Loggertime,BoardTemp,Battery_V,SonarRange_mm 1 to 10"void setup(){// Initialise the serial connection// Serial.begin(57600);sonarSerial.begin(9600);rtc.begin();delay(100);pinMode(8, OUTPUT);pinMode(9, OUTPUT);pinMode(18, OUTPUT);greenred4flash(); //blink the LEDs to show the board is onsetupLogFile();// Setup timer eventssetupTimer();// Setup sleep modesetupSleep();// Serial.println("Power On, running: ultrasonic_logger_example_1.ino");// Serial.println("Power On, running: ultrasonic_logger_example_1.ino");digitalWrite(8, HIGH);stringComplete = false;digitalWrite(18, HIGH);delay(500);//wait for board to stabilizerange_mm = SonarRead();//does not add data to a string, included only for debuggingdigitalWrite(18, LOW);digitalWrite(8,LOW);delay (2000);}void loop(){//Update the timertimer.update();if(currentminute % 5 == 0){digitalWrite(8, HIGH);dataRec = createDataRecord();stringComplete = false;delay(100);digitalWrite(18, HIGH);//turns on switched powerdelay(10000);//wait 15 sec for board to stabilize after startuprange_mm1 = SonarRead();stringComplete = false;delay (1000);range_mm2 = SonarRead();stringComplete = false;delay (1000);range_mm3 = SonarRead();stringComplete = false;delay (1000);range_mm4 = SonarRead();stringComplete = false;delay (1000);range_mm5 = SonarRead();stringComplete = false;delay (1000);range_mm6 = SonarRead();stringComplete = false;delay (1000);range_mm7 = SonarRead();stringComplete = false;delay (1000);range_mm8 = SonarRead();stringComplete = false;delay (1000);range_mm9 = SonarRead();stringComplete = false;delay (1000);range_mm10 = SonarRead();stringComplete = false;delay (1000);digitalWrite(8, LOW);//following records ten data reads.dataRec += ",";dataRec += range_mm1;dataRec += ",";dataRec += range_mm2;dataRec += ",";dataRec += range_mm3;dataRec += ",";dataRec += range_mm4;dataRec += ",";dataRec += range_mm5;dataRec += ",";dataRec += range_mm6;dataRec += ",";dataRec += range_mm7;dataRec += ",";dataRec += range_mm8;dataRec += ",";dataRec += range_mm9;dataRec += ",";dataRec += range_mm10;//Save the data record to the log filelogData(dataRec);//Echo the data to the serial connection//Serial.println();//Serial.print("Data Record: ");//Serial.println(dataRec);String dataRec = "";}systemSleep();}void showTime(uint32_t ts){//Retrieve and display the current date/timeString dateTime = getDateTime();//Serial.println(dateTime);}void setupTimer(){//Schedule the wakeup every minutetimer.every(READ_DELAY, showTime);//Instruct the RTCTimer how to get the current time readingtimer.setNowCallback(getNow);}void wakeISR(){//Leave this blank}void setupSleep(){pinMode(RTC_PIN, INPUT_PULLUP);PcInt::attachInterrupt(RTC_PIN, wakeISR);//Setup the RTC in interrupt modertc.enableInterrupts(RTC_INT_PERIOD);//Set the sleep modeset_sleep_mode(SLEEP_MODE_PWR_DOWN);}void systemSleep(){//Wait until the serial ports have finished transmittingSerial.flush();Serial1.flush();//The next timed interrupt will not be sent until this is clearedrtc.clearINTStatus();//Disable ADCADCSRA &= ~_BV(ADEN);//Sleep timenoInterrupts();sleep_enable();interrupts();sleep_cpu();sleep_disable();//Enbale ADCADCSRA |= _BV(ADEN);}String getDateTime(){String dateTimeStr;//Create a DateTime object from the current timeDateTime dt(rtc.makeDateTime(rtc.now().getEpoch()));currentepochtime = (dt.get()); //Unix time in secondscurrentminute = (dt.minute());//Convert it to a Stringdt.addToString(dateTimeStr);return dateTimeStr;}uint32_t getNow(){currentepochtime = rtc.now().getEpoch();return currentepochtime;}void greenred4flash(){for (int i=1; i <= 4; i++){digitalWrite(8, HIGH);digitalWrite(9, LOW);delay(50);digitalWrite(8, LOW);digitalWrite(9, HIGH);delay(50);}digitalWrite(9, LOW);}void setupLogFile(){// initialize the SD card at SPI_FULL_SPEED for best performance.// try SPI_HALF_SPEED if bus errors occur.if (!SD.begin(SD_SS_PIN, SPI_HALF_SPEED)) {SD.initErrorHalt();}//Check if the file already existsbool oldFile = SD.exists(FILE_NAME);//Open the file in write modeFile logFile = SD.open(FILE_NAME, FILE_WRITE);//Add header information if the file did not already existif (!oldFile){logFile.println(LOGGERNAME);logFile.println(DATA_HEADER);}//Close the file to save itlogFile.close();}void logData(String rec){//Re-open the fileFile logFile = SD.open(FILE_NAME, FILE_WRITE);//Write the CSV datalogFile.println(rec);//Close the file to save itlogFile.close();}String createDataRecord(){//Create a String type data record in csv format//TimeDate, Loggertime,Temp_DS, Diff1, Diff2, boardtempString data = getDateTime();data += ",";rtc.convertTemperature(); //convert current temperature into registersboardtemp = rtc.getTemperature(); //Read temperature sensor valuebatterysenseValue = analogRead(batteryPin);batteryvoltage = (3.3/1023.) * (12.7/2.7) * batterysenseValue;data += currentepochtime;data += ",";addFloatToString(data, boardtemp, 3, 1); //floatdata += ",";addFloatToString(data, batteryvoltage, 4, 2);return data;}static void addFloatToString(String & str, float val, char width, unsigned char precision){char buffer[10];dtostrf(val, width, precision, buffer);str += buffer;}int SonarRead(){int result;char inData[5]; //char array to read data intoint index = 0;while (sonarSerial.read() != -1) {}while (stringComplete == false) {if (sonarSerial.available()){char rByte = sonarSerial.read(); //read serial input for "R" to mark start of dataif(rByte == 'R'){//Serial.println("rByte set");while (index < 4) //read next three character for range from sensor{if (sonarSerial.available()){delay(50);inData[index] = sonarSerial.read();//Serial.println(inData[index]); //Debug lineindex++; // Increment where to write next}}inData[index] = 0x00; //add a padding byte at end for atoi() function}rByte = 0; //reset the rByte ready for next readingindex = 0; // Reset index ready for next readingstringComplete = true; // Set completion of read to trueresult = atoi(inData); // Changes string data into an integer for use}}return result;}
-
2019-12-09 at 4:43 PM #13454
I put your code into a “code snippet” to make it easier to read.
You’re listening to the sonar via SoftwareSerial. SoftwareSerial works by means of pin change interrupts. Pin change interrupts wake the board up. While the sonar is powered, it will continuously send out data. So if your sonar is continuously powered and continuously sending out data and you don’t explicitly stop listening and turn off those interrupts, your board will be immediately woken up by the sonar. I’m sorry. If I’d just thought a little harder I could have figured that out without seeing any code. Anyway, if you want to use your code mostly as-is and keep the sonar on all the time, remove the
sonarSerial.begin(9600);
from your setup and make it the first line of your readSonar() function. Then add
sonarSerial.end();
just before the return of that same function. Doing that should prevent the interrupts from keeping the board awake any time except within that function.
I don’t think leaving the sonar continuously powered like that will help it to stay fog-free unless it actually is a “self-cleaning” module. The 7389 isn’t. Have you actually seen it make any difference? I don’t think we’ve ever even tried.
You’re not using ModularSensors, but for anyone who might be and notices the keep-awake issue with a MaxBotix, I created an issue for it here: https://github.com/EnviroDIY/ModularSensors/issues/303
-
2019-12-09 at 5:16 PM #13455
Well, actually, I forgot about the internal data filter. Leaving the sensor always powered will give time for that to come into play. I don’t know if it will help any, though.
Some thing else I thought about in your code: Even though you’re delaying for a second between calls to the
SonarRead()
function, you were actually parsing and keeping the first 10 readings the sensor took after power on (about 166ms apart) and just processing them 1 second apart. That’s because as long as the sonar is sending data (which is continuously while it is powered) and you’re listening to it with SoftwareSerial, the characters are being stored in the buffer. Once the buffer is full, they just get thrown away. Nothing comes out of the buffer until you
read()
it. When you do read it, you’re reading out in the order they were placed into the buffer, even if they were placed there a while ago. The fix I suggested for the sleep will also fix this because the end() will dump the buffer and it will be re-created empty at the begin().
I doubt going up to 25 attempts will make much of a difference.
-
2019-12-23 at 4:31 PM #13488
Did the modification I suggested get your board to go back to sleep and stay asleep?
-
2020-01-07 at 8:02 AM #13536
Thanks for your use of the MaxBotix Sensors. As such, Sara Damiano’s response regarding the 300mm reported value is correct. This is often caused by object defections or condensation. We offer a self-cleaning version of sensor that provides a more robust condensation solution. Link (https://www.maxbotix.com/product-category/all-environments/scxl-maxsonar-wr-products)
Should you have any further sensor questions, please let me know and I will be happy to help. The best way to contact us is at the following link ( https://www.maxbotix.com/contact.htm)
Scott Wielenberg
MaxBotix Inc.
techsupport@maxbotix.com -
2020-01-08 at 1:37 PM #13553
We just finished the last of a series of tests of the Maxbotix. With the changes which Sara suggested (close the serial port after each log interval and restart it for each new consectutive interval), the sleep code does work if the sensor is continuously powered.
Setup: Maxbotix 7389 sensor with the target either stream water or a fixed/flat metal plate approx 1/2 meter on a side. Before all testing (with 2 sensors), the sensor faces were coated with a very thin coating of fluoropolymer grease (very hydrophobic) to help shed any condensation.
Results:
1. Sensor mounted over a standpipe in water. Ambient temperature near 20 C. Frequent bad data (300) with normal serial read using code originally supplied by Shannon Hicks. Sensor powered by Mayfly digital pin only when logging.2. We suspected that there might be some interaction between the sensor and logger. Tried reading in the serial data with 50 milliseconds delay between each digit. This very slow read out of the data- have never seen this in the literature, gave a partial solution. This eliminated the bad data until fall when temperatures dropped down to about 10 C at night. Then bad data again occurred.
3. Sensor tested with a boom mount over the water or metal plate with intermittent power, but no standpipe. Results still showed some bad data points, even with traps to reread up to 20 times in the event of bad data. The bad data occurred at random times, when the temps were well above freezing and below freezing. The conclusion is that condensation on the sensor face is not the issue.
4. The final test was a 10 day test, 5 minute intervals, with sensor continuously powered independently by a separate battery power pack. During that time, the angle of the sensor from perpendicular to the target was varied from 0 degrees up to 5 degrees (to help shed potential condensation if any occurred). During that time, the temperatures ranged from as high as 15 C and as low as -5 C. Absolutely no bad data points were measured during the entire test.
Conclusions:
a. We saw no evidence that the sensor had any issue related to condensation during the tests given that there was a hydrophobic coating on the sensor face and that the bad data occurred at random temperatures as opposed to only when the temperatures were low.b. Reading out the serial data with a pause between digits rather than at normal speed seemed to help eliminate bad data when the weather was warm. But, this did not solve the problem when cooler weather arrived in the fall.
c. There was no bad data during the testing of the sensor with continuously power independent of the Mayfly, including at temperatures well below freezing.
Recommendation: If the Maxbotix 7389 sensor is used and a criterion is to log absolutely no bad data (such as when the data is used to control a pump sampler as we intend), it is recommended that sensor power be supplied continuously by an independent power pack.
I will be happy to forward or post data files if anyone wants to see the raw data.
-
2020-01-08 at 7:13 PM #13559
a. We saw no evidence that the sensor had any issue related to condensation during the tests given that there was a hydrophobic coating on the sensor face and that the bad data occurred at random temperatures as opposed to only when the temperatures were low.
That’s good to know. What was the fluoropolymer grease you used?
b. Reading out the serial data with a pause between digits rather than at normal speed seemed to help eliminate bad data when the weather was warm. But, this did not solve the problem when cooler weather arrived in the fall.
I’m not quite sure what your code looked like, but this doesn’t make sense, so of course it doesn’t make a difference. The Maxbotix talks to your Mayfly at 9600baud sending an R####\r every cycle (150ms-ish). That is exactly the rate that the Mayfly listens and records the data in. That’s not a changeable setting. Any “pause” you add in your code is just a pause in reading out from the buffer that whatever underlying serial library you’re using already stored the characters in. No matter the rate you read your data out from the buffer at, the input rate doesn’t change. The only caveat to that is that SoftwareSerial is just pretending to be a serial port and so it’s possible to throw off the character accuracy if the processor is doing too much when the characters come in. The result of the SoftwareSerial errors would be total garbage though (as in not even printable characters), not readings like “R0300\r”.
c. There was no bad data during the testing of the sensor with continuously power independent of the Mayfly, including at temperatures well below freezing.
Good to know it works. Good to know. Assuming you’re not manually triggering the sonar every time, that’s the internal range filtering doing its job. I’d guess you could get similar results by powering up the sonar just 5-10 seconds before taking a reading. Based on the spec sheet, it takes 5 readings for the filtering to take effect. It doesn’t specify the maximum number of readings the filtering considers, but the sonar “boots” up in ~160ms and, as long as pin 4 is left floating, completes a reading every ~148ms. So if you power up the Maxbotix for even 10s before you accept readings (10s before opening your serial port that is) it will have already had a chance to take over 60 readings which is probably plenty for good filtering.
-
-
-
AuthorPosts
- You must be logged in to reply to this topic.