Asset Tracker: Wake Up upon position change?

I’m trying to figure out how to do this, by combining the two examples from the LIS3DH library on wake ups from movement, and position change. I however have had no luck with this, and I feel like I’m just cluelessly searching around for a solution. Here’s my code: https://go.particle.io/shared_apps/59655abc64245d03ac0012d9

As of now, the sensor simply wakes up on movement, and disregards position change.What I want it to do, is to remain in sleep mode as sleep as it remains flat, but once it for example is held upside down, it will wake up from it.

Any tips?

But how will you know it’s upside down if it’s asleep? The accelerometer can generate an interrupt based on movement, but I don’t think you can pre-program a certain orientation it needs to be in.
You can try waking up only the microcontroller and not fh e radio to check the orientation before determining what to do next.

This probably should be possible, but it didn’t seem to work quite right for me either.

Using the AssetTrackerRK library:


#include "Particle.h"

#include "LIS3DH.h"

// System threading is required for this project
SYSTEM_THREAD(ENABLED);

// This example doesn't use cellular so it's turned off to save data. Position wake-up
// works fine with cellular on as well.
SYSTEM_MODE(MANUAL);

// Global objects
LIS3DHSPI accel(SPI, A2, WKP);

const unsigned SLEEP_TIME_SEC = 3600;
const uint8_t movementThreshold = 32;

bool hasAccel = false;
bool positionChanged = false;

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

	Serial.println("resetting accelerometer");

	LIS3DHConfig config;
	config.setLowPowerWakeMode(movementThreshold);

	// For position detection instead of motion detection, enable these:
	// AOI-6D = '01' is movement recognition. An interrupt is generate when orientation move from unknown zone to known zone.
	// The interrupt signal stay for a duration ODR.
	// Not set: LIS3DH::INT1_CFG_AOI
	config.int1_cfg |= LIS3DH::INT1_CFG_6D;

	hasAccel = accel.setup(config);
	if (!hasAccel) {
		Serial.println("accelerometer not found");
	}

}


void loop() {

	if (!hasAccel) {
		return;
	}

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

	Serial.println("going to sleep");

	// Sleep
	System.sleep(WKP, RISING, SLEEP_TIME_SEC);

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

	positionChanged = ((accel.clearInterrupt() & LIS3DH::INT1_SRC_IA) != 0);
	Serial.printlnf("positionChanged=%d", positionChanged);
}

Setting the 6D bit in INT1_CFG should enable position detection, according the LIS3DH app node AN3308. I’m not positive it’s actually working, however. It seems to trigger with sufficient movement without an orientation change for me. I’m not sure why.

1 Like

Ah I see! Thanks for your reply. I suppose the most effective way for me remains to just have it wake up from acceleration.

1 Like

Instead of relying on a changing position, I’m trying to have the sensor wake up based purely on movement. However, I can’t find a way to actually make the sensor less sensitive than the default setting.For instance, I have this:

const uint8_t movementThreshold = 30
(line 42 in https://go.particle.io/shared_apps/596669df7b2c3ae07900124f)

and it seems to be exactly the same as when it was at 16. Any thoughts on this?

Change this line of code:

config.setLowPowerWakeMode(16);

The 16 should be movementThreshold.

Sorry for asking so many questions - though I can’t quite figure this one out. I have some issues where my sensor is wrongfully activated - so instead of getting false alerts, I tried to build in an additional check. After the sensor wakes up, it goes into a new state, where it enters standby sleep mode for 5 seconds; if the sensor isn’t woken up during this time, it enters sleep mode, if it is, it will continue to GPS_Wait_State. Issue here however is that it it will always go back to sleep mode regardless. Here’s the code:

case SLEEP_TRIGGER_STATE:  {
	
	Serial.println("resetting accelerometer");

	LIS3DHConfig config;
	config.setLowPowerWakeMode(10);
   
    delay(5000);
   
   	System.sleep(WKP, RISING, 5000, SLEEP_NETWORK_STANDBY);
   	
   	awake = ((accel.clearInterrupt() & LIS3DH::INT1_SRC_IA) != 0);

	Serial.printlnf("awake=%d", awake);
	
    if (awake != 0) {
		state = GPS_WAIT_STATE;
		break;
	}

	state = SLEEP_STATE;
	}
	break;

Probably this is not the correct way to do it. Is there any way for a sensor to pick one or the other state depending on whether an acceleration was measured by the LIS3DH?

Just for clarification

This is Stop Mode sleep for th µC (with the radio in standby). Standby sleep would reset the device on wake and hence not execute the follow-up checks.

Ah I see!

Do you have any recommendations how I could do what I want to do? Essentially, I just want to have the device be idle for a few seconds; if movement is detected in that time it enters state A, if not it enters State B. I’ve been thinking for ways to do it with the limited knowledge I have regarding code structure but nothing seems to work well for me, and I can’t find any examples of it in the libraries I digged through.

I suppose sleep-mode in general would be unfavourable for the power consumption of the electron?

If energy conservation is not your prime focus for these 5sec idle time, you could have a particular state that does the waiting like

void loop() {
  static uint32_t _msWait = 0;
  ...
    case SLEEP_TRIGGER_STATE:  {
      Serial.println("just woke from rock");
      _msWait = millis();
      state  = WAIT_FOR_MORE_MOVEMENT
      break;
    case WAIT_FOR_MORE_MOVEMENT:
      if (millis() - _msWait < 5000) return;
      state = NOW_MOVE_ON;
      break;
  ...
}

I tried following your example by adopting it into my code:

https://go.particle.io/shared_apps/5967ce6faff8d512f6000fc6

From sleep state it’ll enter Sleep_Trigger state, and from there move into Verification_State. But once it wakes up from sleep, after connecting it will just breathe cyan continously. Something seems amiss here.

Not entirely sure if this is the only factor, but I think this is not what you want to do there

112	case SLEEP_TRIGGER_STATE:
113	    Serial.println("measuring time");
114	    
115	    _msWait = millis();
116	    state: VERIFICATION_STATE;  // <-- this should probably be: state = VERIFICATION_STATE;
117  	
118	    break;

Oh yea, of course!

With this adjustment, the bug is (obviously) fixed...but regardless of movement the sensor will still always enter publish mode. Not sure what it is. Here's the two modes: I expect the sensor, while in Sleep Trigger state, to count the time it takes for uint32_t to be triggered, and if that time is less than 5 seconds, it will enter GPS wait state.

case SLEEP_TRIGGER_STATE: {
Serial.println("measuring time");

  _msWait = millis();
  state = VERIFICATION_STATE;
	
  break;
case VERIFICATION_STATE: 
    if (millis() - _msWait < VERIFICATION_TIME) {
        state = GPS_WAIT_STATE;
        break;
    }
	state = SLEEP_STATE;

}

Did you figure this out?

Hi,

No I didn’t. As some people have stated, it doesn’t really seems to work, so I stuck with regular movement-interruption for my project.

6 posts were merged into an existing topic: Help choosing correct SLEEP mode w/ Asset Tracker v2