diff --git a/OpenEphys.Onix1/ConfigurePolledBno055.cs b/OpenEphys.Onix1/ConfigurePolledBno055.cs
index 5577f82..3bbda70 100644
--- a/OpenEphys.Onix1/ConfigurePolledBno055.cs
+++ b/OpenEphys.Onix1/ConfigurePolledBno055.cs
@@ -5,8 +5,7 @@
namespace OpenEphys.Onix1
{
///
- /// Configures a Bosch Bno055 9-axis inertial measurement unit (IMU) that is polled by the
- /// computer.
+ /// Configures a Bosch Bno055 9-axis inertial measurement unit (IMU) that is polled by the host computer.
///
///
/// This configuration operator can be linked to a data IO operator, such as
- /// Copy constructor for the class.
+ /// Initializes a new instance of with its properties copied from an
+ /// existing instance.
///
/// A pre-existing object.
public ConfigurePolledBno055(ConfigurePolledBno055 configurePolledBno055)
@@ -126,7 +126,7 @@ void ConfigureBno055(DeviceContext device)
static class PolledBno055
{
public const int BNO055Address = 0x28;
- public const int DataAddress = 0x1A;
+ public const int EulerHeadingLsbAddress = 0x1A;
internal class NameConverter : DeviceNameConverter
{
@@ -216,7 +216,7 @@ public enum Bno055AxisSign : uint
MirrorX = 0b00000_100,
}
- // NB: Can be used to remove axis map and sign properties from MutliDeviceFactories that include a
+ // NB: Can be used to remove axis map and sign properties from MultiDeviceFactories that include a
// ConfigurePolledBno055 when having those options would cause confusion and potential
// commutator malfunction
internal class PolledBno055SingleDeviceFactoryConverter : SingleDeviceFactoryConverter
diff --git a/OpenEphys.Onix1/PolledBno055Data.cs b/OpenEphys.Onix1/PolledBno055Data.cs
index 884d66c..876ed88 100644
--- a/OpenEphys.Onix1/PolledBno055Data.cs
+++ b/OpenEphys.Onix1/PolledBno055Data.cs
@@ -1,6 +1,7 @@
using System;
using System.ComponentModel;
using System.Linq;
+using System.Reactive.Concurrency;
using System.Reactive.Linq;
using Bonsai;
@@ -8,7 +9,7 @@ namespace OpenEphys.Onix1
{
///
/// Produces a sequence of Bno055DataFrames from Bosch Bno055
- /// 9-axis inertial measurement unit (IMU)
+ /// 9-axis inertial measurement unit (IMU) by polling it from the host computer.
///
///
/// This data IO operator must be linked to an appropriate configuration, such as a
public string DeviceName { get; set; }
///
- /// Generates a sequence of Bno055DataFrames at approximately 100
- /// Hz.
+ /// Gets or sets which data registers should be collected from the Bno055.
///
///
- /// This will generate a sequence of Bno055DataFrames at approximately 100 Hz.
- /// This rate may be limited by the hardware.
+ /// The rate that data is sampled is limited by communication with the Bno055 by the host PC (rather
+ /// than a dedicated controller on the headstage). If the user wishes to maximize the sampling rate of
+ /// particular measurements, they can select which should be sampled using this property. For
+ /// instance, specifying "Quaternion, Calibration" means that only the quaternion and sensor
+ /// calibration status registers will be polled and the rest of the members of , with the exception of Clock and HubClock, will be set to
+ /// 0.
+ ///
+ [Category(DeviceFactory.ConfigurationCategory)]
+ [Description("Specifies which data registers should be read from the chip.")]
+ [TypeConverter(typeof(FlagsConverter))]
+ public PolledBno055Registers PolledRegisters { get; set; } = PolledBno055Registers.All;
+
+ ///
+ /// Use a ~100 Hz internal timer to generate a sequence of Bno055DataFrames.
+ ///
+ ///
+ /// An internal timer will be used to poll the Bno055 in order to generate a sequence of Bno055DataFrames at approximately 100 Hz. This rate may be limited by
+ /// hardware communication speeds (see ).
///
/// A sequence of Bno055DataFrames.
public override IObservable Generate()
{
- // Max of 100 Hz, but limited by I2C bus
- var source = Observable.Interval(TimeSpan.FromSeconds(0.01));
+ // NB: NewThreadScheduler runs polling on dedicated thread and uses StopWatch for high resolution
+ // periodic measurements. This results in much better performance than the default scheduler.
+ var source = Observable.Interval(TimeSpan.FromMilliseconds(10), new NewThreadScheduler());
return Generate(source);
}
@@ -44,14 +63,17 @@ public override IObservable Generate()
/// input sequence.
///
///
- /// This will attempt to produce a sequence of Bno055DataFrames that is updated whenever
- /// an item in the sequence is received. This rate is be limited by the
- /// hardware and has a maximum meaningful rate of 100 Hz.
+ /// This will attempt to produce a sequence of Bno055DataFrames that
+ /// is updated whenever an item in the sequence is received. This rate may
+ /// be limited by the hardware communication speeds (see ) and has a
+ /// maximum meaningful rate of 100 Hz, which is the update rate of the sensor fusion algorithm on the
+ /// Bno055 itself.
///
/// A sequence to drive sampling.
- /// A sequence of objects.
+ /// A sequence of Bno055DataFrames.
public unsafe IObservable Generate(IObservable source)
{
+ var polled = PolledRegisters;
return DeviceManager.GetDevice(DeviceName).SelectMany(
deviceInfo =>
{
@@ -68,7 +90,42 @@ public unsafe IObservable Generate(IObservable
{
- var data = i2c.ReadBytes(PolledBno055.DataAddress, sizeof(Bno055DataPayload));
+ byte[] data = {
+ polled.HasFlag(PolledBno055Registers.EulerAngle) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 0) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.EulerAngle) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 1) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.EulerAngle) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 2) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.EulerAngle) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 3) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.EulerAngle) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 4) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.EulerAngle) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 5) : (byte)0,
+
+ polled.HasFlag(PolledBno055Registers.Quaternion) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 6) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Quaternion) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 7) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Quaternion) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 8) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Quaternion) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 9) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Quaternion) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 10) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Quaternion) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 11) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Quaternion) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 12) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Quaternion) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 13) : (byte)0,
+
+ polled.HasFlag(PolledBno055Registers.Acceleration) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 14) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Acceleration) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 15) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Acceleration) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 16) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Acceleration) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 17) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Acceleration) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 18) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Acceleration) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 19) : (byte)0,
+
+ polled.HasFlag(PolledBno055Registers.Gravity) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 20) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Gravity) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 21) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Gravity) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 22) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Gravity) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 23) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Gravity) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 24) : (byte)0,
+ polled.HasFlag(PolledBno055Registers.Gravity) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 25) : (byte)0,
+
+ polled.HasFlag(PolledBno055Registers.Temperature) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 26) : (byte)0,
+
+ polled.HasFlag(PolledBno055Registers.Calibration) ? i2c.ReadByte(PolledBno055.EulerHeadingLsbAddress + 27) : (byte)0,
+ };
+
ulong clock = passthrough.ReadRegister(DS90UB9x.LASTI2CL);
clock += (ulong)passthrough.ReadRegister(DS90UB9x.LASTI2CH) << 32;
fixed (byte* dataPtr = data)
@@ -85,6 +142,69 @@ public unsafe IObservable Generate(IObservable
+ /// Specifies which data registers will be read from the Bno055 during each polling cycle.
+ ///
+ [Flags]
+ public enum PolledBno055Registers
+ {
+ ///
+ /// Specifies that the Euler angles will be polled.
+ ///
+ EulerAngle = 0x1,
+
+ ///
+ /// Specifies that the quaternion will be polled.
+ ///
+ Quaternion = 0x2,
+
+ ///
+ /// Specifies that the linear acceleration will be polled.
+ ///
+ Acceleration = 0x4,
+
+ ///
+ /// Specifies that the gravity vector will be polled.
+ ///
+ Gravity = 0x8,
+
+ ///
+ /// Specifies that the temperature measurement will be polled.
+ ///
+ Temperature = 0x10,
+
+ ///
+ /// Specifies that the sensor calibration status will be polled.
+ ///
+ Calibration = 0x20,
+
+ ///
+ /// Specifies that all sensor measurements and calibration status will be polled.
+ ///
+ All = EulerAngle | Quaternion | Acceleration | Gravity | Temperature | Calibration,
}
/// v
@@ -98,5 +218,4 @@ public class NeuropixelsV2eBno055Data : PolledBno055Data { }
/// v
[Obsolete("This operator is obsolete. Use PolledBno055Data instead. Will be removed in version 1.0.0.")]
public class NeuropixelsV2eBetaBno055Data : PolledBno055Data { }
-
}