Building a Shake-to-Stream Motion Sensor Device
I wanted to create a device that could be activated by shaking it and then stream motion data efficiently to a smartphone. The goal was to make something useful for motion tracking applications while keeping power consumption reasonable and data transmission efficient.
The Hardware Choice
I went with the Seeed Studio Xiao nRF52840 Sense because it combines the Nordic nRF52840 Bluetooth SoC with an onboard LSM6DSL 6-axis IMU sensor. This gave me everything I needed in a tiny package - Bluetooth connectivity, motion sensing, and enough processing power to handle the data efficiently.
The Core Challenge: Efficient Data Streaming
The main technical challenge was streaming high-frequency motion data over Bluetooth efficiently. I needed to balance several competing requirements:
High enough sampling rates to capture meaningful motion (up to 416Hz from the LSM6DSL)
Efficient use of Bluetooth bandwidth
Reasonable power consumption
Configurable parameters for different use cases
Data Batching Implementation
Instead of sending individual sensor readings, I implemented a batching system that groups multiple samples together before transmission. The device collects up to 18 samples (each containing 6-axis data: 3-axis accelerometer + 3-axis gyroscope) into a single packet.
The batching logic works on two triggers:
Count-based: Send when the batch reaches 18 samples
Time-based: Send after 500ms timeout, even with fewer samples
I used a binary format to maximize efficiency - each sample is packed into just 12 bytes using 16-bit integers with appropriate scaling factors. This gives me good resolution while keeping packet sizes manageable for Bluetooth's MTU limitations.
Motion-Based Adaptive Sampling
To improve power efficiency, I implemented adaptive sampling rates based on motion detection. The device runs at two different frequencies:
Idle mode: 12Hz when no motion is detected
Active mode: 52Hz when motion is ongoing
The motion detection uses variance analysis across a sliding window of accelerometer samples. When the variance exceeds a threshold (configurable, default 0.5G), the device switches to active mode. It stays in active mode for a timeout period (default 1 second) after the last detected motion.
This approach significantly reduces power consumption during idle periods while ensuring high-quality data capture during actual motion events.
Shake Detection for Device Activation
The shake detection works by calculating the sum of absolute differences between consecutive accelerometer readings across all three axes. When this sum exceeds a threshold (default 20G total change), it triggers a shake event.
I use shake detection to automatically start Bluetooth advertising when the device is disconnected. This creates an intuitive user experience - shake the device to make it discoverable again.
Bluetooth Range Issues and Power Boost
During testing, I encountered range limitations that made the device impractical for some use cases. The solution was to increase the Bluetooth transmit power to +8dBm (the maximum supported by the nRF52840) and use Coded PHY S=8 mode.
Coded PHY S=8 trades data rate for range - it runs at 125 kbps instead of the standard 1 Mbps, but provides significantly better range and reliability. The device automatically requests this mode when connecting to ensure maximum range performance.
Configuration Management
I wanted the device to be configurable without reflashing firmware, so I implemented a comprehensive configuration system accessible via Bluetooth commands. Users can adjust:
Motion detection thresholds and timeouts
Sampling rates for both idle and active modes
Shake detection sensitivity
Advertising timeouts
Data transmission settings
All configuration changes are stored in non-volatile storage and persist across power cycles.
Interrupt-Driven Architecture
The IMU sensor supports data-ready interrupts, which I use to minimize CPU usage and improve timing accuracy. When new sensor data is available, the LSM6DSL triggers an interrupt that immediately reads the data and queues it for processing.
This approach is much more efficient than polling and ensures I don't miss samples even at higher sampling rates.
Results
The final implementation successfully meets the original goals:
Shake-to-activate functionality works reliably
Motion data streams at up to 52Hz during active periods
Data batching reduces Bluetooth overhead significantly
Adaptive sampling provides good power efficiency
Extended range through higher transmit power and Coded PHY
Fully configurable via Bluetooth commands
The device has proven useful for motion tracking applications where you need responsive activation, efficient data collection, and reasonable battery life. The configurable nature means it can be adapted to different use cases without firmware changes.
The most satisfying aspect was solving the efficiency puzzle - balancing sample rates, batch sizes, transmission timing, and power management to create something that actually works well in practice rather than just meeting the basic requirements.