-1

I am trying to get my lidar tf02 pro to get distance values on Arduino nano but I am unable to get that due to a lack of libraries for tf02 pro on the internet. The only available libraries are for tf mini and tf luna. Can you get me fixed out this code according to tf02 pro? This code is written for tf mini lidar:

#include <SoftwareSerial.h>   //header file of software serial port
SoftwareSerial Serial1(2, 3); //define software serial port name as Serial1 and define pin2 as RX & pin3 as TX
 
int dist;                     //actual distance measurements of LiDAR
int strength;                 //signal strength of LiDAR
int check;                    //save check value
int i;
int uart[9];                   //save data measured by LiDAR
const int HEADER = 0x59;      //frame header of data package
 
 
void setup()
{
  Serial.begin(115200);         //set bit rate of serial port connecting Arduino with computer
  Serial1.begin(115200);      //set bit rate of serial port connecting LiDAR with Arduino
}
 
 
void loop() {
  if (Serial1.available())                //check if serial port has data input
  {
    if (Serial1.read() == HEADER)        //assess data package frame header 0x59
    {
      uart[0] = HEADER;
      if (Serial1.read() == HEADER)      //assess data package frame header 0x59
      {
        uart[1] = HEADER;
        for (i = 2; i < 9; i++)         //save data in array
        {
          uart[i] = Serial1.read();
        }
        check = uart[0] + uart[1] + uart[2] + uart[3] + uart[4] + uart[5] + uart[6] + uart[7];
        if (uart[8] == (check & 0xff))        //verify the received data as per protocol
        {
          dist = uart[2] + uart[3] * 256;     //calculate distance value
          strength = uart[4] + uart[5] * 256; //calculate signal strength value
          Serial.print("dist = ");
          Serial.print(dist);                 //output measure distance value of LiDAR
          Serial.print('\t');
          Serial.print("strength = ");
          Serial.print(strength);             //output signal strength value
          Serial.print('\n');
          delay(300);
        }
      }
    }
  }
}

Click here to view my lidar specs

  • 1
    What makes you think you need a library? The TFMini code you have presented does not use a TFMini specific library (although it is also not great code). Looking at the manuals for the two devices, they use the same protocol, so if this code works with TFMini it would work with TF02 (so long as you have not configured it to work in I2C mode or string mode). But as I said it is not a good design. I'd offer a better solution, but it will have to wait. – Clifford Apr 07 '23 at 07:41

1 Answers1

1

First of all you are expecting too much of SoftwareSerial running it at 115200. Whilst the documentation states:

speeds up to 115200 bps.

you have to understand the consequences of being a software UART. If the CPU is busy being a UART, that is time not doing other work. Personally I doubt that 115200 could be be achieved on a Nano, and certainly not whist getting anything much else done.

I suggest either:

  • using a PC to send the necessary command to set the baud rate to something reasonable like 9600 (start low and increase until it becomes unreliable, then back-off, though given you present a report at 300ms intervals in the code, faster data rate offers no real benefit), or
  • using the hardware Serial port for the LiDAR, and SoftwareSerial for the data output. There is no real need to run the text output at 115200 for the amount of text output at the rate of output you have.

Second SoftwareSerial::read() returns -1 if no data was available, and the TFMini code does not check for that, so it is likely to produce erroneous results - it does not wait on a timeout. If it works at all, it will be because sufficient data happens to be buffered during the 300 millisecond delay, which is itself ill-advised.

Now given an appropriate serial port and/or baud rate, the TFMini uses the same message protocol as the TF02, so the code should "kind of" work if it already works for TFMini. Having said that it is not a great design, and inserting a delay() in a Sketch loop() is always best avoided. It is the software equivalent to spinning your wheels - a lot of power and no progress - the CPU could be doing useful stuff in that time. It is also probably prone to getting out of sync and missing or misinterpreting messages.

