Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TFMini not compatible with ESP8266 / NodeMCU 12E #6

Open
micblack opened this issue Aug 3, 2018 · 10 comments
Open

TFMini not compatible with ESP8266 / NodeMCU 12E #6

micblack opened this issue Aug 3, 2018 · 10 comments

Comments

@micblack
Copy link

micblack commented Aug 3, 2018

Note: If you are trying to run BasicReading.ino on a ESP8266 / NodeMCU 12E, then you will need to make sure you are using ESPSoftwareSerial library and not standard SoftwareSerial otherwise tfmini.getDistance(); will cause a crash and soft restart in an infinite loop.

On running the BasicReading.ino example, changing pins for mySerial to D7 as RX and D8 as TX, and enabling TFMINI_DEBUGMODE the call to tfmini.getDistance() causes this error:

ERROR: no header

Sometimes it also returns a reading but this is just a bogus number.

From the last few hours trying different approaches, I don't think TFMini is compatible with ESP8266/ NodeMCU 12E due to the high baud rate expected from ESPSoftwareSerial.

It would have been great- a cheap WiFi connected LiDAR so I'm hoping I can be proven wrong.

@jucall
Copy link

jucall commented Aug 9, 2018

You are wright. I tried to use TFMini with Wemos Mini Pro D (with ESP8266 Core Processor), At the begining worked OK, but suddenly appears that message.

TF Mini error: too many measurement attempts
Last error:
ERROR_SERIAL_NOHEADER
65535 cm sigstr: 65535

Do you know what can I do?, Do you have a code to reset o do something to fix it?. It's hard to believe that software issue could damage forever the sensor.

This problem doesn't happend with Arduinos?.

Can you share please a zip file with your example project and corrected serial communications libraries to use TFMini with ESP boards (like Wemos)?. The other solutions is have to use an Arduino Pro Mini working at 3.3 Volts to communicate with TFMini.

Greetings.
JC

@pedrooct
Copy link

HI @jucall , can you provide your code please , i'm also trying to use this lidar but to no success . Thank you.

@speedymk1
Copy link

Is there a solution to use TFMini with NodeMCU 12E ?

@pedrooct
Copy link

pedrooct commented Jan 3, 2020

@speedymk1 Hello,I don't have the code but from what i remember you need to delete all the serial.print and serial println from tfmini.cpp.

That should do the trick. If it did please confirm this. Thank you.

@speedymk1
Copy link

@pedrooct
Hi, I tried it now and I will tell you that everything work for me.
Below you will see how I have it done...

Step 1 -> modify the TFMini.cpp:
delete or comment all Serial.print commands in the TFMini.cpp file.
myone look now like following:

/*
Arduino driver for Benewake TFMini time-of-flight distance sensor.
by Peter Jansen (December 11/2017)
This code is open source software in the public domain.

THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The names of the contributors may not be used to endorse or promote products
derived from this software without specific prior written permission.
*/

#include "TFMini.h"

// Constructor
TFMini::TFMini() {
  // Empty constructor
}


boolean TFMini::begin(Stream* _streamPtr) {
  // Store reference to stream/serial object
  streamPtr = _streamPtr;

  // Clear state
  distance = -1;
  strength = -1;
  state = READY;

  // Set standard output mode
  setStandardOutputMode();

  return true;
}


// Public: The main function to measure distance.
uint16_t TFMini::getDistance() {
  int numMeasurementAttempts = 0;
  while (takeMeasurement() != 0) {
    numMeasurementAttempts += 1;
    if (numMeasurementAttempts > TFMINI_MAX_MEASUREMENT_ATTEMPTS) {
//      Serial.println ("TF Mini error: too many measurement attempts");
//      Serial.println ("Last error:");
      if (state == ERROR_SERIAL_NOHEADER)     //Serial.println("ERROR_SERIAL_NOHEADER");
      if (state == ERROR_SERIAL_BADCHECKSUM)  //Serial.println("ERROR_SERIAL_BADCHECKSUM");
      if (state == ERROR_SERIAL_TOOMANYTRIES) //Serial.println("ERROR_SERIAL_TOOMANYTRIES");

      state = ERROR_SERIAL_TOOMANYTRIES;
      distance = -1;
      strength = -1;
      return -1;
    }
  }

  if (state == MEASUREMENT_OK) {
    return distance;
  } else {
    return -1;
  }
}


