Classes

  Name
class Apis
Arduino library for the Apis board, which manages a LiDAR Lite unit (roll/pitch, firmware lock/reset, power supply).

Types

  Name
enum uint8_t SensitivityMode { SENSITIVITY_BALANCED = 0, SENSITIVITY_HIGH = 1, SENSITIVITY_LOW = 2, SENSITIVITY_MAX_RANGE = 3}
Sensitivity mode for the LiDAR Lite acquisition pipeline.

Defines

  Name
  M_PI
  APIS_FW_MIN_PATCH
  APIS_LIBRARY_VERSION
  APIS_LIBRARY_COMMIT
  APIS_RANGE_CAPACITY
  APIS_ACCEL_M_PER_S2_PER_DIGIT
  APIS_ORIENT_CAPACITY
  APIS_ERROR
  APIS_NOT_MEASURED
  NW_READING_ALL
  NW_READING_PRIMARY
  NW_READING_SECONDARY
  NW_READING_RANGE
  NW_READING_ORIENT
  ADR_DEFAULT

Types Documentation

enum SensitivityMode

Enumerator Value Description
SENSITIVITY_BALANCED 0 Default. SIG_COUNT_VAL=0x80, THRESHOLD_BYPASS=0x00. Balanced range and noise performance.
SENSITIVITY_HIGH 1 THRESHOLD_BYPASS=0x80. Lower detection threshold; detects weaker returns at the cost of more false positives.
SENSITIVITY_LOW 2 THRESHOLD_BYPASS=0xB0. Higher detection threshold; fewer false positives at the cost of reduced range.
SENSITIVITY_MAX_RANGE 3 SIG_COUNT_VAL=0xFF. More acquisitions per measurement; longer maximum range, slower throughput.

Sensitivity mode for the LiDAR Lite acquisition pipeline.

Written to REG_CONFIG (0x46) by begin(); applied on every loop() iteration when the firmware reinitialises the LiDAR Lite via InitLiDAR(). Two LiDAR Lite registers drive the behaviour:

  • SIG_COUNT_VAL (0x02): maximum acquisition count per measurement. Higher values average more returns, extending usable range but slowing throughput.
  • THRESHOLD_BYPASS (0x1C): signal detection threshold. Lower values detect weaker returns (higher sensitivity, more false positives); higher values suppress weak returns (fewer false positives, less range).

Macros Documentation

define M_PI

#define M_PI 3.14159265358979323846

define APIS_FW_MIN_PATCH

#define APIS_FW_MIN_PATCH 5

define APIS_LIBRARY_VERSION

#define APIS_LIBRARY_VERSION "0.1.0"

define APIS_LIBRARY_COMMIT

#define APIS_LIBRARY_COMMIT ""

define APIS_RANGE_CAPACITY

#define APIS_RANGE_CAPACITY 64

define APIS_ACCEL_M_PER_S2_PER_DIGIT

#define APIS_ACCEL_M_PER_S2_PER_DIGIT (9.80665e-3f)

define APIS_ORIENT_CAPACITY

#define APIS_ORIENT_CAPACITY 8

define APIS_ERROR

#define APIS_ERROR NW_ERROR

Sentinel returned by all getters and printed by printDataRow() when a measurement fails due to hardware fault, I2C failure, or out-of-range reading. Applies to all measurement types: range, pitch, roll, and all derived statistics (mean, std, sterr). The same value as NW_ERROR, which every NW library uses; APIS_ERROR is the Apis spelling of it.

define APIS_NOT_MEASURED

#define APIS_NOT_MEASURED -9998

Sentinel returned by all getters and printed by printDataRow() when begin() has been called but no successful updateMeasurements() (or updateDistance()/updateOrientation()) has yet completed. Distinct from APIS_ERROR so callers can tell the difference between “the sensor failed” and “we haven’t asked yet.”

define NW_READING_ALL

#define NW_READING_ALL Apis::ALL

define NW_READING_PRIMARY

#define NW_READING_PRIMARY Apis::RANGE

define NW_READING_SECONDARY

#define NW_READING_SECONDARY Apis::ORIENT

define NW_READING_RANGE

#define NW_READING_RANGE NW_READING_PRIMARY

define NW_READING_ORIENT

#define NW_READING_ORIENT NW_READING_SECONDARY

define ADR_DEFAULT

#define ADR_DEFAULT Apis::DEFAULT_ADDRESS

Deprecated:

Use Apis::DEFAULT_ADDRESS. Every NW library defined this same macro with a different value, so a sketch including two of them got the last one. Removed at the next major version.

Source code

/******************************************************************************
Apis.h

Library for the Apis interface board for a LiDAR Lite unit.

Andrew Wickert
Based loosely on early code by Bobby Schulz, including
https://github.com/NorthernWidget/Project-Apis/tree/master/Software/LiDARLite_I2CParse

Started 2020.05.01
Hardware located at:
https://github.com/NorthernWidget/Project-Apis

License: GNU GPL v3. You should find a copy in the repository.
******************************************************************************/

#ifndef Apis_h
#define Apis_h

