Hello, thank you in advance for taking the time to try to help me remedy my current issue.
I'm utilizing a U81 Laser Range Finder from Chengdu JRT with an Arduino Mega 2560 R3. My current circuit is simply the U81 connected to 3.3V, and Tx connected to Tx1 (Pin 18), while Rx is connected to Rx1 (Pin 19).
In order to synchronize the Arduino with the laser range finder, I have written a short sketch which attempts to create a state machine to send a command to start a single automatic measurement cycle, and then await the header of the response. From there, it has to pull the payload from bytes 6, 7, 8, and 9. Once that's been done, those four bits are supposed to be equivalent to the measurement in millimeters.
I'm having trouble with getting consistent payload distances, as well as having trouble performing a calibration of the data to actually match the actual distance it's measuring currently which is ~1000mm.
I'm a bit of a noob with this aside from the occasional hobby project so any and all suggestions are appreciated! In the attempt to give as much information as possible, I'll be attaching the manufacturer datasheet pertaining to sending and receiving these measurement commands, my code, and a sample output from my Serial Monitor.
// No need to include SoftwareSerial library, as we will use hardware UART (Serial1)
// COMMANDS FROM DATASHEETs
byte one_shot_auto[9] = {0xAA, 0x00, 0x00, 0x20, 0x00, 0x01, 0x00, 0x00, 0x21};
byte reply_measurement_results[12] = {0xAA, 0x00, 0x00, 0x22, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01};
// VARs FOR WORKING WITH DATA
unsigned long Data = 0;
unsigned int SignalQuality = 0;
byte Read[12];
// Global variable to store the calibration offset
unsigned long calibrationOffset = 0;
// Function to send one-shot auto mode command
void sendOneShotAutoCommand() {
delay(10); // Small delay to ensure sensor is ready to receive
Serial1.write(one_shot_auto, 9);
}
// Function to read the response from the sensor
bool readSensorResponse() {
// Wait for the complete reply from the sensor with a timeout of 500 milliseconds
unsigned long startTime = millis();
int bytesRead = 0;
bool headerFound = false;
int startIdx = 0;
while (bytesRead < 12 && millis() - startTime < 1000) {
if (Serial1.available()) {
byte currentByte = Serial1.read();
if (!headerFound) {
if (currentByte == 0xAA) {
headerFound = true;
startIdx = bytesRead;
}
}
if (headerFound) {
Read[bytesRead] = currentByte;
bytesRead++;
// If we have received 12 bytes, check if it's a valid reply
if (bytesRead == 12) {
// Process the reply and extract the measurement data
if (Read[startIdx + 1] == 0x00 && Read[startIdx + 2] == 0x00 && Read[startIdx + 3] == 0x22 && Read[startIdx + 4] == 0x00 && Read[startIdx + 5] == 0x03) {
Data = (unsigned long)Read[startIdx + 6] << 24 | (unsigned long)Read[startIdx + 7] << 16 | (unsigned long)Read[startIdx + 8] << 8 | Read[startIdx + 9];
SignalQuality = (unsigned int)Read[startIdx + 10] << 8 | Read[startIdx + 11];
return true;
}
}
}
}
}
return false;
}
// Function to calibrate the payload distance
unsigned long calibrateDistance(unsigned long rawDistance) {
// Calculate the calibration offset if not already calculated
if (calibrationOffset == 0) {
// Replace '1000' with the actual distance in millimeters from the target
unsigned long actualDistance = 1000;
// Calculate the offset by finding the difference between measured and actual distance
calibrationOffset = actualDistance - rawDistance;
}
// Apply the calibration offset to the raw distance
unsigned long calibratedDistance = rawDistance + calibrationOffset;
return calibratedDistance;
}
// Function to print measurement data and signal quality
void printMeasurementData() {
// Extract the payload distance (measurement data)
unsigned long payloadDistance = (unsigned long)Read[6] | (unsigned long)Read[7] << 8 | (unsigned long)Read[8] << 16 | (unsigned long)Read[9] << 24;
// Calibrate the payload distance
unsigned long calibratedDistance = calibrateDistance(payloadDistance);
// Print the payload distance values
Serial.print("Payload Distance (Raw): ");
Serial.println(payloadDistance);
Serial.print("Payload Distance (Calibrated): ");
Serial.println(calibratedDistance);
// Extract the payload count (number of valid data points)
int payloadCount = (Read[5] << 8) | Read[4];
// Extract the payload signal quality
int payloadSignalQuality = (Read[11] << 8) | Read[10];
Serial.print("Payload Count: ");
Serial.println(payloadCount);
Serial.print("Payload Signal Quality: ");
Serial.println(payloadSignalQuality);
// If the payload count is not 3, print the raw data
if (payloadCount != 3) {
Serial.println("Invalid response or no response received.");
printRawData();
}
}
void printRawData() {
// Add debug information
unsigned int payloadCount = (Read[5] << 8) | Read[4];
unsigned long payloadDistance = (unsigned long)Read[9] << 24 | (unsigned long)Read[8] << 16 | (unsigned long)Read[7] << 8 | Read[6];
Serial.print("Payload Count: ");
Serial.println(payloadCount);
Serial.print("Payload Distance: ");
Serial.println(payloadDistance);
}
//==========
void setup() {
Serial.begin(19200); // Set baud rate for Serial Monitor
delay(2000);
Serial1.begin(19200); // Set baud rate for communication with the laser range finder
}
enum State {
IDLE,
MEASURING,
};
State currentState = IDLE;
unsigned long previousMillis = 0;
//==========
void loop() {
switch (currentState) {
case IDLE:
sendOneShotAutoCommand();
currentState = MEASURING;
previousMillis = millis(); // Store the current time for delay
break;
case MEASURING:
if (millis() - previousMillis >= 500) { // Increase the timeout to 500ms
bool responseReceived = readSensorResponse();
if (responseReceived && Read[5] == 0x04) { // Check for valid payload count (4 bytes for payload distance)
printMeasurementData();
} else {
Serial.println("Invalid response or no response received.");
printRawData();
}
currentState = IDLE;
delay(100); // Add a delay before the next measurement to avoid rapid transitions
}
break;
}
}