Slow TF-Luna performance

Hi,

I have a TF-Luna connected to an ESP32 and coded it with Micropython based on example code. My use case is measuring car movement for a garage stop light, and I am not sure if this will work given the poor performance. It does not measure consistently, and I wonder if mine is defective. (I literally purchased it yesterday so can easily return it.) Here is more information:

Source code: https://m.l1k.cc/upload/ejL6yb ← Notice the counter used to show when a loop runs
Output: https://m.l1k.cc/upload/bkLr6d ← Notice how the loop runs for long periods where there are no measurements

Any ideas?

Please make sure that the tested distance is normal in the upper computer.

I got that configured, and it seemed to work better. Why is it so slow with Micropython on my ESP32? I also tested with Arduino and had similar issues.

Some suggestions:
1. in arduino or ESP32, check the raw data first.
2. then add the logic step by step to rule out areas of influence.
3. delay function may also affect


For your information:

TF series

# -*- coding: utf-8 -*-
import serial.tools.list_ports
import time
import numpy as np


ser = serial.Serial()
ser.port = 'COM85' #设置端口
ser.baudrate = 115200 #设置雷达的波特率

def getTFminiData():
        while True:
                count = ser.in_waiting #获取接收到的数据长度
                if count > 8:
                        recv = ser.read(9)#读取数据并将数据存入recv
                        ser.reset_input_buffer()#清除输入缓冲区
##                        print(hex(sum(recv[0:8]))[-2:])
##                        print(recv[8])
                        if recv[0] == 0x59 and recv[1] == 0x59 and recv[8] == int(hex(sum(recv[0:8]))[-2:],16): #python3 frame head and checksum check
                                distance = np.int16(recv[2] + np.int16(recv[3] << 8))
                                strength = recv[4] + recv[5] * 256
                                #print(strength)
                                #TFmini-s A01
                                if distance < 10 and distance >= 0:#测量盲区
                                        print('unreliable data: range hole: distance = %5d  strength = %5d' % (distance, strength))
                                else:
                                        if strength < 100:#信号强度过小
                                                print('low strength: distance = %5d  strength = %5d' % (distance, strength))
                                        elif strength == 65535:#信号强度过饱和
                                                print('strength saturation: distance = %5d  strength = %5d' % (distance, strength))
                                        elif strength > 65535:#环境光饱和
                                                print('unreliable data: ambient light saturation')
                                        else:#正常打印
                                                print('distance = %5d  strength = %5d' % (distance, strength))