#include <Arduino.h>
#include <Wire.h>
#include <NW_Core.h>  // NW_Core: NW_Device (Schema 1 protocol), NW_Readings (statistics), NW_Report

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

// Minimum firmware patch (Page 0 byte 0x0A) this library accepts. Patch 1 is
// the first firmware serving the Schema 1 register map; patch 5 serves the
// zero generation with every reading, which this library reads.
#define APIS_FW_MIN_PATCH 5

// Build identity: this library's version (held equal to library.properties by
// NW-Tests/version_check.py) and its build commit, set by the NW-Build wrapper from
// git and blank in an Arduino IDE build. Both go into a logger's status file.
#define APIS_LIBRARY_VERSION "0.1.0"
#ifndef APIS_LIBRARY_COMMIT
#define APIS_LIBRARY_COMMIT ""
#endif

// Register addresses and bit masks are implementation details and live in
// Apis.cpp (NW convention: no public names for them). Sketches use the API.

// Reading arrays: each measurement keeps its readings from the last
// updateMeasurements() in a statically sized array so that median and
// two-pass statistics can be computed. Capacity is per measurement group;
// a sketch may override before including this header, e.g.
//   #define APIS_RANGE_CAPACITY 200
// No heap is ever used; a request above capacity is clamped to it.
#ifndef APIS_RANGE_CAPACITY
#define APIS_RANGE_CAPACITY 64
#endif
// Digits to m/s^2 for the accelerometer. The firmware sets CTRL_REG4 = 0x88,
// which is full scale +/-2 g with high resolution, and LIS3DH Table 4 gives
// that configuration a sensitivity of 1 mg per digit; the firmware right-
// shifts the 12-bit word into place before serving it, so a served digit is
// one milli-g. Standard gravity is 9.80665 m/s^2.
#define APIS_ACCEL_M_PER_S2_PER_DIGIT (9.80665e-3f)

#ifndef APIS_ORIENT_CAPACITY
#define APIS_ORIENT_CAPACITY 8
#endif

enum SensitivityMode : uint8_t {
  SENSITIVITY_BALANCED = 0,  
  SENSITIVITY_HIGH = 1,      
  SENSITIVITY_LOW = 2,       
  SENSITIVITY_MAX_RANGE = 3  
};

#define APIS_ERROR NW_ERROR

#define APIS_NOT_MEASURED -9998

// Deprecated component selectors. Use the class-scoped Apis::ALL, Apis::RANGE,
// Apis::ORIENT instead (see Apis::Component). Kept so existing sketches compile;
// values match the enum and will be removed in a future major version.

class Apis : public NW_Sensor {
public:
  static constexpr uint8_t DEFAULT_ADDRESS = 0x41;

  enum Component : uint8_t {
    RANGE = 0x01,   
    ORIENT = 0x02,  
    ALL = 0x03      
  };

  Apis(uint16_t nRangeReadings = 1, bool rangeStats = false,
       uint16_t nOrientReadings = 1, bool orientStats = false);

  bool begin(uint8_t address = DEFAULT_ADDRESS,
             SensitivityMode sensitivity = SENSITIVITY_BALANCED);

  uint8_t getHardwareMajor();
  uint8_t getHardwareMinor();
  uint8_t getFirmwareVersion();

  // --- Configuration setters ---
  uint16_t setDistanceReadings(uint16_t n);
  void setDistanceStats(bool enable);
  uint16_t setOrientationReadings(uint16_t n);
  void setAccelerationColumns(bool enable);
  void setMagnitudeColumns(bool enable);
  void setTiltColumns(bool enable);
  void setOrientationStats(bool enable);
  void setRangefinderSensitivity(SensitivityMode mode);

  void setI2CAddress(uint8_t newAddress);

  // --- Handshake (NW-Device-Specification Page 2 Block 0) ---
  bool ready();

  bool newReading();

  bool requestReading(uint8_t component = ALL);

  // --- Faults (status byte, live; Report register, latched) ---
  bool faulted(uint8_t chip);
  bool anyFault();
  uint8_t reportChip();
  uint8_t reportKind();
  size_t printReport(Print& out);
  size_t printStatus(Print& out, bool boot = false) override;
  // --- NW_Sensor: the logger's view (Margay::watch) ---
  const char* name() const override {
    return "Apis";
  }
  bool reportIsFault() override;
  uint8_t bootReportKind() override;
  void clearBootReport() override;
  bool updateDistance();

  bool updateOrientation();

  bool updateMeasurements(uint8_t component = ALL);

  uint16_t getDistanceCount();
  uint16_t getOrientationCount();

  // --- Single-value getters ---
  float getDistance();
  float getRoll();
  float getPitch();
  float getAccelerationX();
  float getAccelerationY();
  float getAccelerationZ();
  float getAccelerationMagnitude();
  float getTilt();
  uint8_t getSignalStrength();
  int16_t getAccelerometerTemperatureADC();
  float getAccelerometerTemperatureChange();
  int16_t getZeroTemperatureADC();
  uint16_t getZeroGeneration();
  bool zeroChanged();
  size_t dumpZeros(Print& out);

