dept-of-scrapyard-robotics / msa3xx
Drive MSA301 and MSA311 motion sensors over I2C with PHP
Package info
github.com/DeptOfScrapyardRobotics/MSA3xx
pkg:composer/dept-of-scrapyard-robotics/msa3xx
Requires
- php: ^8.3
- scrapyard-io/bare-metal: ^0.4.0
- scrapyard-io/reality-interface: ^0.4.0
- scrapyard-io/waveforms: ^0.4.0
Suggests
- scrapyard-io/gpio: ^0.4.0 - For direct linux-based GPIO
- scrapyard-io/i2c: ^0.4.0 - For direct linux-based I2C
- scrapyard-io/mpsse: ^0.4.0 - For I2C/GPIO over an FTDI Serial-to-USB Device
This package is auto-updated.
Last update: 2026-06-10 02:17:52 UTC
README
PHP Package for the MSA3xx-family of motion sensors.
Compatible I2C Interfaces
The MSA3xx sensors communicate with your device over I2C, the InterIntegrated Circuit Protocol.
You can interface with sensors like MSA311 with this package the following ways:
- A Linux Single-Board Computer's exposed GPIO pins using the dedicated I2C SDA/SCL pins
- An MPSSE-enabled USB-to-Serial device such as an FT232H generally using D0 for SCL and D1 for SDA connected to nearly any Linux or MacOS USB port.
The MSA311 has a fixed I2C address of 0x62 (the MSA301 uses 0x26). It does not expose an
SPI interface.
Dependencies
This package makes use of modules within:
This package also requires one of the following extensions in order to interface with I2C
In addition, an extension wrapper package is needed
For ext-posi
For ext-ftdi
Installing from Composer
Inside the root of your PHP Project, simply require the MSA3xx package from composer
composer require dept-of-scrapyard-robotics/msa3xx
Framework Configuration
If you would like to use the ScrapyardIO Framework to bootstrap your sensor without wasting lines configuring your sensor right in the script you can add your desired configuration to scrapyard-io.php, such as in this example:
I2C
use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\MSA311; use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\Enums\MSA311I2CAddress; return [ 'boards' => [ // For Native Configurations 'msa311-native' => [ 'class_name' => MSA311::class, 'connection' => ['driver' => 'native'], 'startup' => [ 'i2c' => [ 'chip_device' => 1, 'slave_address' => MSA311I2CAddress::DEFAULT->value, ], ], ], // For USB Configurations 'msa311-usb' => [ 'class_name' => MSA311::class, 'connection' => ['driver' => 'usb'], 'startup' => [ 'i2c' => [ 'chip_device' => 'ft232h', 'slave_address' => MSA311I2CAddress::DEFAULT->value, ], ], ], ] ];
Basic Usage
Native (POSIX) I2C driver. (Single Board Computers)
use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\MSA311; use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\Enums\MSA311I2CAddress; $native_i2c_sensor = MSA311::connection('native') ->i2c(1, MSA311I2CAddress::DEFAULT->value) ->create() [$x, $y, $z] = $native_i2c_sensor->acceleration;
USB (MPSSE) driver using I2C. (Linux and MacOS)
use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\MSA311; use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\Enums\MSA311I2CAddress; $usb_i2c_sensor = MSA311::connection('usb') ->i2c('ft232h', MSA311I2CAddress::DEFAULT->value) ->create() [$x, $y, $z] = $usb_i2c_sensor->acceleration;
Alternative Usage
Using Through the Sensor Library (as an Accelerometer)
use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\MSA311; use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\Enums\MSA311I2CAddress; use RealityInterface\Sensors\Applied\Accelerometry\Accelerometer; $msa311 = MSA311::connection('native') ->i2c(1, MSA311I2CAddress::DEFAULT->value) ->create(); $sensor = Accelerometer::as($msa311); $data = $sensor->getAcceleration();
Using Through the Sensor Framework (with an autoloaded config) (as an Accelerometer)
use RealityInterface\Sensors\Applied\Accelerometry\Accelerometer; $sensor = Accelerometer::using('msa311'); $data = $sensor->getAcceleration();
Advanced Usage
You can preset the sensor's output data rate and range while building the connection:
use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\MSA311; use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\Enums\MSA311DataRate; use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\Enums\MSA311I2CAddress; use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\Enums\MSA311Range; $sensor = MSA311::connection('native') ->i2c(1, MSA311I2CAddress::DEFAULT->value) ->dataRate(MSA311DataRate::HZ500) ->fullScaleRange(MSA311Range::G4) ->create();
You can also tune measurement behavior at runtime using the MSA311's configuration properties:
data_ratecontrols the output data rate and power consumption.rangecontrols the full-scale measurement range (±2 g to ±16 g).power_modeselectsNORMAL,LOW_POWER, orSUSPENDoperation.bandwidthcontrols the low-power-mode filter bandwidth.x_axis_enabled,y_axis_enabled,z_axis_enabledtoggle individual axes.
use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\MSA311; use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\Enums\MSA311Bandwidth; use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\Enums\MSA311DataRate; use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\Enums\MSA311I2CAddress; use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\Enums\MSA311PowerMode; use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\Enums\MSA311Range; $sensor = MSA311::connection('native') ->i2c(1, MSA311I2CAddress::DEFAULT->value) ->create(); // Set output data rate to 250 Hz $sensor->data_rate = MSA311DataRate::HZ250; // Set full-scale range to ±8 g $sensor->range = MSA311Range::G8; // Keep the part in normal (full-power) mode $sensor->power_mode = MSA311PowerMode::NORMAL; // Tune the low-power bandwidth filter $sensor->bandwidth = MSA311Bandwidth::HZ125; // Disable the Z axis if you only care about the X/Y plane $sensor->z_axis_enabled = false;
The MSA311 is a fixed 12-bit part. The
resolutionfield exists in the RANGE_RESOLUTION register for MSA301 compatibility, but changing it has no effect on the MSA311's data width.
Tap Detection
Tap detection is configured with enableTapDetection() and polled with the tapped property:
use DeptOfScrapyardRobotics\Sensors\MSA3xx\MSA311\Enums\MSA311TapDuration; // Single-tap detection with a moderate threshold $sensor->enableTapDetection(tap_count: 1, threshold: 25); // Double-tap detection with a 250 ms double-tap window $sensor->enableTapDetection( tap_count: 2, threshold: 25, double_tap_window: MSA311TapDuration::MS250, ); // Poll for a tap event if ($sensor->tapped) { echo "Tap detected!"; }
Calibration
The MSA311 driver does not expose the per-axis hardware offset registers, so calibration is performed in software by collecting samples at a known orientation and applying a correction to subsequent reads.
Zero-G Offset Calibration
Place the sensor flat and level, then capture a baseline at rest:
$samples = 50; $sum_x = $sum_y = $sum_z = 0.0; for ($i = 0; $i < $samples; $i++) { [$x, $y, $z] = $sensor->acceleration; $sum_x += $x; $sum_y += $y; $sum_z += $z; usleep(10000); } $gravity = 9.806; $offset_x = $sum_x / $samples; // should be ~0 m/s² $offset_y = $sum_y / $samples; // should be ~0 m/s² $offset_z = ($sum_z / $samples) - $gravity; // should be ~0 m/s² after removing 1g // Apply offsets to subsequent reads [$raw_x, $raw_y, $raw_z] = $sensor->acceleration; $cal_x = $raw_x - $offset_x; $cal_y = $raw_y - $offset_y; $cal_z = $raw_z - $offset_z;
Range Selection and Sensitivity
Choosing the right range trades sensitivity for headroom. The MSA311 outputs 12-bit samples:
| Range | Sensitivity | Resolution |
|---|---|---|
| ±2 g | 1024 LSB/g | ~0.98 mg/LSB |
| ±4 g | 512 LSB/g | ~1.95 mg/LSB |
| ±8 g | 256 LSB/g | ~3.91 mg/LSB |
| ±16 g | 128 LSB/g | ~7.81 mg/LSB |
For most motion-sensing applications, G2 or G4 gives the best resolution. Use G8 or
G16 when measuring strong impacts or vibration.
Sensor API
The getters and setters in this API interface with the device directly (register reads/writes),
so you can use property access while still working against the sensor itself. Multi-setting
registers are broken out into DataObjects and fields that only accept specific values are
enum-backed.
Readable Properties (Getters)
-
$sensor->device_idReads and returns the MSA311 part ID. Should return0x13. -
$sensor->accelerationReads all three axes and returns a[x, y, z]array in m/s². -
$sensor->raw_x,$sensor->raw_y,$sensor->raw_zReturns the signed 12-bit raw output for a single axis (no scaling applied). -
$sensor->new_data_readyReads the DATA_INTERRUPT register and returnstruewhen a fresh sample is available. -
$sensor->tappedReturnstrueif a tap matching the configuredenableTapDetection()mode was detected. -
$sensor->motion_interruptReads and returns the fullMSA311MotionInterruptdata object (orientation, single/double tap, active and freefall status flags). -
$sensor->rangeReturns the currentMSA311Rangefull-scale measurement range. Possible values:G2,G4,G8,G16. -
$sensor->resolutionReturns the currentMSA311Resolution. Fixed at 12-bit behavior on the MSA311. Possible values:BIT14,BIT12,BIT10,BIT8. -
$sensor->data_rateReturns the currentMSA311DataRateoutput data rate. Possible values:HZ1,HZ1_95,HZ3_9,HZ7_81,HZ15_63,HZ31_25,HZ62_5,HZ125,HZ250,HZ500,HZ1000. -
$sensor->x_axis_enabledReturnstrueif the X axis is active. -
$sensor->y_axis_enabledReturnstrueif the Y axis is active. -
$sensor->z_axis_enabledReturnstrueif the Z axis is active. -
$sensor->power_modeReturns the currentMSA311PowerMode. Possible values:NORMAL,LOW_POWER,SUSPEND. -
$sensor->bandwidthReturns the currentMSA311Bandwidthlow-power filter bandwidth. Possible values:HZ1_95,HZ3_9,HZ7_81,HZ15_63,HZ31_25,HZ62_5,HZ125,HZ250,HZ500. -
$sensor->range_resolutionReads and returns the fullMSA311RangeResolutiondata object. -
$sensor->output_data_rate_registerReads and returns the fullMSA311OutputDataRatedata object (data rate plus per-axis enable flags). -
$sensor->power_mode_bandwidthReads and returns the fullMSA311PowerModeBandwidthdata object. -
$sensor->interrupt_set0Reads and returns the fullMSA311InterruptSet0data object (orientation / tap / active interrupt enables). -
$sensor->interrupt_set1Reads and returns the fullMSA311InterruptSet1data object (new-data and freefall interrupt enables). -
$sensor->interrupt_map0Reads and returns the fullMSA311InterruptMap0data object (event-to-INT1 routing). -
$sensor->tap_configReads and returns the fullMSA311TapConfigdata object (tap quiet/shock timing and the double-tap window).
Writable Properties (Setters)
-
$sensor->range = MSA311Range::G8;Sets the full-scale measurement range. -
$sensor->resolution = MSA311Resolution::BIT12;Writes the resolution field of the RANGE_RESOLUTION register. -
$sensor->data_rate = MSA311DataRate::HZ250;Sets the output data rate. -
$sensor->x_axis_enabled = true;Enables or disables the X axis. -
$sensor->y_axis_enabled = true;Enables or disables the Y axis. -
$sensor->z_axis_enabled = true;Enables or disables the Z axis. -
$sensor->power_mode = MSA311PowerMode::NORMAL;Sets the device power mode. -
$sensor->bandwidth = MSA311Bandwidth::HZ125;Sets the low-power-mode filter bandwidth. -
$sensor->range_resolution = new MSA311RangeResolution(...);Writes the full RANGE_RESOLUTION register from a data object. -
$sensor->output_data_rate_register = new MSA311OutputDataRate(...);Writes the full ODR register from a data object. -
$sensor->power_mode_bandwidth = new MSA311PowerModeBandwidth(...);Writes the full POWER_MODE_BANDWIDTH register from a data object. -
$sensor->interrupt_set0 = new MSA311InterruptSet0(...);Writes the full INT_SET_0 register from a data object. -
$sensor->interrupt_set1 = new MSA311InterruptSet1(...);Writes the full INT_SET_1 register from a data object. -
$sensor->interrupt_map0 = new MSA311InterruptMap0(...);Writes the full INT_MAP_0 register from a data object. -
$sensor->tap_config = new MSA311TapConfig(...);Writes the full TAP_DURATION register from a data object.
Methods
-
$sensor->getAcceleration(): arrayReads all three axes (each as a separate 2-byte transfer) and returns a[x, y, z]array in m/s². This is the method backing theaccelerationproperty and theGenericAccelerometercontract. -
$sensor->enableTapDetection(int $tap_count = 1, int $threshold = 25, bool $long_initial_window = true, bool $long_quiet_window = true, MSA311TapDuration $double_tap_window = MSA311TapDuration::MS250): voidConfigures single- (tap_count: 1) or double-tap (tap_count: 2) detection and enables the matching interrupt. ThrowsInvalidArgumentExceptionfor any other tap count.