// Public: Return the most recent signal strength measuremenet from the TF Mini
uint16_t TFMini::getRecentSignalStrength() {
  return strength;
}


// Private: Set the TF Mini into the correct measurement mode
void TFMini::setStandardOutputMode() {
  // Set to "standard" output mode (this is found in the debug documents)
  streamPtr->write((uint8_t)0x42);
  streamPtr->write((uint8_t)0x57);
  streamPtr->write((uint8_t)0x02);
  streamPtr->write((uint8_t)0x00);
  streamPtr->write((uint8_t)0x00);
  streamPtr->write((uint8_t)0x00);
  streamPtr->write((uint8_t)0x01);
  streamPtr->write((uint8_t)0x06);

  delay(100);
}


// Private: Handles the low-level bits of communicating with the TFMini, and detecting some communication errors.
int TFMini::takeMeasurement() {
  int numCharsRead = 0;
  uint8_t lastChar = 0x00;

  // Step 1: Read the serial stream until we see the beginning of the TF Mini header, or we timeout reading too many characters.
  while (1) {

    if (streamPtr->available()) {
      uint8_t curChar = streamPtr->read();

      if ((lastChar == 0x59) && (curChar == 0x59)) {
        // Break to begin frame
        break;

      } else {
        // We have not seen two 0x59's in a row -- store the current character and continue reading.
        lastChar = curChar;
        numCharsRead += 1;
      }
    }

    // Error detection:  If we read more than X characters without finding a frame header, then it's likely there is an issue with
    // the Serial connection, and we should timeout and throw an error.
    if (numCharsRead > TFMINI_MAXBYTESBEFOREHEADER) {
      state = ERROR_SERIAL_NOHEADER;
      distance = -1;
      strength = -1;
      if (TFMINI_DEBUGMODE == 1)// Serial.println("ERROR: no header");
      return -1;
    }

  }

  // Step 2: Read one frame from the TFMini
  uint8_t frame[TFMINI_FRAME_SIZE];

  uint8_t checksum = 0x59 + 0x59;
  for (int i=0; i<TFMINI_FRAME_SIZE; i++) {
    // Read one character
    while (!streamPtr->available()) {
      // wait for a character to become available
    }
    frame[i] = streamPtr->read();

    // Store running checksum
    if (i < TFMINI_FRAME_SIZE-2) {
      checksum += frame[i];
    }
  }

  // Step 2A: Compare checksum
  // Last byte in the frame is an 8-bit checksum
  uint8_t checksumByte = frame[TFMINI_FRAME_SIZE-1];
  if (checksum != checksumByte) {
    state = ERROR_SERIAL_BADCHECKSUM;
    distance = -1;
    strength = -1;
    if (TFMINI_DEBUGMODE == 1)// Serial.println("ERROR: bad checksum");
    return -1;
  }


  // Step 3: Interpret frame
  uint16_t dist = (frame[1] << 8) + frame[0];
  uint16_t st = (frame[3] << 8) + frame[2];
  uint8_t reserved = frame[4];
  uint8_t originalSignalQuality = frame[5];


  // Step 4: Store values
  distance = dist;
  strength = st;
  state = MEASUREMENT_OK;

  // Return success
  return 0;
}

Step 2 -> my testing code:

/* This example shows how to use the TFMini module.
The nodeMCU have an build in Watchdog and therefore it is necessary,
that you delete/disable all <<Serial.print>> commands from the TFMini.cpp.
Otherwise you will run into an restart loop, because the Watchdog become
activated...

Wiring:
TFMini  -> nodeMCU
SDA     -> D2 -> 4 -> Tx
SCL     -> D1 -> 5 -> Rx
VCC     -> 5V
GND     -> GND
*/
#include <Arduino.h>
#include <SoftwareSerial.h>
#include "TFMini.h"

// Setup software serial port
SoftwareSerial mySerial(5, 4);      // connection to TFMini
TFMini         tfmini;              // tfmini access
unsigned long  previousMillis = 0;  // access time
const long interval = 10;           // interval at which to measure (milliseconds)