  // --- Statistics getters ---
  // Computed two-pass in 32-bit float over the readings stored by the last
  // updateMeasurements(). Adequate for N up to the array capacities
  // (tens to a few hundred); at N in the thousands the sum of squared
  // deviations would want double precision, which the AVR lacks.
  float getDistanceMean();
  float getDistanceMedian();
  float getAccelerationMagnitudeMedian();
  float getTiltMedian();
  float getPitchMedian();
  float getRollMedian();
  float getDistanceStd();
  float getDistanceSterr();
  float getAccelerationMagnitudeStd();
  float getAccelerationMagnitudeSterr();
  float getTiltStd();
  float getTiltSterr();
  float getPitchStd();
  float getPitchSterr();
  float getRollStd();
  float getRollSterr();

  size_t printDataHeader(Print& out) override;

  size_t printDataRow(Print& out) override;

  uint8_t defaultAddress() const override;

  bool wake(uint8_t address) override;

  bool acquire() override;

  size_t printNote(Print& out, bool beginFailed = false) override;

  // --- Reading interface (NW standard) ---
  size_t printHeader(Print& out);

  size_t printReading(Print& out);

  size_t logReading(Print& out);

  void beginReadings(uint8_t component = ALL, uint16_t n = 0);

  void endReadings();

  // --- Deprecated raw-reading interface (v0.1.x names) ---
  [[deprecated("Use beginReadings()")]] void beginRawReadings(uint8_t component = ALL);

  [[deprecated("Use logReading(Print&)")]] uint16_t takeRawReading(char* buf, uint16_t offset);

  [[deprecated("Use endReadings()")]] void endRawReadings();

private:

  // The Schema 1 device protocol (identity gates, handshake, batches, faults): NW_Core.
  NW_Device _dev;
  static uint8_t _chips(uint8_t component);
  // Configuration
  NW_ReadingsConfig _distanceCfg;     // readings per updateMeasurements() and stats columns, LiDAR
  NW_ReadingsConfig _orientationCfg;  // accelerometer
  bool _accelerationColumns = false;  // the g vector's components: off unless asked for
  bool _magnitudeColumns = false;
  bool _tiltColumns = false;

  // Stored measurements and statistics.
  // All initialised to APIS_NOT_MEASURED; set to APIS_ERROR on error.
  float _distance = APIS_NOT_MEASURED;
  float _pitch = APIS_NOT_MEASURED;
  float _roll = APIS_NOT_MEASURED;
  float _accelX = APIS_NOT_MEASURED;  // last reading, m/s^2
  float _accelY = APIS_NOT_MEASURED;
  float _accelZ = APIS_NOT_MEASURED;
  float _magnitude = APIS_NOT_MEASURED;  // burst mean, m/s^2
  float _tilt = APIS_NOT_MEASURED;       // burst mean, deg

  // Range statistics

  // Orientation statistics

  // Readings behind the current statistics (set by updateMeasurements):
  // one array per measurement, native type, oldest first, and the count
  // of valid entries.
  // One storage path: every acquisition appends here (updateDistance(),
  // updateOrientation(), whether from updateMeasurements() or logReading());
  // the statistics getters read the arrays; updateMeasurements() and
  // beginReadings() start a fresh set. (NW_Core)
  NW_Readings<int16_t, APIS_RANGE_CAPACITY> _distanceReadings;
  NW_Readings<float, APIS_ORIENT_CAPACITY> _pitchReadings;
  NW_Readings<float, APIS_ORIENT_CAPACITY> _rollReadings;
  NW_Readings<float, APIS_ORIENT_CAPACITY> _magnitudeReadings;
  NW_Readings<float, APIS_ORIENT_CAPACITY> _tiltReadings;

  // LiDAR Lite signal strength; updated by updateDistance()
  uint8_t _signalStrength = 0;
  // Accelerometer temperature digits (relative); updated by updateOrientation()
  int16_t _accelerometerTemp = APIS_NOT_MEASURED;
  int16_t _zeroTemp = APIS_NOT_MEASURED;
  // Zero generation carried by the last orientation reading (begin() seeds it
  // from Page 1), and whether it moved between the last two readings
  uint16_t _zeroGen = 0;
  bool _zeroChanged = false;

  // Sensor sensitivity; set initially to default "balanced" mode
  SensitivityMode _sensitivity = SENSITIVITY_BALANCED;

  // Chips covered by the current run of readings (beginReadings)
  uint8_t _rawComponent = ALL;
};

// Deprecated component selectors (v0.1.x): the class-scoped Apis::ALL,
// Apis::RANGE, Apis::ORIENT replace them. Kept so existing sketches compile.
#ifndef NW_READING_ALL
#define NW_READING_ALL Apis::ALL
#define NW_READING_PRIMARY Apis::RANGE
#define NW_READING_SECONDARY Apis::ORIENT
#endif
#define NW_READING_RANGE NW_READING_PRIMARY
#define NW_READING_ORIENT NW_READING_SECONDARY

#define ADR_DEFAULT Apis::DEFAULT_ADDRESS

#endif

Updated on 2026-10-04 at 04:51:39 +0000