I’m trying to print data for 0 to 1080 steps in real time using socket. Unfortunately, I can’t use ROS2 because it’s too much of a headache to set up on Windows and Mac M2. I’m using Ethernet to communicate via a socket with the UAM-05LP. However, pyserial doesn’t seem to be working for me. Below is the code I have right now for the UAM-05LP. Comparing the data obtained from the official software to my implementation, there’s a significant difference: the official software shows consistent and real-time data, while the data from the socket connection is inconsistent and different.
Problem list here:
The data obtained from the Hokuyo UAM-05LP using PySerial is different from the data displayed by the Hokuyo official software. See the below photo showing the terminal output and the official Hokuyo software for comparison.
I want to use a NumPy array instead of a regular list for better performance. I’m looking for suggestions on how to achieve this.
Question I have: What did I do wrong? lol
A screenshot of an official software log(urgbenriplus on windows): (The log shows the step and range data arranged in table format below)
Step Range 0
0 928
1 1155
2 1155
3 1124
4 906
5 827
____________
0 961
1 1158
2 1165
3 1145
4 908
5 839
____________
0 925
1 1154
2 1157
3 1138
4 912
5 837
____________
0 939
1 1160
2 1161
3 1148
4 893
5 841
my terminal output:
lidar data to 5 indexes: [2702, 2255, 2174, 2158, 2149]
lidar data to 5 indexes: [41, 41, 46, 46, 46]
lidar data to 5 indexes: [2304, 2240, 2240, 2240, 2240]
lidar data to 5 indexes: [1553, 1553, 1549, 1555, 1544]
lidar data to 5 indexes: [48, 48, 48, 48, 49]
lidar data to 5 indexes: [2752, 3008, 3456, 3968, 0]
lidar data to 5 indexes: [3320, 3310, 3307, 3295, 3291]
lidar data to 5 indexes: [8, 8, 8, 8, 9]
lidar data to 5 indexes: [1408, 832, 768, 1024, 1024]
lidar data to 5 indexes: [2473, 1971, 1777, 1735, 1729]
lidar data to 5 indexes: [36, 35, 35, 35, 35]
lidar data to 5 indexes: [128, 2496, 704, 3648, 3648]
lidar data to 5 indexes: [666, 648, 648, 659, 653]
lidar data to 5 indexes: [36, 37, 37, 37, 36]
lidar data to 5 indexes: [1152, 2112, 2176, 1728, 64]
lidar data to 5 indexes: [3228, 3210, 3222, 3273, 3262]
lidar data to 5 indexes: [0, 64, 0, 64, 1957]
lidar data to 5 indexes: [1541, 1538, 1527, 1485, 1187]
lidar data to 5 indexes: [48, 48, 48, 48, 49]
lidar data to 5 indexes: [2880, 3200, 3136, 3584, 3968]
lidar data to 5 indexes: [3316, 3316, 3306, 3297, 3293]
lidar data to 5 indexes: [8, 8, 8, 8, 8]
So, see the big difference between terminal and table from the official program. What should I do to make it more accurate and same as first sample?
See the code below:
import socket
import traceback
import time
class HokuyoLiDAR:
def __init__(self, ip_address="192.168.0.10", port=10940):
self.socket = None
self.ip_address = ip_address
self.port = port
self.is_connected = False
def connect(self):
try:
if self.is_connected:
return True
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.settimeout(5)
print(f"Attempting to connect to {self.ip_address}:{self.port}")
self.socket.connect((self.ip_address, self.port))
print("Connected to LiDAR")
# Initialize SCIP2.0 protocol
self.socket.sendall(b"SCIP2.0\n")
response = self.socket.recv(1024).decode('ascii')
if "SCIP2.0" not in response:
raise ConnectionError("Failed to initialize SCIP2.0 protocol")
self.socket.sendall(b"VV\n")
response = self.socket.recv(1024).decode('ascii')
if not response:
raise ConnectionError("No response from status request")
self.is_connected = True
print("Successfully initialized SCIP2.0 protocol")
return True
except Exception as e:
print(f"Connection failed: {e}")
if self.socket:
self.socket.close()
self.socket = None
self.is_connected = False
return False
def decode_data(self, data: str) -> dict:
"""Decode the SCIP2.0 data format into human-readable format"""
try:
lines = data.strip().split('\n')
if len(lines) < 3:
return {"error": "Incomplete data"}
# Parse measurement data
distances_mm = []
# Process each data line
for line in lines[2:]: # skip steps and timestamp
if not line.strip():
continue
# Skip line identifier (first 2 chars)
data_line = line[2:] if len(line) > 2 else line
# Process 3-character blocks
for i in range(0, len(data_line), 3):
if i + 2 < len(data_line):
# Decode the 3-character block
chars = data_line[i:i + 3]
# Convert to distance in millimeters
value = ((ord(chars[1]) - 0x30) << 6) | (ord(chars[2]) - 0x30)
distances_mm.append(value)
return distances_mm
except Exception as e:
return {"error": f"Decoding error: {str(e)}"}
def start_continuous_measurement(self):
try:
if not self.is_connected:
raise ConnectionError("Not connected to LiDAR")
# Stop any existing measurement
self.socket.sendall(b"QT\n")
response = self.socket.recv(1024).decode('ascii')
# Start new measurement
command = "MD0000108000100\n"
self.socket.sendall(command.encode())
response = self.socket.recv(1024).decode('ascii')
if not response.startswith("MD"):
raise ConnectionError("Failed to start measurement")
return response
except Exception as e:
print(f"Error starting measurement: {e}")
self.is_connected = False
raise
def read_measurement(self):
try:
if not self.is_connected:
if not self.connect():
return None
data = self.socket.recv(4096).decode('ascii')
if not data:
return None
decoded = self.decode_data(data)
print("lidar data to 5 indexes: ", decoded[:5])
return decoded[:1080] # Hokuyo ignores anything after 1080 so following the same example
except socket.timeout:
print("Timeout while reading data")
return None
except Exception as e:
print(f"Error reading measurement: {e}")
traceback.print_exc()
self.is_connected = False
return None
def disconnect(self):
if self.socket:
try:
self.socket.close()
except:
pass
self.socket = None
self.is_connected = False
print("Disconnected from LiDAR")
lidar = HokuyoLiDAR()
if lidar.connect():
lidar.start_continuous_measurement()
try:
while True:
scan = lidar.read_measurement()
time.sleep(0.1)
except KeyboardInterrupt:
lidar.disconnect()
I’m expecting to print accurate data, just like the official software program displays