/*
-----------------S E T U P-----------------
*/
void setup() {
  // Step 1: Initialize hardware serial port (serial debug port)
  Serial.begin(115200);
  // wait for serial port to connect. Needed for native USB port only
  while (!Serial);

  // Step 2: Initialize the data rate for the SoftwareSerial port
  mySerial.begin(TFMINI_BAUDRATE);  // default boudrate is 115200
  delay(10);

  // Step 3: Initialize the TF Mini sensor
  tfmini.begin(&mySerial);
  Serial.println ("Initializing Serial and mySerial finished");
}


/*
-----------------L O O P-----------------
*/
void loop() {
  // we will not use an delay...
  // but we wait some short time before taking the next measurement
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    // save the last measure time
    previousMillis = currentMillis;
    // Take one TF Mini distance measurement
    uint16_t dist = tfmini.getDistance();
    uint16_t strength = tfmini.getRecentSignalStrength();
    // Display the measurement
    Serial.print(dist);
    Serial.print(" cm   Signal: ");
    Serial.println(strength);
  }
}

@pedrooct
Copy link

pedrooct commented Jan 4, 2020

@speedymk1 so it work right ?

@speedymk1
Copy link

Yes, it work how it should.
Perfect, thanks again 👌😊

@sachinELEVEN
Copy link

@pedrooct
Hi, I tried it now and I will tell you that everything work for me.
Below you will see how I have it done...

Step 1 -> modify the TFMini.cpp:
delete or comment all Serial.print commands in the TFMini.cpp file.
myone look now like following:

/*
Arduino driver for Benewake TFMini time-of-flight distance sensor.
by Peter Jansen (December 11/2017)
This code is open source software in the public domain.

THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The names of the contributors may not be used to endorse or promote products
derived from this software without specific prior written permission.
*/

#include "TFMini.h"

// Constructor
TFMini::TFMini() {
  // Empty constructor
}


boolean TFMini::begin(Stream* _streamPtr) {
  // Store reference to stream/serial object
  streamPtr = _streamPtr;

  // Clear state
  distance = -1;
  strength = -1;
  state = READY;

  // Set standard output mode
  setStandardOutputMode();

  return true;
}


// Public: The main function to measure distance.
uint16_t TFMini::getDistance() {
  int numMeasurementAttempts = 0;
  while (takeMeasurement() != 0) {
    numMeasurementAttempts += 1;
    if (numMeasurementAttempts > TFMINI_MAX_MEASUREMENT_ATTEMPTS) {
//      Serial.println ("TF Mini error: too many measurement attempts");
//      Serial.println ("Last error:");
      if (state == ERROR_SERIAL_NOHEADER)     //Serial.println("ERROR_SERIAL_NOHEADER");
      if (state == ERROR_SERIAL_BADCHECKSUM)  //Serial.println("ERROR_SERIAL_BADCHECKSUM");
      if (state == ERROR_SERIAL_TOOMANYTRIES) //Serial.println("ERROR_SERIAL_TOOMANYTRIES");

      state = ERROR_SERIAL_TOOMANYTRIES;
      distance = -1;
      strength = -1;
      return -1;
    }
  }

  if (state == MEASUREMENT_OK) {
    return distance;
  } else {
    return -1;
  }
}


// Public: Return the most recent signal strength measuremenet from the TF Mini
uint16_t TFMini::getRecentSignalStrength() {
  return strength;
}


// Private: Set the TF Mini into the correct measurement mode
void TFMini::setStandardOutputMode() {
  // Set to "standard" output mode (this is found in the debug documents)
  streamPtr->write((uint8_t)0x42);
  streamPtr->write((uint8_t)0x57);
  streamPtr->write((uint8_t)0x02);
  streamPtr->write((uint8_t)0x00);
  streamPtr->write((uint8_t)0x00);
  streamPtr->write((uint8_t)0x00);
  streamPtr->write((uint8_t)0x01);
  streamPtr->write((uint8_t)0x06);

  delay(100);
}


