How to Code TW10S UART Laser Module?

Hello Forum, I am new to this community, I am using TW10S Li3 Laser module for distance measurement application, i have assembled the hardware with arduino uno for software serial communication as for arduino hardware serial communication, its being used by CP2120 USB to UART so it wont interfere with laser communication.
Now the code part is left, i cannot understand its data sheet much so need a code for its Fast Continuous Measurement (iFACM) mode.

can someone help ASAP please?

My hardware connection:

  • TW10s to Arduino
    en to 5V
    tx to D2
    RX to D3
    3.3V to 3.3V
    Gnd to Gnd

  • Arduino to CP2120
    Rx to Tx
    Tx to RX
    5V to 5 V
    Gnd to Gnd
    (have checked CP and arduino communication, its working fine)

heres the datasheet:
Datasheet TW10S UART

Yeah, that's a crummy document.

One thing that might make playing with the Laser device would be to leave the Arduino out of the picture for now.

Instead, hook it up to your PC and use a terminal emulator program like PuTTY or CoolTerm to talk and listen.

That would let you type in commands and see the response, and to see any data it produces as well.

I would do that even if the documentation was the best it could be. There is no need to start coding and complicate the matter with errors you may make doing that.

I think even as bad as it is, with the documentation and some experiments using just the terminal emulator you will have vastly lees trouble almost to the point of none at all writing some simple code that will choose modes and report sensor data.

HTH

a7

1 Like

Out of curiosity I just googled

arduino TW10S

and suggest you to do that if you have not.

a7

I have visited almost all the sites having keyword Tw10S but to me was not much of help...

thanks for your suggestions, i have seen PUTTY being mentioned in one of many those sites... guess have to go beyond Arduino IDE...

Here is the update on TW10s, We connected it directly with USB to UART(CP or FT) and set Arduino aside, uploaded this code from Python (link below), and observed the readings in serial debug assistant (Microsoft), as the laser started to flash continuously, serial monitor showed some hex-based MODBUS protocol data!

Now here some info that would come in handy for decoding the data:

Continuous measurement code (to be sent by us): (01 03 00 01 00 02 95 CB)
Continuous measurement response: (01 03 04 xx xx xx xx yy yy)
where (xx: distance data yy: CRC code)

MODBUS Request Frame format:
(1Byte-address code ) (1Byte- function code) (2Bytes - initial address ) (2Bytes- Register number (N) ) (2Bytes- CRC)
MODBUS Response Frame format:
Normal response: (1Byte-address code ) (1Byte- function code) (1Bytes - Byte count ) (2 * N Bytes - Register values ) (2Bytes- CRC)
Abormal response: (1Byte-address code ) (1Byte- error code) (1Bytes - Exception code ) (2Bytes- CRC).
Exception code definition: 0x01: Error
Function code 0x02: Error start
address 0x03: Error Number Register
0x04: Error register value 0x05: CRC
Error 0x06: Equipment Busy
Continuous Code GitHub

some more commands

Hi,
I'm using a TW10S-UART sensor but i suppose it works the same.

I am using the SoftwareSerial Library in order to communicate with the sensor.

#include <SoftwareSerial.h>

#define TX_laser 4
#define RX_laser 5

SoftwareSerial Serial2(TX_laser, RX_laser);

To start measuring you need to send a request in the format that @ning_lily suggested:


uint8_t commandContinuous[8] = {0x01, 0x03, 0x00, 0x01, 0x00, 0x02, 0x95, 0xCB}; //the command for continuous reading
uint8_t commandUnique[8] = {0x01, 0x03, 0x00, 0x0F, 0x00, 0x02, 0xF4, 0x08}; //the command for one time reading
uint8_t onoff[11] = {0x01, 0x10, 0x00, 0x03, 0x00, 0x01, 0x02, 0x00, 0x01, 0x67, 0xA3}; //the command to turn it on or off
uint8_t data[9];

//*****************************************************************************

