Setting Up the TFmini-S with ESP32: Customizing Signal Strength and Frame Rate

Protonest IoT
7 min readSep 29, 2024

--

In this article, we’ll share our experience connecting the TFmini-S LiDAR sensor with an ESP32, adjusting its signal strength and frame rate to suit your application.

First, let’s look into some types of distance sensors and applications of each type.

Types of Distance Sensors

Ultrasonic Sensors

  • How They Work: They send out sound waves and measure how long it takes for the echo to return.
  • Best For: Measuring water levels, obstacle detection in robots, and simple distance measurements.

LiDAR Sensors (e.g. TFmini-S)

  • How They Work: They emit laser beams and calculate distance based on how long the light takes to bounce back.
  • It is a type of TOF sensor.(In TOF sensors either sound or laser is used)
  • Best For Precise distance measurements in open areas, drone navigation, and mapping.

Radar Sensors

  • How They Work: They use radio waves to detect objects and measure distances.
  • Best For: Automotive safety systems, industrial automation, and weather monitoring.

In this article, we are guiding you through the implementation of TFmini-S sensor with ESP32.

Components Used

Connecting the TFmini-S to the ESP32

Follow the following circuit diagram,

Note: We used UART (serial communication) in this implementation.

Programming the ESP32

Understanding the Settings

Signal Strength Threshold

  • What is signal strength threshold: The minimum signal strength the sensor needs to consider a reading reliable.
  • The default value is set to 100. If the signal strength drops below this, the sensor marks the reading as unreliable.
  • Why Adjust It: Lowering the threshold allows the sensor to accept weaker signals, which might help in detecting surfaces like water that don’t reflect light well.

Frame Rate

  • What is frame rate: How many measurements the sensor take per second.
  • Default Value: 100 Hz.
  • Why Adjust It: Lowering the frame rate can reduce noise and provide more stable readings in environments with fluctuating surfaces, though it means fewer data points per second.

Referencing the TFmini-S Datasheet

Setting Signal Strength Threshold

Command Format:

5A 07 22 XX LL HH 00 SU
5A: Frame header.
07: Length of the frame (8 bytes).
22: Command ID for setting the strength threshold.
XX: New strength threshold value divided by 10.
LL HH: Distance value to output when below the threshold (commonly 65535).
00: Reserved byte.
SU: Checksum (sum of bytes from 5A to 00, lower 8 bits).

On page 18 of the datasheet, you can find,

If you need to make the threshold as 50,

XX = 50/10 = 5(DEC) = 0x05(HEX)

Distance value to output when below the threshold,

We took it as 65535 cm.

65535(DEC) = FFFF(HEX)

LL —0xFF

HH — 0xFF

The code line for that is as follows,

command[4] = distance & 0xFF; // LL = 0xFF
How it came?

1111 1111 1111 1111 (distance = 0x65535)
&
0000 0000 1111 1111 (0x00FF)
---------------------
0000 0000 1111 1111 (0x00FF)

And for HH is,

command[5] = (distance >> 8) & 0xFF; // HH = 0xFF

First, we need to shift the distance by 8 bits to the right,

0000 0000 1111 1111  (After shift = 0x00FF)
&
0000 0000 1111 1111 (0x00FF)
---------------------
0000 0000 1111 1111 (0x00FF)

Hope you learn how we made the code for getting HH and LL.

Calculating checksum: (sum of bytes from 5A to 00, lower 8 bits)

It was calculated using,

  // Calculate checksum
uint8_t checksum = 0;
for (int i = 0; i < 7; i++) {
checksum += command[i];
}
command[7] = checksum & 0xFF; // SU (Checksum) Only lower 8 bits are considered

Code Snippet for setting the threshold is,


// Function to set the strength threshold
void setStrengthThreshold(uint8_t threshold, uint16_t distance) {
uint8_t command[8];
command[0] = 0x5A; // Frame header
command[1] = 0x07; // Length of the frame
command[2] = 0x22; // Command ID for strength threshold

// XX: Threshold value divided by 10
command[3] = threshold / 10; // Ensure threshold is divisible by 10

// LL and HH: Distance value when below threshold (little-endian)
command[4] = distance & 0xFF; // LL (Low Byte)
command[5] = (distance >> 8) & 0xFF; // HH (High Byte)

// Calculate checksum
uint8_t checksum = 0;
for (int i = 0; i < 7; i++) {
checksum += command[i];
}
command[6] = checksum & 0xFF; // SU (Checksum)

// Send command to TFmini-S
lidarSerial.write(command, 8);

// Debug output
Serial.print("Strength threshold set to ");
Serial.print(threshold);
Serial.print(", Distance when below threshold: ");
Serial.println(distance);
}

Setting Frame Rate

Datasheet info,

Command Format:

5A 06 03 LL HH SU
5A: Frame header.
06: Length of the frame (6 bytes).
03: Command ID for setting frame rate.
LL HH: Desired frame rate (e.g., 0x64 0x00 for 100 Hz).
SU: Checksum.

Its the same as before for calculating LL and HH.

For 100 Hz,
100(DEC) = 0x0064 (HEX)

So,

HH: 0x00
LL: 0x64

Code snippet,