// Private: Handles the low-level bits of communicating with the TFMini, and detecting some communication errors.
int TFMini::takeMeasurement() {
  int numCharsRead = 0;
  uint8_t lastChar = 0x00;

  // Step 1: Read the serial stream until we see the beginning of the TF Mini header, or we timeout reading too many characters.
  while (1) {

    if (streamPtr->available()) {
      uint8_t curChar = streamPtr->read();

      if ((lastChar == 0x59) && (curChar == 0x59)) {
        // Break to begin frame
        break;

      } else {
        // We have not seen two 0x59's in a row -- store the current character and continue reading.
        lastChar = curChar;
        numCharsRead += 1;
      }
    }

    // Error detection:  If we read more than X characters without finding a frame header, then it's likely there is an issue with
    // the Serial connection, and we should timeout and throw an error.
    if (numCharsRead > TFMINI_MAXBYTESBEFOREHEADER) {
      state = ERROR_SERIAL_NOHEADER;
      distance = -1;
      strength = -1;
      if (TFMINI_DEBUGMODE == 1)// Serial.println("ERROR: no header");
      return -1;
    }

  }

  // Step 2: Read one frame from the TFMini
  uint8_t frame[TFMINI_FRAME_SIZE];

  uint8_t checksum = 0x59 + 0x59;
  for (int i=0; i<TFMINI_FRAME_SIZE; i++) {
    // Read one character
    while (!streamPtr->available()) {
      // wait for a character to become available
    }
    frame[i] = streamPtr->read();

    // Store running checksum
    if (i < TFMINI_FRAME_SIZE-2) {
      checksum += frame[i];
    }
  }

  // Step 2A: Compare checksum
  // Last byte in the frame is an 8-bit checksum
  uint8_t checksumByte = frame[TFMINI_FRAME_SIZE-1];
  if (checksum != checksumByte) {
    state = ERROR_SERIAL_BADCHECKSUM;
    distance = -1;
    strength = -1;
    if (TFMINI_DEBUGMODE == 1)// Serial.println("ERROR: bad checksum");
    return -1;
  }


  // Step 3: Interpret frame
  uint16_t dist = (frame[1] << 8) + frame[0];
  uint16_t st = (frame[3] << 8) + frame[2];
  uint8_t reserved = frame[4];
  uint8_t originalSignalQuality = frame[5];


  // Step 4: Store values
  distance = dist;
  strength = st;
  state = MEASUREMENT_OK;

  // Return success
  return 0;
}

Step 2 -> my testing code:

/* This example shows how to use the TFMini module.
The nodeMCU have an build in Watchdog and therefore it is necessary,
that you delete/disable all <<Serial.print>> commands from the TFMini.cpp.
Otherwise you will run into an restart loop, because the Watchdog become
activated...

Wiring:
TFMini  -> nodeMCU
SDA     -> D2 -> 4 -> Tx
SCL     -> D1 -> 5 -> Rx
VCC     -> 5V
GND     -> GND
*/
#include <Arduino.h>
#include <SoftwareSerial.h>
#include "TFMini.h"

// Setup software serial port
SoftwareSerial mySerial(5, 4);      // connection to TFMini
TFMini         tfmini;              // tfmini access
unsigned long  previousMillis = 0;  // access time
const long interval = 10;           // interval at which to measure (milliseconds)

/*
-----------------S E T U P-----------------
*/
void setup() {
  // Step 1: Initialize hardware serial port (serial debug port)
  Serial.begin(115200);
  // wait for serial port to connect. Needed for native USB port only
  while (!Serial);

  // Step 2: Initialize the data rate for the SoftwareSerial port
  mySerial.begin(TFMINI_BAUDRATE);  // default boudrate is 115200
  delay(10);

  // Step 3: Initialize the TF Mini sensor
  tfmini.begin(&mySerial);
  Serial.println ("Initializing Serial and mySerial finished");
}


/*
-----------------L O O P-----------------
*/
void loop() {
  // we will not use an delay...
  // but we wait some short time before taking the next measurement
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    // save the last measure time
    previousMillis = currentMillis;
    // Take one TF Mini distance measurement
    uint16_t dist = tfmini.getDistance();
    uint16_t strength = tfmini.getRecentSignalStrength();
    // Display the measurement
    Serial.print(dist);
    Serial.print(" cm   Signal: ");
    Serial.println(strength);
  }
}

Amazing and thank you for your solution 😀 . Also FYI this solution works even for TF-LUNA LIDAR

@HuanLiangTsai
Copy link

I followed the above two steps and code. However, I got the following message. How can I solve the problem? Many thanks.

TF Mini error: too many measurement attempts
Last error:
ERROR_SERIAL_BADCHECKSUM
65535 cm Signal: 65535

@HuanLiangTsai
Copy link

Finally the results showing "65535 cm Signal: 65535" were not correct, I am sincerely asking possible help. Many thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants