Arduino Tilt & Laser Distance Finder

A middle school teacher reached out looking for a firmware developer to create a tilt and laser range finder for classroom use to encourage STEM education. This looked like a fun project and appeared straight forward. The teacher had already selected, purchased, and assembled the hardware into a demonstration system for his classroom.

The hardware included:

  • Nano 33 BLE
  • Nextion NX4024T032 basic touch display (400×240, 3.2″ display)
  • Laser range module
  • MB102 power supply
  • 12V AA battery pack (AA cell used for on/off switch)
Laser Distance Finder and Tilt Measuring Device

The Nano 33 BLE has an Inertial Measurement Unit (IMU) to support tilt measurement and the laser range module provided distance information via a serial interface.

The laser module interface documentation was minimal and some test code was created to understand the control and response formats. Second I had planned on using ITEADLIB library to interface to the Nextion display, but the library doesn’t support Nano 33 BLE. So I had to generate code to interface to the Nextion display.

The client provided graphic for the tilt gauge and battery status and conceptual functions and screens. The final system had three screens:

  • Control and measurement used to start/stop measurements, display current measurement data (distance and tilt), and show battery status. It also had buttons to see a previous measurement list and go to the settings page.
  • Measurement list that shows the last 10 measurements in current units.
  • Settings page was used to change tilt and distance calibration offsets, change screen brightness, and toggle units between feet-inches, inches, and millimeters.

On the control and measurement screen there were three primary firmware calculations that were needed, distance measurement, tilt angle, and battery voltage percentage. The only control function was to turn the distance/tilt measurement on and off that used a multi-state Nextion button object.

Distance Calculation

The laser distance module is a self contained system where control and data used an asynchronous start/stop protocol at 115200 baud, 8-N-1. The laser module had both single and multiple (continuous) measurement modes. I used the multiple measurement mode where the module once enabled, continued to send measurements so the system could be pointed and adjusted as needed before stopping the measurement and storing the results.

While in this measurement mode, the distance was updated whenever a new measurement was received through the serial interface. The message was decoded and converted to the display string using the user selected units (ft-inches, inches, or mm). All data was stored in the firmware in inches and converted when needed.

Tilt Calculation

Tilt was updated whenever the Inertial Measurement Unit (IMU) had a new measurement. The interface to the LSM9DS1 IMU used an Arduino library. The IMU x-axis is inline with the laser module. I used all three axis in the calculation and applied the classical method of rectangular to spherical conversion to find the tilt. The key assumption was the only acceleration is due to gravity.

g_tilt = (180.0*acos(x/sqrt(x*x+y*y+z*z))/M_PI) - 90;  // +/- 90 degrees

Battery Percentage Calculation

A low current voltage divider was used to estimate the remaining battery level. Based on the voltage a percentage was calculated. On the Nextion display a progress bar was used to show the amount of remaining battery and the color was changed based on the level between green (50% or greater), yellow, and red (15% or less). The battery level was updated based on a programmable timer value.

Nextion Display

The Nextion Display was developed using the Nextion’s HMI software. Buttons used images to reflect on, off, settings, save, and back. The Nextion display interface is serial and the protocol is defined in the user documentation. Below is a sequence that sets the length of the progress bar, sets the color, and writes the text value of the battery percentage.

  nextionSerial.print("j0.val=");              // progress bar
  nextionSerial.print(String(100-intPerCent));
  nextionSerial.print("\xFF\xFF\xFF");

  if(percentage < 15) {
    nextionSerial.print("j0.bco=63488");       // progress bar red
    nextionSerial.print("\xFF\xFF\xFF");    
  }
  else if (percentage >= 50) {
    nextionSerial.print("j0.bco=1024");       // progress bar green
    nextionSerial.print("\xFF\xFF\xFF");        
  }
  else {
    nextionSerial.print("j0.bco=65504");       // progress bar yellow
    nextionSerial.print("\xFF\xFF\xFF");    
  }
  
  nextionSerial.print("t3.txt=");       // text value
  nextionSerial.print("\"" + String(intPerCent) + "%" + "\"");
  nextionSerial.print("\xFF\xFF\xFF");

Saving Operating Parameters

The Nano 33 BLE does not have EEPROM. The only non-volatile memory is flash. For this project the user wanted to store the units and offsets between power cycles. I looked at several libraries and found one designed to store parameters in flash by Dirk Frehiling on Github. The library works with a data structure defined by the programmer (typedef struct) and uses writePrefs and readPrefs object methods.

// cal flash data structure
typedef struct flashStruct {
  float calDistance;        // inches (always)
  float calTilt;            // degrees
  enum outputType outUnits; // units
} calibrationData;

The project has some other nice features like going into a power down mode after inactivity and displayed fractions of an inch as a fraction for measurements in FT-IN, and INCHES. One future improvement is to increase the accuracy of the tilt measurement using more advance calibration techniques.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s