void setTFminiSFrameRate(uint16_t frameRate) {
// TFmini-S frame rate command requires 6 bytes
uint8_t command[6];
command[0] = 0x5A; // Frame header
command[1] = 0x06; // Length of the frame (6 bytes)
command[2] = 0x03; // Command ID for frame rate

// Split frameRate into Low Byte (LL) and High Byte (HH) in little-endian format
command[3] = frameRate & 0xFF; // LL (Low Byte)
command[4] = (frameRate >> 8) & 0xFF; // HH (High Byte)

// Calculate checksum: sum of bytes from command[0] to command[4]
uint8_t checksum = 0;
for (int i = 0; i < 5; i++) {
checksum += command[i];
}
command[5] = checksum & 0xFF; // SU (Checksum)

// Send the 6-byte command to the TFmini-S
lidarSerial.write(command, 6);

// Debug output
Serial.print("Frame rate set to ");
Serial.print(frameRate);
Serial.println(" Hz");
}

The checksum is calculated as before.

Now, let’s look into the complete code.

#include <HardwareSerial.h> // Reference the ESP32 built-in serial port library
HardwareSerial lidarSerial(2); // Using serial port 2
#define RXD2 16
#define TXD2 17

void setup() {
Serial.begin(115200); // Initializing serial port
lidarSerial.begin(115200, SERIAL_8N1, RXD2, TXD2); // Initializing serial port
// Set TFminiS frame rate to desired value, e.g., 100 Hz
//setTFminiSFrameRate(1); // Set frame rate to 100 Hz
//setStrengthThreshold(50, 65535);
}

// Function to calculate checksum
uint8_t calculateChecksum(uint8_t *data, int length) {
uint16_t sum = 0;
for (int i = 0; i < length - 1; i++) { // Exclude checksum byte
sum += data[i];
}
return sum & 0xFF; // Return lower 8 bits
}

// Function to set frame rate
void setTFminiSFrameRate(uint16_t frameRate) {
// TFmini-S frame rate command requires 6 bytes
uint8_t command[6];
command[0] = 0x5A; // Frame header
command[1] = 0x06; // Length of the frame (6 bytes)
command[2] = 0x03; // Command ID for frame rate

// Split frameRate into Low Byte (LL) and High Byte (HH) in little-endian format
command[3] = frameRate & 0xFF; // LL (Low Byte)
command[4] = (frameRate >> 8) & 0xFF; // HH (High Byte)

// Calculate checksum: sum of bytes from command[0] to command[4]
uint8_t checksum = 0;
for (int i = 0; i < 5; i++) {
checksum += command[i];
}
command[5] = checksum & 0xFF; // SU (Checksum)

// Send the 6-byte command to the TFmini-S
lidarSerial.write(command, 6);

// Debug output
Serial.print("Frame rate set to ");
Serial.print(frameRate);
Serial.println(" Hz");
}


// Function to set the strength threshold
void setStrengthThreshold(uint8_t threshold, uint16_t distance) {
uint8_t command[8];
command[0] = 0x5A; // Frame header
command[1] = 0x07; // Length of the frame
command[2] = 0x22; // Command ID for strength threshold

// XX: Threshold value divided by 10
command[3] = threshold / 10; // Ensure threshold is divisible by 10

// LL and HH: Distance value when below threshold (little-endian)
command[4] = distance & 0xFF; // LL (Low Byte)
command[5] = (distance >> 8) & 0xFF; // HH (High Byte)


// Calculate checksum
uint8_t checksum = 0;
for (int i = 0; i < 7; i++) {
checksum += command[i];
}
command[6] = checksum & 0xFF; // SU (Checksum)

// Send command to TFmini-S
lidarSerial.write(command, 8);

// Debug output
Serial.print("Strength threshold set to ");
Serial.print(threshold);
Serial.print(", Distance when below threshold: ");
Serial.println(distance);
}

void loop() {
uint8_t buf[9] = {0}; // An array that holds data
if (lidarSerial.available() > 0) {
lidarSerial.readBytes(buf, 9); // Read 9 bytes of data
if( buf[0] == 0x59 && buf[1] == 0x59)
{
uint16_t distance = buf[2] + buf[3] * 256;
uint16_t strength = buf[4] + buf[5] * 256;
int16_t temperature = buf[6] + buf[7] * 256;
Serial.print("Distance: ");
Serial.print(distance);
Serial.print(" cm, strength: ");
Serial.print(strength);
Serial.print(", temperature: ");
Serial.println(temperature / 8.0 - 256.0);
}
}
delay(10);
}

First, you need to uncomment,

//setTFminiSFrameRate(1); 
//setStrengthThreshold(50, 65535);

And set the frame rate and threshold.

Upload the code, after that, you will see the settings are saved.

Comment it again and upload the code again, then you will see the following data from the sensor on the serial monitor,

Hope you enjoyed the article. Please comment below or send us an email to info@protonest.co, if you face any issues when implementing.

Contact us for any consultations or projects related to IoT and embedded systems.

Email: info@protonest.co

Protonest for more details.

Protonest specializes in transforming IoT ideas into reality. We offer prototyping services from concept to completion. Our commitment ensures that your visionary IoT concepts become tangible, innovative, and advanced prototypes.

Our Website: https://www.protonest.co/

Cheers!

--

--

Protonest IoT
Protonest IoT

Written by Protonest IoT

We make your IoT ideas a reality

No responses yet