##                                #TFmini-plus A05
##                                if distance < 10 and distance >0:#测量盲区
##                                        print('unreliable data: range hole: distance = %5d  strength = %5d' % (distance, strength))
##                                else:
##                                        if strength < 100:#信号强度过小
##                                                print('low strength: distance = %5d  strength = %5d' % (distance, strength))
##                                        elif strength == 65535:#信号强度过饱和
##                                                print('strength saturation: distance = %5d  strength = %5d' % (distance, strength))
##                                        elif strength > 65535:#环境光饱和
##                                                print('unreliable data: ambient light saturation')
##                                        else:#正常打印
##                                                print('distance = %5d  strength = %5d' % (distance, strength))
##                                #TFLuna A05
##                                if distance < 20 and distance > 0:#测量盲区
##                                        print('unreliable data: range hole: distance = %5d  strength = %5d' % (distance, strength))
##                                else:
##                                        if strength < 100:#信号强度过小
##                                                print('low strength: distance = %5d  strength = %5d' % (distance, strength))
##                                        elif strength == 65535:#信号强度过饱和
##                                                print('strength saturation: distance = %5d  strength = %5d' % (distance, strength))
##                                        elif strength > 65535:#环境光饱和
##                                                print('unreliable data: ambient light saturation')
##                                        else:#正常打印
##                                                print('distance = %5d  strength = %5d' % (distance, strength))
##
##                                #TF02-Pro A01
##                                if strength < 60:#信号强度过小
##                                        print('low strength: distance = %5d  strength = %5d' % (distance, strength))
##                                elif strength > 60 and distance >= 45 and distance <=60:
##                                        print('distance = %5d  strength = %5d' % (distance, strength))
##                                elif strength > 60 and distance > 60:
##                                        print('abnormal: distance = %5d  strength = %5d' % (distance, strength))
##                                elif strength == 65535:#信号强度过饱和
##                                        print('strength saturation: distance = %5d  strength = %5d' % (distance, strength))
##                                elif strength > 65535:#环境光饱和
##                                        print('unreliable data: ambient light saturation')
##                                else:#正常打印
##                                        print('distance = %5d  strength = %5d' % (distance, strength))
##                                #TF03 180
##                                if distance < 10:
##                                        print('unreliable data: range hole: distance = %5d  strength = %5d' % (distance, strength))
##                                else:
##                                        if strength < 40 or distance > 18000:#信号强度过小or超测量范围
##                                                print('low strength or outof range: distance = %5d  strength = %5d' % (distance, strength))
##                                        elif strength == 65535:#信号强度过饱和
##                                                print('strength saturation: distance = %5d  strength = %5d' % (distance, strength))
##                                        elif strength > 65535:#环境光饱和
##                                                print('unreliable data: ambient light saturation')
##                                        else:#正常打印
##                                                print('distance = %5d  strength = %5d' % (distance, strength))
                                ser.reset_input_buffer()


                        if recv[0] == 'Y' and recv[1] == 'Y'and int(recv[8].encode('hex'),16) == int( hex(sum(int(i.encode('hex'),16) for i in recv[0:8]))[-2:],16):  # python2 //此处标示出文件读取成功
                                lowD = int(recv[2].encode('hex'), 16)
                                highD = int(recv[3].encode('hex'), 16)
                                lowS = int(recv[4].encode('hex'), 16)
                                highS = int(recv[5].encode('hex'),16)
                                distance = np.int16(lowD + np.int16(highD << 8))
                                strength = lowS + highS * 256
                                #TFmini-s A01
                                if distance < 10 and distance >= 0:#测量盲区
                                        print('unreliable data: range hole: distance = %5d  strength = %5d' % (distance, strength))
                                else:
                                        if strength < 100:#信号强度过小
                                                print('low strength: distance = %5d  strength = %5d' % (distance, strength))
                                        elif strength == 65535:#信号强度过饱和
                                                print('strength saturation: distance = %5d  strength = %5d' % (distance, strength))
                                        elif strength > 65535:#环境光饱和
                                                print('unreliable data: ambient light saturation')
                                        else:#正常打印
                                                print('distance = %5d  strength = %5d' % (distance, strength))
