Skip to content

Commit e9d56d9

Browse files
authored
Merge branch 's2025_teamA' into A4_planning
2 parents d3ee30e + d87f5a5 commit e9d56d9

13 files changed

Lines changed: 1222 additions & 109 deletions

File tree

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,8 @@ cython_debug/
168168

169169
.vscode/
170170
setup/zed_sdk.run
171-
cuda/
171+
172+
cuda/
173+
#Ignore ROS bags
174+
*.bag
175+

GEMstack/mathutils/dubins.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def derivative(self,x,u):
4444
right = [-fwd[1],fwd[0]]
4545
phi = u[1]
4646
d = u[0]
47-
return np.array([fwd[0]*d,fwd[1]*d,phi])
47+
return np.array([fwd[0]*d,fwd[1]*d,phi*d])
4848

4949

5050
class DubinsCarIntegrator(ControlSpace):

GEMstack/mathutils/transforms.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ def vector_dist(v1, v2) -> float:
3636
"""Euclidean distance between two vectors"""
3737
return vo.distance(v1,v2)
3838

39+
def vector_dot(v1, v2) -> float:
40+
"""Dot product between two vectors"""
41+
return vo.dot(v1,v2)
42+
43+
def vector_cross(v1, v2) -> float:
44+
"""Cross product between two 2D vectors"""
45+
return vo.cross(v1,v2)
46+
3947
def vector2_angle(v1, v2 = None) -> float:
4048
"""find the ccw angle bewtween two 2d vectors"""
4149
if v2 is None:
@@ -123,3 +131,16 @@ def xy_to_lat_lon(x_east : float, y_north : float, lat_reference : float, lon_re
123131
# convert GNSS waypoints into local fixed frame reprented in x and y
124132
lat, lon = axy.xy2ll(x_east, y_north, lat_reference, lon_reference)
125133
return lat, lon
134+
135+
def quaternion_to_euler(x : float, y : float, z : float, w : float):
136+
t0 = +2.0 * (w * x + y * z)
137+
t1 = +1.0 - 2.0 * (x * x + y * y)
138+
roll = np.arctan2(t0, t1)
139+
t2 = +2.0 * (w * y - z * x)
140+
t2 = +1.0 if t2 > +1.0 else t2
141+
t2 = -1.0 if t2 < -1.0 else t2
142+
pitch = np.arcsin(t2)
143+
t3 = +2.0 * (w * z + x * y)
144+
t4 = +1.0 - 2.0 * (y * y + z * z)
145+
yaw = np.arctan2(t3, t4)
146+
return [roll, pitch, yaw]
Lines changed: 60 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,107 @@
1-
# ROS Headers
1+
#!/usr/bin/env python3
2+
"""
3+
Capture ROS messages and save each run in its own time-stamped folder.
4+
"""
5+
26
import rospy
3-
from sensor_msgs.msg import Image,PointCloud2
7+
from sensor_msgs.msg import Image, PointCloud2
48
import sensor_msgs.point_cloud2 as pc2
59
import ctypes
610
import struct
7-
8-
# OpenCV and cv2 bridge
911
import cv2
1012
from cv_bridge import CvBridge
1113
import numpy as np
1214
import os
15+
import datetime
1316

1417
lidar_points = None
1518
camera_image = None
1619
depth_image = None
1720
bridge = CvBridge()
1821

19-
def lidar_callback(lidar : PointCloud2):
22+
def lidar_callback(lidar: PointCloud2):
2023
global lidar_points
2124
lidar_points = lidar
2225

23-
def camera_callback(img : Image):
26+
def camera_callback(img: Image):
2427
global camera_image
2528
camera_image = img
2629

27-
def depth_callback(img : Image):
30+
def depth_callback(img: Image):
2831
global depth_image
2932
depth_image = img
3033

31-
def pc2_to_numpy(pc2_msg, want_rgb = False):
34+
def pc2_to_numpy(pc2_msg, want_rgb=False):
3235
gen = pc2.read_points(pc2_msg, skip_nans=True)
3336
if want_rgb:
34-
xyzpack = np.array(list(gen),dtype=np.float32)
37+
xyzpack = np.array(list(gen), dtype=np.float32)
3538
if xyzpack.shape[1] != 4:
3639
raise ValueError("PointCloud2 does not have points")
37-
xyzrgb = np.empty((xyzpack.shape[0],6))
38-
xyzrgb[:,:3] = xyzpack[:,:3]
39-
for i,x in enumerate(xyzpack):
40-
rgb = x[3]
41-
# cast float32 to int so that bitwise operations are possible
42-
s = struct.pack('>f' ,rgb)
43-
i = struct.unpack('>l',s)[0]
44-
# you can get back the float value by the inverse operations
45-
pack = ctypes.c_uint32(i).value
46-
r = (pack & 0x00FF0000)>> 16
47-
g = (pack & 0x0000FF00)>> 8
40+
xyzrgb = np.empty((xyzpack.shape[0], 6))
41+
xyzrgb[:, :3] = xyzpack[:, :3]
42+
for i, x in enumerate(xyzpack):
43+
rgb = x[3]
44+
s = struct.pack('>f', rgb)
45+
i_val = struct.unpack('>l', s)[0]
46+
pack = ctypes.c_uint32(i_val).value
47+
r = (pack & 0x00FF0000) >> 16
48+
g = (pack & 0x0000FF00) >> 8
4849
b = (pack & 0x000000FF)
49-
#r,g,b values in the 0-255 range
50-
xyzrgb[i,3:] = (r,g,b)
50+
xyzrgb[i, 3:] = (r, g, b)
5151
return xyzrgb
5252
else:
53-
return np.array(list(gen),dtype=np.float32)[:,:3]
53+
return np.array(list(gen), dtype=np.float32)[:, :3]
5454

55-
def save_scan(lidar_fn,color_fn,depth_fn):
56-
print("Saving scan to",lidar_fn,color_fn,depth_fn)
57-
pc = pc2_to_numpy(lidar_points,want_rgb=False)
58-
np.savez(lidar_fn,pc)
59-
cv2.imwrite(color_fn,bridge.imgmsg_to_cv2(camera_image))
55+
def save_scan(lidar_fn, color_fn, depth_fn):
56+
print("Saving scan to", lidar_fn, color_fn, depth_fn)
57+
pc = pc2_to_numpy(lidar_points, want_rgb=False)
58+
np.savez(lidar_fn, pc)
59+
cv2.imwrite(color_fn, bridge.imgmsg_to_cv2(camera_image))
6060
dimage = bridge.imgmsg_to_cv2(depth_image)
6161
dimage_non_nan = dimage[np.isfinite(dimage)]
62-
print("Depth range",np.min(dimage_non_nan),np.max(dimage_non_nan))
63-
dimage = np.nan_to_num(dimage,nan=0,posinf=0,neginf=0)
64-
dimage = (dimage/4000*0xffff)
65-
print("Depth pixel range",np.min(dimage),np.max(dimage))
62+
print("Depth range", np.min(dimage_non_nan), np.max(dimage_non_nan))
63+
dimage = np.nan_to_num(dimage, nan=0, posinf=0, neginf=0)
64+
dimage = (dimage / 4000 * 0xffff)
65+
print("Depth pixel range", np.min(dimage), np.max(dimage))
6666
dimage = dimage.astype(np.uint16)
67-
cv2.imwrite(depth_fn,dimage)
67+
cv2.imwrite(depth_fn, dimage)
68+
69+
def main(base_folder='data', start_index=1):
70+
# unique folder for this capture run based on the current date/time.
71+
run_timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
72+
run_folder = os.path.join(base_folder, run_timestamp)
73+
os.makedirs(run_folder, exist_ok=True)
74+
print("Capture run folder:", run_folder)
75+
76+
rospy.init_node("capture_lidar_zed", disable_signals=True)
77+
rospy.Subscriber("/lidar1/velodyne_points", PointCloud2, lidar_callback)
78+
rospy.Subscriber("/zed2/zed_node/rgb/image_rect_color", Image, camera_callback)
79+
rospy.Subscriber("/zed2/zed_node/depth/depth_registered", Image, depth_callback)
6880

69-
def main(folder='data',start_index=1):
70-
rospy.init_node("capture_lidar_zed",disable_signals=True)
71-
lidar_sub = rospy.Subscriber("/lidar1/velodyne_points", PointCloud2, lidar_callback)
72-
camera_sub = rospy.Subscriber("/zed2/zed_node/rgb/image_rect_color", Image, camera_callback)
73-
depth_sub = rospy.Subscriber("/zed2/zed_node/depth/depth_registered", Image, depth_callback)
7481
index = start_index
7582
print("Press any key to:")
76-
print(" store lidar point clouds as npz")
77-
print(" store color images as png")
78-
print(" store depth images (m scaled by 0xffff/4000) as 16-bit tif")
83+
print(" - store lidar point clouds as npz")
84+
print(" - store color images as png")
85+
print(" - store depth images (m scaled by 0xffff/4000) as 16-bit tif")
7986
print("Press Escape or Ctrl+C to quit")
80-
while True:
81-
if camera_image:
82-
cv2.imshow("result",bridge.imgmsg_to_cv2(camera_image))
87+
88+
while not rospy.is_shutdown():
89+
if camera_image is not None:
90+
cv2.imshow("result", bridge.imgmsg_to_cv2(camera_image))
8391
key = cv2.waitKey(30)
8492
if key == -1:
85-
#nothing
86-
pass
93+
pass # No key pressed.
8794
elif key == 27:
88-
#escape
89-
break
95+
break # Escape key pressed.
9096
else:
9197
if lidar_points is None or camera_image is None or depth_image is None:
9298
print("Missing some messages?")
9399
else:
94-
files = [os.path.join(folder,'lidar{}.npz'.format(index)),
95-
os.path.join(folder,'color{}.png'.format(index)),
96-
os.path.join(folder,'depth{}.tif'.format(index))]
100+
files = [
101+
os.path.join(run_folder, 'lidar{}.npz'.format(index)),
102+
os.path.join(run_folder, 'color{}.png'.format(index)),
103+
os.path.join(run_folder, 'depth{}.tif'.format(index))
104+
]
97105
save_scan(*files)
98106
index += 1
99107

@@ -105,4 +113,4 @@ def main(folder='data',start_index=1):
105113
folder = sys.argv[1]
106114
if len(sys.argv) >= 3:
107115
start_index = int(sys.argv[2])
108-
main(folder,start_index)
116+
main(folder, start_index)

0 commit comments

Comments
 (0)