The Sketch loop() architecture is most suited ot non-blocking statemachines. So given a serial port with a feasible chance of working and given it a sensible name, (e.g. TF01Port rather than the meaningless Serial1), then, you might implement a TFx acquisition function as a non-blocking (i.e. no delays or waiting) state-machine thus:

#include <stdint.h>
    
bool TFxAcquire( uint16_t& distance, 
                 uint16_t& strength, 
                 uint16_t& temperature )
{
    static const HDR = 0x59 ;
    static uint16_t d = 0u ;
    static uint16_t s = 0u ;
    static uint16_t t = 0u ;
    static uint8_t checksum = 0 ;    
    enum
    {
        WAIT_HDR1,
        WAIT_HDR2,
        WAIT_DIST_L,
        WAIT_DIST_H,
        WAIT_STREN_L,
        WAIT_STREN_H,
        WAIT_TEMP_L,
        WAIT_TEMP_H,
        WAIT_CHKSM
    } state = WAIT_HDR
        
    bool new_value = false ;
   
    int ch = TF01Port.read() ;
    if( ch > 0 )
    {   
        uint8_t rx = (uint8_t)ch ;
        checksum += rx ;

        switch( state )
        {
            case WAIT_HDR1 :
            {
                checksum = rx ;
                if( rx == HDR ) state++ ;
            }
            break ;

            case WAIT_HDR2 :
            {
                state = rx == HDR ? state + 1 : WAIT_HDR1 ;
            }
            break ;

            case WAIT_DIST_L :
            {
                d = rx ;
                state++ ;
            }
            break ;

            case WAIT_DIST_H :
            {
                d |= rx << 8 ;
                state++ ;
            }
            break ;

            case WAIT_STREN_L :
            {
                s = rx ;
                state++ ;
            }
            break ;

            case WAIT_STREN_H :
            {
                s |= rx << 8 ;
                state++ ;
            }
            break ;

            case WAIT_TEMP_L :
            {
                t = rx ;
                state++ ;            
            }
            break ;

            case WAIT_TEMP_H :
            {
                t |= rx << 8 ;
                state++ ;
            }
            break ;

            case WAIT_CHKSM :
            {
                if( rx = checksum )
                {
                    distance = d ;
                    strength = s ;
                    temperature = t ;
                    new_value = true ;
                }

                state = WAIT_HDR1 ;
            }
            break ;       
        }
    }
    
    return new_value ;
}

If you use the default Serial object for the LiDAR, I suggest you create an alias e.g.:

#define TF01Port Serial

but for a SoftwareSerial instance, simply give it a useful name in the first instance:

SoftwareSerial TF01Port(2, 3);

Then in loop() you would call that repeatedly. When the function returns true, the data has been updated.

In the following example, loop() is also non-blocking, so the processor is available to do other work in real-time. By making the data static, the data once valid remains valid (TFxAcquire() does not modify the data unless it has an update). When the data is updated, it is timestamped so that the data report only shows new data or none at all.

void loop() 
{
    static const unsigned long UPDATE_MILLIS = 300u ;
    
    static unsigned long last_report_time = millis() ;
    static unsigned long acquisition_time = millis() ;
    static uint16_t distance, strength, temperature ;
    
    unsigned long now = millis() ;
    
    // If new data aquired...
    if( TFxAquire( distance, strength, temperature ) )
    {
        // ... timestamp it
        acquisition_time = now ;
    }
    
    // Determine age of current data
    unsigned long data_age = now - acquisition_time ;
    
    // If it is time to report, and data has been updated
    // since last report...
    if( now - last_report_time >= UPDATE_MILLIS && 
        data_age <= UPDATE_MILLIS )
    {
        // ... timestamp the report 
        last_report_time = now ;
        
        // ... print data here       
    }
    
    // Do other real-time stuff here
}

Note that I have not compiled, tested or debugged this code - it is informed by the TF02 documentation. Treat as illustrative of a design rather then necessarily working code.

Clifford
  • 88,407
  • 13
  • 85
  • 165