##                                #TFmini-plus A05
##                                if distance < 10 and distance >0:#测量盲区
##                                        print('unreliable data: range hole: distance = %5d  strength = %5d' % (distance, strength))
##                                else:
##                                        if strength < 100:#信号强度过小
##                                                print('low strength: distance = %5d  strength = %5d' % (distance, strength))
##                                        elif strength == 65535:#信号强度过饱和
##                                                print('strength saturation: distance = %5d  strength = %5d' % (distance, strength))
##                                        elif strength > 65535:#环境光饱和
##                                                print('unreliable data: ambient light saturation')
##                                        else:#正常打印
##                                                print('distance = %5d  strength = %5d' % (distance, strength))
##                                #TFLuna A05
##                                if distance < 20 and distance > 0:#测量盲区
##                                        print('unreliable data: range hole: distance = %5d  strength = %5d' % (distance, strength))
##                                else:
##                                        if strength < 100:#信号强度过小
##                                                print('low strength: distance = %5d  strength = %5d' % (distance, strength))
##                                        elif strength == 65535:#信号强度过饱和
##                                                print('strength saturation: distance = %5d  strength = %5d' % (distance, strength))
##                                        elif strength > 65535:#环境光饱和
##                                                print('unreliable data: ambient light saturation')
##                                        else:#正常打印
##                                                print('distance = %5d  strength = %5d' % (distance, strength))
##
##                                #TF02-Pro A01
##                                if strength < 60:#信号强度过小
##                                        print('low strength: distance = %5d  strength = %5d' % (distance, strength))
##                                elif strength > 60 and distance >= 45 and distance <=60:
##                                        print('distance = %5d  strength = %5d' % (distance, strength))
##                                elif strength > 60 and distance > 60:
##                                        print('abnormal: distance = %5d  strength = %5d' % (distance, strength))
##                                elif strength == 65535:#信号强度过饱和
##                                        print('strength saturation: distance = %5d  strength = %5d' % (distance, strength))
##                                elif strength > 65535:#环境光饱和
##                                        print('unreliable data: ambient light saturation')
##                                else:#正常打印
##                                        print('distance = %5d  strength = %5d' % (distance, strength))
##                                #TF03 180
##                                if distance < 10:
##                                        print('unreliable data: range hole: distance = %5d  strength = %5d' % (distance, strength))
##                                else:
##                                        if strength < 40 or distance > 18000:#信号强度过小or超测量范围
##                                                print('low strength or outof range: distance = %5d  strength = %5d' % (distance, strength))
##                                        elif strength == 65535:#信号强度过饱和
##                                                print('strength saturation: distance = %5d  strength = %5d' % (distance, strength))
##                                        elif strength > 65535:#环境光饱和
##                                                print('unreliable data: ambient light saturation')
##                                        else:#正常打印
##                                                print('distance = %5d  strength = %5d' % (distance, strength))
                                ser.reset_input_buffer()
                else:
                        time.sleep(0.005) #50ms
if __name__ == '__main__':
        try:
                if ser.is_open == False:
                        try:
                                ser.open()
                        except:
                                print('Open COM failed!')
                getTFminiData()
        except KeyboardInterrupt:  # Ctrl+C
                if ser != None:
                        ser.close()

only tf-luna

import serial
import time
ser = serial.Serial("/dev/ttyS0", 115200)
# we define a new function that will get the data from LiDAR and publish it
def read_data():
    time.sleep(1)  # Sleep 1000ms
    while True:
        counter = ser.in_waiting # count the number of bytes of the serial port
        if counter > 8:
            bytes_serial = ser.read(9)
            ser.reset_input_buffer()
            
            if bytes_serial[0] == 0x59 and bytes_serial[1] == 0x59: # python3
                distance = bytes_serial[2] + bytes_serial[3]*256
                strength = bytes_serial[4] + bytes_serial[5]*256
                temperature = bytes_serial[6] + bytes_serial[7]*256 # For TFLuna
                temperature = (temperature/8) - 256
                print("TF-Luna python3 portion")
                print("Distance:"+ str(distance) + "cm")
                print("Strength:" + str(strength))
                if temperature != 0:
                    print("Chip Temperature:" + str(temperature)+ "℃")
                ser.reset_input_buffer()
                
            if bytes_serial[0] == "Y" and bytes_serial[1] == "Y":
                distL = int(bytes_serial[2].encode("hex"), 16)
                distH = int(bytes_serial[3].encode("hex"), 16)
                stL = int(bytes_serial[4].encode("hex"), 16)
                stH = int(bytes_serial[5].encode("hex"), 16)
                distance = distL + distH*256
                strength = stL + stH*256
                tempL = int(bytes_serial[6].encode("hex"), 16)
                tempH = int(bytes_serial[7].encode("hex"), 16)
                temperature = tempL + tempH*256
                temperature = (temperature/8) - 256
                print("TF-Luna python2 portion")
                print("Distance:"+ str(distance) + "cm\n")
                print("Strength:" + str(strength) + "\n")
                print("Chip Temperature:" + str(temperature) + "℃\n")
                ser.reset_input_buffer()
if __name__ == "__main__":
    try:
        if ser.isOpen() == False:
            ser.open()
        read_data()
    except KeyboardInterrupt:
        if ser != None:
            ser.close()
            print("program interrupted by the user")

Hi,

