Skip to content

Commit 0bcea68

Browse files
merge simulateur
2 parents 3e2017d + 6d40f83 commit 0bcea68

107 files changed

Lines changed: 14039 additions & 15 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/pages.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
# - name: Check for hard links and symlinks
3232
# run: |
3333
# find site -type l -exec echo "Symlink found: {}" \; -o -type f -links +1 -exec echo "Hard link found: {}" \;
34-
- name: Upload build artifacts
34+
- name: Upload build artifacts
3535
uses: actions/upload-pages-artifact@v3
3636
with:
3737
name: github-pages
@@ -47,3 +47,4 @@ jobs:
4747
- name: Deploy to GitHub Pages
4848
id: deployment
4949
uses: actions/deploy-pages@v4
50+

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ site
55
*.zip
66
Captured_Frames
77
Debug
8-
Debug_Wayfinding
8+
Debug_Wayfinding
9+

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"python.analysis.autoImportCompletions": false
3+
}

Lidar_Utils/Live_display_radar.py

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
# pip install matplotlib numpy
2+
import socket
3+
import time
4+
import traceback
5+
import sys
6+
import os
7+
from itertools import cycle
8+
import binascii
9+
import _thread as thread
10+
import numpy as np
11+
import matplotlib.pyplot as plt
12+
13+
14+
IP = '192.168.0.10'
15+
PORT = 10940
16+
AUTORANGE = False
17+
18+
def partition(n: int, lst):
19+
for i in range(0, len(lst), n):
20+
yield lst[i:i + n]
21+
22+
23+
def deg2theta(deg):
24+
return deg / 360 * 2 * np.pi
25+
26+
def toCartesian(xTheta, xR):
27+
X = np.cos(xTheta) * xR
28+
Y = np.sin(xTheta) * xR
29+
return X,Y
30+
31+
class HokuyoReader():
32+
measureMsgHeads = {'ME', 'GE', 'MD', 'GD'}
33+
34+
def makeSocket(self, ip, port):
35+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
36+
sock.connect((ip, port))
37+
sock.settimeout(5)
38+
return sock
39+
40+
# decode 3 byte integer data line
41+
def decodeDistance(self, data):
42+
# remove checksum bytes for every 65 bytes of data
43+
parts = [''.join(part[:-1]) for part in list(partition(65, data))]
44+
# repack data
45+
data = ''.join(parts)
46+
# transform 3-byte int
47+
ns = [ord(d) - 0x30 for d in data]
48+
ns = [f'{d:06b}' for d in ns]
49+
ns = list(partition(3, ns))
50+
ns = [int(''.join(c3), 2) for c3 in ns]
51+
# set out-of-range value to zero
52+
ns = [0 if n == 65533 else n for n in ns]
53+
54+
self.rDistance = np.array(ns)
55+
self.mStep = self.startStep
56+
self.measuring = False
57+
return ns
58+
59+
def __init__(self, ip, port, startStep=0):
60+
self.ip = ip
61+
self.port = port
62+
# For decoding measuring data
63+
self.measuring = False
64+
self.skip = 0
65+
self.head = None
66+
# Starting step id
67+
self.startStep = startStep
68+
# Current step id, for decoding polar distance data
69+
self.mStep = startStep
70+
# Array of distance
71+
self.rDistance = np.zeros(1081-startStep, dtype=int)
72+
# Buffer to receive packets
73+
self.buf = ""
74+
self.expectedPacketSize = 65*50 + 44 # TODO hardcoded for full range measurement
75+
76+
ids = np.arange(1081-startStep)
77+
self.xTheta = deg2theta((ids + startStep) * 270.0 / 1080 + 45 - 90)
78+
79+
self.sock = self.makeSocket(ip, port)
80+
self.__startReader__()
81+
82+
83+
def send(self, cmd: str):
84+
self.sock.sendall(cmd.encode())
85+
86+
87+
def startPlotter(self):
88+
plt.show()
89+
fig = plt.figure()
90+
axc = plt.subplot(121)
91+
axp = plt.subplot(122, projection='polar')
92+
# axp.set_thetamax(deg2theta(45))
93+
# axp.set_thetamax(deg2theta(270 + 45))
94+
axp.grid(True)
95+
print('Plotter started, press any key to exit')
96+
97+
print(f'{self.xTheta}, {self.rDistance}')
98+
while True:
99+
X, Y = toCartesian(self.xTheta, self.rDistance)
100+
101+
axp.clear()
102+
axc.clear()
103+
104+
axp.plot(self.xTheta, self.rDistance)
105+
106+
axc.plot(X, Y)
107+
108+
if not AUTORANGE:
109+
axp.set_rmax(8000)
110+
axc.set_xlim(-5000, 5000)
111+
axc.set_ylim(-5000, 5000)
112+
113+
plt.pause(1e-17)
114+
115+
if plt.waitforbuttonpress(timeout=0.02):
116+
os._exit(0)
117+
118+
119+
120+
# Change hokuyo IP address, requires reboot
121+
def changeIP(self, ip: str, gateway: str, netmask='255.255.255.0'):
122+
def formatZeros(addr):
123+
return ''.join([n.rjust(3, '0') for n in addr.split('.')])
124+
125+
ip = formatZeros(ip)
126+
gateway = formatZeros(gateway)
127+
netmask = formatZeros(netmask)
128+
cmd = f'$IP{ip}{netmask}{gateway}\r\n'
129+
print(f'ChangeIP cmd: {cmd}')
130+
self.send(cmd)
131+
132+
# Start continous read mode
133+
def startContinuous(self, start: int, end: int, withIntensity=False):
134+
head = 'ME' if withIntensity else 'MD'
135+
cmd = f'{head}{start:04d}{end:04d}00000\r\n'
136+
print(cmd)
137+
self.head = cmd.strip()
138+
self.send(cmd)
139+
140+
141+
# Start single read
142+
def singleRead(self, start: int, end: int, withIntensity=False):
143+
head = 'GE' if withIntensity else 'GD'
144+
cmd = f'{head}{start:04d}{end:04d}01000\r\n'
145+
self.send( cmd)
146+
147+
def stop(self):
148+
cmd = 'QT\r\n'
149+
self.send( cmd)
150+
151+
def reboot(self):
152+
cmd = 'RB\r\n'
153+
self.send(cmd)
154+
self.send(cmd)
155+
156+
157+
def handleMsgLine(self, line):
158+
if line == self.head:
159+
self.measuring = True
160+
self.skip = 0
161+
self.mStep = self.startStep
162+
return True
163+
164+
if self.measuring:
165+
if self.skip < 2:
166+
self.skip += 1
167+
return True
168+
else:
169+
self.buf += line.strip()
170+
# print(f'buf size {len(self.buf)}')
171+
if len(self.buf) >= self.expectedPacketSize:
172+
self.decodeDistance(self.buf)
173+
self.buf = ''
174+
return True
175+
176+
return False
177+
178+
def __startReader__(self):
179+
def handleMeasuring(msg):
180+
lines = msg.split()
181+
for line in lines:
182+
if not self.handleMsgLine(line):
183+
print(f'ignore {line}')
184+
185+
def loop():
186+
try:
187+
while True:
188+
try:
189+
m, _ =self.sock.recvfrom(1024)
190+
msg = m.decode()
191+
handleMeasuring(msg)
192+
except socket.timeout as e:
193+
print('Read timeout, sensor disconnected?')
194+
os._exit(1)
195+
finally:
196+
self.sock.close()
197+
198+
thread.start_new_thread(loop, ())
199+
200+
if __name__ == '__main__':
201+
sensor = HokuyoReader(IP, PORT)
202+
sensor.stop()
203+
# sensor.singleRead(0, 1080)
204+
time.sleep(2)
205+
206+
sensor.startContinuous(0, 1080)
207+
sensor.startPlotter()

0 commit comments

Comments
 (0)