void setup() {
  // put your setup code here, to run once:
  Serial2.begin(9600); //start serial communication with the sensor
  delay(200);
  Serial2.write(onoff, 11); //turns the sensor on
}

//*****************************************************************************

void loop() {
  Serial2.write(commandUnique, 8); //ask for a one time measurement
  delay(200);
  if( Serial2.available() >0){
    Serial2.readBytes(data, 9); //reads the response and stores it as an array ( data )
    Serial2.overflow(); //clears serial2
  }

Once you have the response you can convert it to distance (in mm) using this:

uint8_t byte6_1, byte5_1, byte6_2, byte5_2, byte5_1_hex, byte5_2_hex, byte6_1_hex, byte6_2_hex;

uint8_t commandContinue[8] = {0x01, 0x03, 0x00, 0x01, 0x00, 0x02, 0x95, 0xCB};
uint8_t commandUnique[8] = {0x01, 0x03, 0x00, 0x0F, 0x00, 0x02, 0xF4, 0x08};
uint8_t marche[11] = {0x01, 0x10, 0x00, 0x03, 0x00, 0x01, 0x02, 0x00, 0x01, 0x67, 0xA3};
uint8_t data[9];
uint32_t distance;

//*****************************************************************************
uint32_t calcul_distance(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
  distance = (d * 1 + c * 16 + b * 16 * 16 + a * 16 * 16 * 16); //converts 4 hex digits into decimal
  return distance;
}

void loop() {
  Serial2.write(commandUnique, 8);
  delay(200);
  if( Serial2.available() >0){
    Serial2.readBytes(data, 9);
    Serial2.overflow();
  }

  delay(200);
  byte5_1 = data[5] / 16;
  byte5_2 = data[5] - byte5_1 * 16;
  byte6_1 = data[6] / 16;
  byte6_2 = data[6] - byte6_1 * 16;
  distance = calcul_distance(byte5_1, byte5_2, byte6_1, byte6_2);
  if (distance < 20000) {
    Serial.println(distance);
  }

}

Once you have the values you can use the CRC code to check the integrity of the values you received. to do that i am using the CRC library like so:

#include <CRC16.h>

CRC16 crc(CRC16_MODBUS_POLYNOME,
          CRC16_MODBUS_INITIAL,
          CRC16_MODBUS_XOR_OUT,
          CRC16_MODBUS_REV_IN,
          CRC16_MODBUS_REV_OUT);

/*...*/

void loop() {
  Serial2.write(commandUnique, 8);
  delay(200);
  if( Serial2.available() >0){
    Serial2.readBytes(data, 9);
    Serial2.overflow();
  }

  for(int i = 0; i < sizeof(data); i++)
  {
    crc.add(data[i]);
  }
  uint8_t CRC = crc.calc(); //calculates CRC check code

  if( CRC ==0 ) { //the data is valid only if CRC value is 0

    delay(200);
    byte5_1 = data[5] / 16;
    byte5_2 = data[5] - byte5_1 * 16;
    byte6_1 = data[6] / 16;
    byte6_2 = data[6] - byte6_1 * 16;
    distance = calcul_distance(byte5_1, byte5_2, byte6_1, byte6_2);

    if (distance < 20000) {
      Serial.println(distance);
    }
 }
  crc.restart(); //resets the library to be able to calculate another crc check code
}

That way you can decide to only calculate the distance if the data has been received correctly

Here is the whole code:


#include <CRC16.h>


//*****************************************************************************
#include <SoftwareSerial.h>

#define TX_laser 4
#define RX_laser 5

SoftwareSerial Serial2(TX_laser, RX_laser);

CRC16 crc(CRC16_MODBUS_POLYNOME,
          CRC16_MODBUS_INITIAL,
          CRC16_MODBUS_XOR_OUT,
          CRC16_MODBUS_REV_IN,
          CRC16_MODBUS_REV_OUT);



uint8_t byte6_1, byte5_1, byte6_2, byte5_2, byte5_1_hex, byte5_2_hex, byte6_1_hex, byte6_2_hex;

uint8_t commandContinue[8] = {0x01, 0x03, 0x00, 0x01, 0x00, 0x02, 0x95, 0xCB};
uint8_t commandUnique[8] = {0x01, 0x03, 0x00, 0x0F, 0x00, 0x02, 0xF4, 0x08};
uint8_t marche[11] = {0x01, 0x10, 0x00, 0x03, 0x00, 0x01, 0x02, 0x00, 0x01, 0x67, 0xA3};
uint8_t data[9];
uint32_t distance;


//*****************************************************************************
uint32_t calcul_distance(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {

  distance = (d * 1 + c* 16 + b * 16 * 16 + a * 16 * 16 * 16); //converts the 4 hex digits into decimal
  return distance;
}

//*****************************************************************************
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial2.begin(9600);
  delay(200);
  Serial.print("start");
  Serial2.write(marche, 11);
}

//*****************************************************************************

void loop() {
  Serial2.write(commandUnique, 8);
  delay(200);
  if( Serial2.available() >0){
    Serial2.readBytes(data, 9);
    Serial2.overflow();
  }

  for(int i = 0; i < sizeof(data); i++)
  {
    //Serial.print(data[i], HEX);
    //Serial.print("  ");
    crc.add(data[i]);
  }
  uint8_t CRC = crc.calc();
  //Serial.println(CRC, HEX);

  delay(200);
  byte5_1 = data[5] / 16;
  byte5_2 = data[5] - byte5_1 * 16;
  byte6_1 = data[6] / 16;
  byte6_2 = data[6] - byte6_1 * 16;
  distance = calcul_distance(byte5_1, byte5_2, byte6_1, byte6_2);

  if (distance < 20000 && CRC ==0) {
    Serial.println(distance);
  }

  crc.restart();
}

Thanks @guillaume_lrt for the complete code and all that simple explanation, will surely try that ASAP... :slightly_smiling_face:

Hi @guillaume_lrt Thank you for your code and for the step by step notes!

I tried using your code but can't seem to get my TW10S UART module to work.
All I get is a blinking laser and no output on the serial.
(I get an output on the serial when the module is not connected. (just a bunch of 0s)

I have the module wired to an arduino nano every so that:
3.3v goes to 3.3v
gnd goes to gnd
#define TX_laser 8
#define RX_laser 9
and connected the EN_PWR input on the module to 5v.

How did you wire the module? any guidance would be appreciated!

Thank you.

Hi! I'm glad you could try my code.
Here is the wiring i'm using (the pins used here are 3 and 4 for RX & TX so it becomes

#define TX_laser 4
#define RX_laser 3

)
wiring_laser_TW10S

You can notice I'm using a 3.3V voltage regulator in order to transform the +5V of the arduino into +3.3V. I'm also using a voltage divider bridge so that the data transmitted by the arduino is never above 3.3V (higher voltage could cause damage to the laser even though it could work)

To solve your problem i recommend checking your wiring and make sure when you initialize the SoftwareSerial library you pass as parameter first the receiver pin (the one connected to the transmitter = TX_laser) and then the transmitter pin (which is connected to the receiver pin of the laser = RX_laser)

If it still doesn't work could you show us your code & wiring so that we can get a closer look at what you're doing?

Good luck!

1 Like

Hi Guillaume_Irt,
Thank you!
I added the voltage divider and now it works!

Really appreciate your help.
-JML

Thank you for all of your help! My Due is talking to the laser module very well.
Did you ever find out what command changes the measurement frequency? It doesn't appear to be on that list and I'm stuck at measuring around 0.5-1Hz

Hello,
Glad to see my answer helped !
Sorry i haven't found that command and I have the same problem :frowning:
If you want you can take a look at the tutorial I posted here (in French) maybe you can find some answer to other problems you may be troubling with...