Before reading below, I was previously using Micropython and your sample code appears to be standard Pythong so unfortunately, I am not configured to use that.

I have explored this further and switched to Arduino to see if it made a difference. Once again, this is based on your sample code, and I have shortened it to remove temp and power in case that impacts it. (Source code below.) Sadly the problem persists. (I also gave the TF-Luna a dedicated power supply in case that was the issue.)

I also added a couple of tests to the Arduino code which revealed an interesting finding. When the TF-Luna fails to provide values, it prints “Buffer” which means that the problem is caused by this line of code:

if( buf[0] == 0x59 && buf[1] == 0x59)

Which is driven by this code:

lidarSerial.readBytes(buf, 9);

Any idea why?

Full source 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
#define garageDist 300 //Distance of car entering in cm

void setup() {
  Serial.begin(115200); // Initializing serial port
  lidarSerial.begin(115200, SERIAL_8N1, RXD2, TXD2); // Initializing serial port
}

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;
      Serial.print("Distance(cm): ");
      Serial.println(distance);
    }
    else{
      Serial.println("Buffer");
    }
  }
  else{
    Serial.println("Unavailable");
  }
  delay(10); 
}

Just to add, one more weird symptom that I see is that it starts measuring distances fairly rapidly and accurately, and then all of a sudden measurement stops. To be clear, the program is still running but that readBytes line is not delivering the expected 0x59 values and so it never gets to the Serial.print distance lines…

Do not repeat the definition of uint_8 buf[9] in the loop function.
Define it outside the function and clear the data inside the function.

typedef struct {
  int distance;
  int strength;
  int temp;
  boolean receiveComplete;
} TF;
TF Lidar = {0, 0, 0, false};

void getLidarData(TF* lidar) 
{
  static char i = 0;
  char j = 0;
  int checksum = 0;
  static int rx[9];
  if (Serial.available()) 
  {
    rx[i] = Serial.read();
    if (rx[0] != 0x59) 
    {
      i = 0;
    } 
    else if (i == 1 && rx[1] != 0x59) {
      i = 0;
    } 
    else if (i == 8) 
    {
      for (j = 0; j < 8; j++) 
      {
        checksum += rx[j];
      }
      if (rx[8] == (checksum % 256)) 
      {
          lidar->distance = rx[2] + rx[3] * 256;
          lidar->strength = rx[4] + rx[5] * 256;
          lidar->temp = (rx[6] + rx[7] * 256) / 8 - 256;
          lidar->receiveComplete = true;
      }
      i = 0;
    } 
    else 
    {
      i++;
    }
  }
}

void setup() {
  Serial.begin(115200);
}

void loop() 
{
  getLidarData(&Lidar);       //Acquisition of radar data
  if (Lidar.receiveComplete) 
  {
    Lidar.receiveComplete = false;
    Serial.print("Distance: ");
    Serial.print(Lidar.distance);
    Serial.print("cm\t");
    Serial.print("Strength: ");
    Serial.print(Lidar.strength);
    Serial.print("\t");
    Serial.print("Temp: ");
    Serial.println(Lidar.temp);
  }
}

Thank you! I will test this out later tonight and report back.

I also found a TF-LUNA I2C library for Arduino and will check that out too, in case there is something about the UART interface that is causing the performance issues.

This is the entire code and it is not running properly. What am I missing?

Fixed code in the post below

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

typedef struct {
  int distance;
  int strength;
  int temp;
  boolean receiveComplete;
} TF;
TF Lidar = {0, 0, 0, false};

void getLidarData(TF* lidar) 
{
  static char i = 0;
  char j = 0;
  int checksum = 0;
  static int rx[9];
  if (Serial.available()) 
  {
    rx[i] = Serial.read();
    if (rx[0] != 0x59) 
    {
      i = 0;
    } 
    else if (i == 1 && rx[1] != 0x59) {
      i = 0;
    } 
    else if (i == 8) 
    {
      for (j = 0; j < 8; j++) 
      {
        checksum += rx[j];
      }
      if (rx[8] == (checksum % 256)) 
      {
          lidar->distance = rx[2] + rx[3] * 256;
          lidar->strength = rx[4] + rx[5] * 256;
          lidar->temp = (rx[6] + rx[7] * 256) / 8 - 256;
          lidar->receiveComplete = true;
      }
      i = 0;
    } 
    else 
    {
      i++;
    }
  }
}

void setup() {
  Serial.begin(115200);
}

void loop() 
{
  getLidarData(&Lidar);       //Acquisition of radar data
  if (Lidar.receiveComplete) 
  {
    Lidar.receiveComplete = false;
    Serial.print("Distance: ");
    Serial.print(Lidar.distance);
    Serial.print("cm\t");
    Serial.print("Strength: ");
    Serial.print(Lidar.strength);
    Serial.print("\t");
    Serial.print("Temp: ");
    Serial.println(Lidar.temp);
  }
}

Your code had a bug, but I sorted it out. It works perfectly now. Thank you!

For future viewers, here is the final working Arduino 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
#define garageDist 300 //Distance of car entering in cm

typedef struct {
  int distance;
  int strength;
  int temp;
  boolean receiveComplete;
} TF;
TF Lidar = {0, 0, 0, false};

void getLidarData(TF* lidar) 
{
  static char i = 0;
  char j = 0;
  int checksum = 0;
  static int rx[9];
  if (lidarSerial.available()) 
  {
    rx[i] = lidarSerial.read();
    if (rx[0] != 0x59) 
    {
      i = 0;
    } 
    else if (i == 1 && rx[1] != 0x59) {
      i = 0;
    } 
    else if (i == 8) 
    {
      for (j = 0; j < 8; j++) 
      {
        checksum += rx[j];
      }
      if (rx[8] == (checksum % 256)) 
      {
          lidar->distance = rx[2] + rx[3] * 256;
          lidar->strength = rx[4] + rx[5] * 256;
          lidar->temp = (rx[6] + rx[7] * 256) / 8 - 256;
          lidar->receiveComplete = true;
      }
      i = 0;
    } 
    else 
    {
      i++;
    }
  }
}

void setup() {
  Serial.begin(115200);
  lidarSerial.begin(115200, SERIAL_8N1, RXD2, TXD2); // Initializing serial port
}

void loop() 
{
  getLidarData(&Lidar);       //Acquisition of radar data
  if (Lidar.receiveComplete) 
  {
    Lidar.receiveComplete = false;
    Serial.print("Distance: ");
    Serial.print(Lidar.distance);
    Serial.print("cm\t");
    Serial.print("Strength: ");
    Serial.print(Lidar.strength);
    Serial.print("\t");
    Serial.print("Temp: ");
    Serial.println(Lidar.temp);
  }
}
1 Like

I reviewed your code and created a version that works with Micropython. It uses “global” which is not the best code etiquette, but it works on my ESP32. Here it is for anyone who could use it:

from machine import UART, Pin
import time

uart1 = UART(1, baudrate=115200, tx=Pin(17), rx=Pin(16))      

def getLidarData(UART1):
    global i
    global temp
    if UART1.any() > 0:
        temp[i] = int.from_bytes(UART1.read(1), 'little')
        if not(temp[0] == 89): #0x59
            i = 0
        elif i == 1 and not(temp[1] == 89): #0x59
            i = 0
        elif i == 8:
            totalData = 0
            for z in range(8):
                totalData += temp[z]
            if temp[8] == (totalData % 256):
                distance   = temp[2] + temp[3] * 256            #DistanceValue
                strength    = temp[4] + temp[5] * 256            #signal strength
                temperature= (temp[6] + temp[7]* 256)/8-256     #Chip temperature
                print("distance = " + str(distance) + "cm,strengh = " + str(strength) + ",temperature = " + str(temperature))
            i = 0
        else:
            i += 1

temp = [0,0,0,0,0,0,0,0,0]
i = 0
time.sleep(1)  
while True:
    getLidarData(uart1)
    time.sleep(0.01)