System.sleep and WKP Pin


#2

I did a bunch of experiments with wake on move, and I never had a problem with sleeping until WKP or 4 hours. Every 4 hours I’d report battery stats. Here’s the post and the code that I used for different accelerometers:


#3

Rickkas7 - thanks! Curious - I’m using the tracker shield put out by Particle - did you happen to test the Asset Tracker shield?


#4

Yes, there’s a LIS3DH version that works with AssetTracker in the Github link in the community post. It worked quite well!


#5

OH!!! So the library that seems to be offered up by Particle isn’t the preferred one?


#6

The problem is that the LIS3DH library built into the asset tracker library was missing some features I wanted to use. I planned to merge my changes into the official library and do a pull request, but I never got around to doing it.


#7

@n8xja, I think you are mixing units here
You are using millis() in conjunction with System.sleep(), but the time to sleep is given in seconds not milliseconds :wink:

Additionally you might want to use SLEEP_NETWORK_STANDBY and have a look at the recent update notice about 0.6.0-rc.1


#8

ScruffR, Thanks for pointing that out - I caught to.

I’ll take a look at the RC as well.

Appreciate it - thanks!


#9

I’ve been getting my head around the LIS3DH “driver” mentioned and while I understand how to use setup up the “WKP” feature that aluded me on the other driver, I don’t understand how to read the readXYZmagnitude or the x,y,z values. Must be something I’m just missing so any pointers are appreciated.

EDIT-Added: I’m not an expert of reading data sheets and translating that to code by any stretch. I do not see anything congruent between the LIS3DH driver in the community provided side vs the Particle provided accelerometer driver.(Is driver the right term for this?) In case there maybe a better way than what I am thinking of, as long as there is motion as seen by the accelerometer, I do want to keep the Electron awake. After motion has stopped for a given amount of time, the code would put the accelerometer to sleep for at least 60 minutes or if the motion returned, which ever was first. I used values determined experimentally to determine what the “keep awake” threshold from the accelerometer. So after re-coding for the LIS3DH driver which does seem to wake up the Electron, I couldn’t figure out how to read, while the electron was awake the X,Y,Z values.

Thank you!


#10

I’m still having that issue, any way to solve that?


#11

Danpe - You might want to try the library: AssetTrackerRK


#12

Thanks for the plug. AssetTrackerRK in the community libraries in Particle Build (Web IDE) as “AssetTrackerRK” and here:

I changed the way the LIS3DH wake-on-movement code works and it’s much more reliable now. Before I just turned off Z axis detection, which is only effective in canceling gravity when sitting flat. Now it correctly handles gravity compensation so you can put it asleep tilted and it will wake properly.

It’s almost a drop-in replacement for the official AssetTracker library. It also uses TinyGPS++ instead of the Adafruit GPS library; I find the TinyGPS++ parser to be more reliable.


#13

Thanks guys!

When I’m using the original AssetTracker WakeOnMove example.

on 0.5.3 electron firmware version it stopped waking up the device after an hour.
Now after updating to 0.6.0-RC2 it takes about 3-4 hours of no movement to stop waking up the device.

I just flashed the AssetTrackerRK example, will keep you posted.


#14

I wrote both versions of the LIS3DH wake on move code, but the new one in AssetTrackerRK works much better for me. I’ll get the new version moved into the official AssetTracker code once a few people have confirmed that indeed it works better. I’ve seen the failure to wake up with the old code but not the new code but since it doesn’t always happen it’s hard to prove that it’s fixed.


#15

rickkas7 - I don’t know if this is helpful to you as the author of the library but I wanted to throw it out there. I’ve been using readXYZmagnitude() in while the electron is awake to determine if there is any movement at all, in all 3 axis. During testing, when readXYZmagnitude() > 9000, I know there whether or not the device I’m tracking is in motion.

Initial tests seems that the default movement threshold used in waking up is 16 but that does not seem sensitive enough. I have not adjusted that value yet (not sure if decreasing the value increases sensitivity or not) If I read correctly your comments, that waking on movement only responds to the Z axis. Is there a way to have it wake up to the something akin to values read from readXYZmagnitude?


#16

I presume this is for the official AssetTracker library? I wouldn’t recommend using the wake on move in that library, as it currently does not work reliably. But smaller values make it more sensitive.

The AssetTrackerRK uses a completely different method of detecting movement. First, it only allows sleep when the device is not moving, and you can also set a time for no movement before allowing sleep. The reason for this is that the LIS3DH requires a calibration for its resting position so it can cancel out gravity regardless of orientation.

This is the sample program I use to test calibration with AssetTrackerRK. It’s much easier because it prints debugging serial messages instead of putting the device to sleep, so you can rapidly see what’s happening when you adjust the time threshold and also the sensitivity setLowPowerWakeMode(16).

#include "Particle.h"

#include "AssetTrackerRK/LIS3DH.h"

// Example of using the movement detection feature and SPI connection, like the asset tracker.
// Instead of actually putting the device to sleep, this prints information which is handy
// for debugging purposes. The WakeOnMove example actually uses sleep mode.

SYSTEM_THREAD(ENABLED);

void movementInterruptHandler();

// LIS3DH is connected as in the AssetTracker, to the primary SPI with A2 as the CS (SS) pin, and INT connected to WKP
LIS3DHSPI accel(SPI, A2, WKP);

bool sensorsInitialized;
unsigned long lastPrintSample = 0;

volatile bool movementInterrupt = false;
uint8_t lastPos = 0;

void setup() {
	Serial.begin(9600);

	attachInterrupt(WKP, movementInterruptHandler, RISING);

	delay(5000);

	// Initialize sensors
	LIS3DHConfig config;
	config.setLowPowerWakeMode(16);

	sensorsInitialized = accel.setup(config);
	Serial.printlnf("sensorsInitialized=%d", sensorsInitialized);
}

void loop() {

	if (movementInterrupt) {
		accel.clearInterrupt();

		Serial.println("movementInterrupt");

		// Recalibrate the accelerometer for possibly being in a new orientation.
		// Wait up to 15 seconds for it to be stationary for 2 seconds.
		bool ready = accel.calibrateFilter(2000, 15000);
		Serial.printlnf("calibrateFilter ready=%d", ready);

		movementInterrupt = false;
	}
}

void movementInterruptHandler() {
	movementInterrupt = true;
}



#17

With setLowPowerWakeMode - does lowering the value make it more sensitive or less sensitive?


#18

The movement threshold is an unsigned 7-bit number (0-127) and smaller values are more sensitive. The default is 16.

The absolute value of the acceleration is compared to this threshold. So if you have -25 acceleration, you would exceed the threshold of +16 and wakeup would still occur.

There is some conversion between these values and actual G values, but it depends on the scale range and I’m not exactly sure how it works.


#19

Hi Rick,

I must say your new AssetTrackerRK is much more reliable and makes more sense on the logic behind it.

I think I found the cause of why the device doesn’t wake up, I ran a tests in the last (almost) 2 days.

When I’m using your example as is with:
const unsigned long TIME_PUBLISH_BATTERY_SEC = 22 * 60; // every 22 minutes send a battery update to keep the cellular connection up
Then everything works as expected. super professional even woke up after 10 hours.

When I’m changing it back to
const unsigned long TIME_PUBLISH_BATTERY_SEC = 4 * 60 * 60; // every 4 hours send a battery update
Then the issues starts, and the device won’t wake up after ~2 hours. and this reproduces it self 100% of the times.

I’m on the latest 0.6.0-RC2 btw.

Any thoughts on that?


#20

Thanks! The behavior you’re seeing is interesting. What options are you using for sleep? I’ll give it a try with the same options.


#21

I’m using the exact one from the examples:

case SLEEP_STATE:
  // Wait for Electron to stop moving for 2 seconds so we can recalibrate the accelerometer
  accel.calibrateFilter(2000);

  // Is this necessary?
  //digitalWrite(D6, HIGH);
  //pinMode(D6, INPUT);

  Serial.println("going to sleep");
  delay(500);

  // Sleep
  System.sleep(WKP, RISING, TIME_PUBLISH_BATTERY_SEC, SLEEP_NETWORK_STANDBY);

  // This delay should not be necessary, but sometimes things don't seem to work right
  // immediately coming out of sleep.
  delay(500);

  awake = ((accel.clearInterrupt() & LIS3DH::INT1_SRC_IA) != 0);

  Serial.printlnf("awake=%d", awake);

  // Restart the GPS
  //pinMode(D6, OUTPUT);
  digitalWrite(D6, LOW);
  startFix = millis();
  gettingFix = true;

  state = GPS_WAIT_STATE;
  stateTime = millis();
  break;

Am I missing something?