Compare commits

...

2 Commits

Author SHA1 Message Date
084ae634d0 7-11 2025-07-11 01:06:59 +08:00
ca0d875b1d r2分支 2025-07-10 13:14:47 +08:00
32 changed files with 333 additions and 510 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"cmake.sourceDirectory": "/home/robofish/RC2025/src/rm_msg"
}

View File

@ -2,11 +2,11 @@ source install/setup.bash
commands=(
"ros2 launch rm_nav_bringup bringup_real.launch.py \
world:=RC2026 \
world:=1 \
mode:=mapping \
lio:=fastlio \
localization:=icp \
lio_rviz:=false \
lio_rviz:=true \
nav_rviz:=true"
)

6
nav.sh
View File

@ -1,7 +1,7 @@
# 备场代码
source install/setup.bash
commands=(
"/bin/python3 /home/robofish/RC2025/src/rm_driver/rm_serial_driver/script/pub_aim.py"
"ros2 launch rm_nav_bringup bringup_real.launch.py \
world:=RC2026 \
mode:=nav \
@ -10,7 +10,9 @@ commands=(
lio_rviz:=false \
nav_rviz:=true"
"ros2 launch rm_simpal_move simple_move.launch.py"
"ros2 topic pub /move_goal rm_msgs/msg/MoveGoal '{x: 0.60, y: 3.995, angle: 0.0, max_speed: 10.0, tolerance: 0.1, rotor: false}' --once"
"/bin/python3 /home/robofish/RC2025/src/rm_driver/rm_serial_driver/script/R2_Serial.py"
"/bin/python3 /home/robofish/RC2025/src/rm_driver/rm_serial_driver/script/slect.py map"
)
for cmd in "${commands[@]}"; do

View File

@ -1,16 +1,18 @@
# 备场代码
source install/setup.bash
commands=(
"/bin/python3 /home/robofish/RC2025/src/rm_driver/rm_serial_driver/script/pub_aim.py"
"ros2 launch rm_nav_bringup bringup_real.launch.py \
world:=RC2025 \
world:=map1 \
mode:=nav \
lio:=fastlio \
localization:=icp \
lio_rviz:=false \
nav_rviz:=true"
"ros2 launch rm_simpal_move simple_move.launch.py"
"ros2 topic pub /move_goal rm_msgs/msg/MoveGoal '{x: 0.56, y: 3.960, angle: 0.0, max_speed: 10.0, tolerance: 0.1, rotor: false}' --once"
"/bin/python3 /home/robofish/RC2025/src/rm_driver/rm_serial_driver/script/R2_Serial.py"
"/bin/python3 /home/robofish/RC2025/src/rm_driver/rm_serial_driver/script/slect.py map1"
)
for cmd in "${commands[@]}"; do

21
nav2.sh Normal file
View File

@ -0,0 +1,21 @@
# 备场代码
source install/setup.bash
commands=(
"ros2 launch rm_nav_bringup bringup_real.launch.py \
world:=map2 \
mode:=nav \
lio:=fastlio \
localization:=icp \
lio_rviz:=false \
nav_rviz:=true"
"ros2 launch rm_simpal_move simple_move.launch.py"
"/bin/python3 /home/robofish/RC2025/src/rm_driver/rm_serial_driver/script/R2_Serial.py"
"/bin/python3 /home/robofish/RC2025/src/rm_driver/rm_serial_driver/script/slect.py map2"
)
for cmd in "${commands[@]}"; do
gnome-terminal -- bash -c "source install/setup.bash; $cmd; exec bash"
sleep 0.5
done

View File

@ -25,7 +25,7 @@
},
"lidar_configs" : [
{
"ip" : "192.168.1.137",
"ip" : "192.168.1.176",
"pcl_data_type" : 1,
"pattern_mode" : 0,
"extrinsic_parameter" : {

View File

@ -0,0 +1,209 @@
import rclpy
from rclpy.node import Node
import serial
import struct
from rm_msgs.msg import DataAim
from geometry_msgs.msg import TransformStamped
import tf2_ros
import tf2_geometry_msgs
import time
class AimDataSerial(Node):
def __init__(self):
super().__init__('aim_data_serial')
# 串口配置
self.serial_port_r2 = '/dev/r2'
self.serial_port_r1 = '/dev/ttyACM0'
self.baud_rate = 115200
# 重连计数器
self.r1_reconnect_count = 0
self.r2_reconnect_count = 0
self.max_reconnect_attempts = 5
# 初始化串口连接
self.init_serial_connections()
# TF2监听器用于获取baselink在map上的坐标
self.tf_buffer = tf2_ros.Buffer()
self.tf_listener = tf2_ros.TransformListener(self.tf_buffer, self)
# 订阅话题
self.subscription = self.create_subscription(
DataAim,
'/chassis/data_aim',
self.aim_callback,
10
)
# 定时器,定期获取和发送坐标数据
self.timer = self.create_timer(0.1, self.position_timer_callback) # 10Hz
# 计数器,用于减少日志输出
self.position_counter = 0
self.get_logger().info('Aim data serial node started')
def init_serial_connections(self):
"""初始化串口连接"""
# 初始化r2串口瞄准数据
self.serial_conn_r2 = self.open_serial_port(self.serial_port_r2, "r2")
# 初始化r1串口坐标数据
self.serial_conn_r1 = self.open_serial_port(self.serial_port_r1, "r1")
def open_serial_port(self, port, name):
"""打开串口返回串口对象或None"""
try:
ser = serial.Serial(
port=port,
baudrate=self.baud_rate,
timeout=1
)
self.get_logger().info(f'Serial port {port} ({name}) opened successfully')
return ser
except Exception as e:
self.get_logger().error(f'Failed to open serial port {name}: {e}')
return None
def reconnect_serial(self, port, name, current_conn, reconnect_count_attr):
"""尝试重新连接串口"""
reconnect_count = getattr(self, reconnect_count_attr)
if reconnect_count >= self.max_reconnect_attempts:
return None
self.get_logger().warn(f'Attempting to reconnect {name} (attempt {reconnect_count + 1})')
# 关闭现有连接
if current_conn and current_conn.is_open:
current_conn.close()
# 等待一下再重连
time.sleep(0.5)
# 尝试重新连接
new_conn = self.open_serial_port(port, name)
setattr(self, reconnect_count_attr, reconnect_count + 1)
if new_conn:
# 重连成功,重置计数器
setattr(self, reconnect_count_attr, 0)
self.get_logger().info(f'{name} reconnected successfully')
return new_conn
def safe_serial_write(self, serial_conn, data, port_name):
"""安全的串口写入,包含错误处理和重连"""
if not serial_conn:
return False
try:
serial_conn.write(data)
return True
except Exception as e:
self.get_logger().error(f'Write error on {port_name}: {e}')
# 尝试重连
if port_name == "r1":
self.serial_conn_r1 = self.reconnect_serial(
self.serial_port_r1, "r1", self.serial_conn_r1, "r1_reconnect_count"
)
elif port_name == "r2":
self.serial_conn_r2 = self.reconnect_serial(
self.serial_port_r2, "r2", self.serial_conn_r2, "r2_reconnect_count"
)
return False
def aim_callback(self, msg):
if not self.serial_conn_r2:
return
try:
# 提取yaw和distance数据
yaw = msg.yaw
distance = msg.distance
self.get_logger().info(f'Received - yaw: {yaw}, distance: {distance}')
# 构建发送数据包
# 格式: 包头(0xFF) + yaw(4字节float) + distance(4字节float) + 包尾(0xFE)
packet = bytearray()
packet.append(0xFF) # 包头
packet.extend(struct.pack('<f', yaw)) # yaw (小端序float)
packet.extend(struct.pack('<f', distance)) # distance (小端序float)
packet.append(0xFE) # 包尾
# 发送数据到r2串口
if self.safe_serial_write(self.serial_conn_r2, packet, "r2"):
self.get_logger().info(f'Sent aim packet to r2: {packet.hex()}')
except Exception as e:
self.get_logger().error(f'Error in aim_callback: {e}')
def position_timer_callback(self):
if not self.serial_conn_r1:
return
try:
# 获取baselink相对于map的变换
transform = self.tf_buffer.lookup_transform(
'map', # 目标坐标系
'base_link', # 源坐标系
rclpy.time.Time() # 最新时间
)
# 提取位置坐标
x = transform.transform.translation.x
y = transform.transform.translation.y
z = transform.transform.translation.z
# 减少日志输出频率
self.position_counter += 1
if self.position_counter % 50 == 0: # 每5秒打印一次
self.get_logger().info(f'Position - x: {x:.3f}, y: {y:.3f}, z: {z:.3f}')
# 构建坐标数据包
# 格式: 包头(0xAA) + x(4字节float) + y(4字节float) + z(4字节float) + 包尾(0xBB)
packet = bytearray()
packet.append(0xAA) # 包头
packet.extend(struct.pack('<f', x)) # x坐标 (小端序float)
packet.extend(struct.pack('<f', y)) # y坐标 (小端序float)
packet.extend(struct.pack('<f', z)) # z坐标 (小端序float)
packet.append(0xBB) # 包尾
# 发送数据到r1串口
if self.safe_serial_write(self.serial_conn_r1, packet, "r1"):
if self.position_counter % 50 == 0: # 只在打印位置时也打印发送信息
self.get_logger().info(f'Sent position packet to r1: {packet.hex()}')
except tf2_ros.TransformException as e:
# TF变换异常可能是坐标系不存在或时间不同步
if self.position_counter % 100 == 0: # 减少TF异常日志频率
self.get_logger().warn(f'Transform exception: {e}')
except Exception as e:
self.get_logger().error(f'Error in position_timer_callback: {e}')
def __del__(self):
if hasattr(self, 'serial_conn_r2') and self.serial_conn_r2 and self.serial_conn_r2.is_open:
self.serial_conn_r2.close()
self.get_logger().info('Serial port r2 closed')
if hasattr(self, 'serial_conn_r1') and self.serial_conn_r1 and self.serial_conn_r1.is_open:
self.serial_conn_r1.close()
self.get_logger().info('Serial port r1 closed')
def main(args=None):
rclpy.init(args=args)
try:
node = AimDataSerial()
rclpy.spin(node)
except KeyboardInterrupt:
pass
finally:
if rclpy.ok():
rclpy.shutdown()
if __name__ == '__main__':
main()

View File

@ -1,79 +0,0 @@
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
import serial
import struct
from rm_msgs.msg import DataAim # 假设使用DataAim消息类型您可以根据实际消息类型调整
class AimDataSerial(Node):
def __init__(self):
super().__init__('aim_data_serial')
# 串口配置
self.serial_port = '/dev/ttyUSB0' # 根据实际串口设备调整
self.baud_rate = 115200
try:
self.serial_conn = serial.Serial(
port=self.serial_port,
baudrate=self.baud_rate,
timeout=1
)
self.get_logger().info(f'Serial port {self.serial_port} opened successfully')
except Exception as e:
self.get_logger().error(f'Failed to open serial port: {e}')
return
# 订阅话题
self.subscription = self.create_subscription(
DataAim, # 根据实际消息类型调整
'/chassis/data_aim',
self.aim_callback,
10
)
self.get_logger().info('Aim data serial node started')
def aim_callback(self, msg):
try:
# 提取yaw和distance数据
# 根据实际消息结构调整这里假设使用Point32的x和y字段
yaw = msg.yaw
distance = msg.distance
self.get_logger().info(f'Received - yaw: {yaw}, distance: {distance}')
# 构建发送数据包
# 格式: 包头(0xFF) + yaw(4字节float) + distance(4字节float) + 包尾(0xFE)
packet = bytearray()
packet.append(0xFF) # 包头
packet.extend(struct.pack('<f', yaw)) # yaw (小端序float)
packet.extend(struct.pack('<f', distance)) # distance (小端序float)
packet.append(0xFE) # 包尾
# 发送数据
self.serial_conn.write(packet)
self.get_logger().debug(f'Sent packet: {packet.hex()}')
except Exception as e:
self.get_logger().error(f'Error in aim_callback: {e}')
def __del__(self):
if hasattr(self, 'serial_conn') and self.serial_conn.is_open:
self.serial_conn.close()
self.get_logger().info('Serial port closed')
def main(args=None):
rclpy.init(args=args)
try:
node = AimDataSerial()
rclpy.spin(node)
except KeyboardInterrupt:
pass
finally:
if rclpy.ok():
rclpy.shutdown()
if __name__ == '__main__':
main()

View File

@ -1,79 +0,0 @@
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
import serial
import struct
from rm_msgs.msg import DataAim # 假设使用DataAim消息类型您可以根据实际消息类型调整
class AimDataSerial(Node):
def __init__(self):
super().__init__('aim_data_serial')
# 串口配置
self.serial_port = '/dev/ttyUSB0' # 根据实际串口设备调整
self.baud_rate = 115200
try:
self.serial_conn = serial.Serial(
port=self.serial_port,
baudrate=self.baud_rate,
timeout=1
)
self.get_logger().info(f'Serial port {self.serial_port} opened successfully')
except Exception as e:
self.get_logger().error(f'Failed to open serial port: {e}')
return
# 订阅话题
self.subscription = self.create_subscription(
DataAim, # 根据实际消息类型调整
'/chassis/data_aim',
self.aim_callback,
10
)
self.get_logger().info('Aim data serial node started')
def aim_callback(self, msg):
try:
# 提取yaw和distance数据
# 根据实际消息结构调整这里假设使用Point32的x和y字段
yaw = msg.yaw
distance = msg.distance
self.get_logger().info(f'Received - yaw: {yaw}, distance: {distance}')
# 构建发送数据包
# 格式: 包头(0xFF) + yaw(4字节float) + distance(4字节float) + 包尾(0xFE)
packet = bytearray()
packet.append(0xFF) # 包头
packet.extend(struct.pack('<f', yaw)) # yaw (小端序float)
packet.extend(struct.pack('<f', distance)) # distance (小端序float)
packet.append(0xFE) # 包尾
# 发送数据
self.serial_conn.write(packet)
self.get_logger().debug(f'Sent packet: {packet.hex()}')
except Exception as e:
self.get_logger().error(f'Error in aim_callback: {e}')
def __del__(self):
if hasattr(self, 'serial_conn') and self.serial_conn.is_open:
self.serial_conn.close()
self.get_logger().info('Serial port closed')
def main(args=None):
rclpy.init(args=args)
try:
node = AimDataSerial()
rclpy.spin(node)
except KeyboardInterrupt:
pass
finally:
if rclpy.ok():
rclpy.shutdown()
if __name__ == '__main__':
main()

View File

@ -1,101 +0,0 @@
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
import serial
import struct
import tf2_ros
from geometry_msgs.msg import TransformStamped
from tf2_geometry_msgs import do_transform_pose
from geometry_msgs.msg import PoseStamped
import math
class SelfPositionSerial(Node):
def __init__(self):
super().__init__('self_position_serial')
# 串口配置
self.serial_port = '/dev/ttyUSB1' # 根据实际串口设备调整
self.baud_rate = 115200
try:
self.serial_conn = serial.Serial(
port=self.serial_port,
baudrate=self.baud_rate,
timeout=1
)
self.get_logger().info(f'Serial port {self.serial_port} opened successfully')
except Exception as e:
self.get_logger().error(f'Failed to open serial port: {e}')
return
# TF监听器
self.tf_buffer = tf2_ros.Buffer()
self.tf_listener = tf2_ros.TransformListener(self.tf_buffer, self)
# 定时器,定期发送位置信息
self.timer = self.create_timer(0.1, self.send_position) # 10Hz
self.get_logger().info('Self position serial node started')
def send_position(self):
try:
# 获取base_link在map下的位置
transform = self.tf_buffer.lookup_transform(
'map', 'base_link', rclpy.time.Time())
# 提取位置和朝向
x = transform.transform.translation.x
y = transform.transform.translation.y
z = transform.transform.translation.z
# 计算yaw角从四元数
quat = transform.transform.rotation
yaw = math.atan2(2.0 * (quat.w * quat.z + quat.x * quat.y),
1.0 - 2.0 * (quat.y * quat.y + quat.z * quat.z))
self.get_logger().debug(f'Position - x: {x:.3f}, y: {y:.3f}, z: {z:.3f}, yaw: {yaw:.3f}')
# 构建发送数据包
# 格式: 包头(0xFF) + x(4字节) + y(4字节) + z(4字节) + yaw(4字节) + 校验和(1字节) + 包尾(0xFE)
packet = bytearray()
packet.append(0xFF) # 包头
packet.extend(struct.pack('<f', x)) # x坐标
packet.extend(struct.pack('<f', y)) # y坐标
packet.extend(struct.pack('<f', z)) # z坐标
packet.extend(struct.pack('<f', yaw)) # yaw角
# 计算校验和(数据部分的异或校验)
checksum = 0
for i in range(1, len(packet)):
checksum ^= packet[i]
packet.append(checksum)
packet.append(0xFE) # 包尾
# 发送数据
self.serial_conn.write(packet)
self.get_logger().debug(f'Sent position packet: {packet.hex()}')
except Exception as e:
self.get_logger().warn(f'Failed to get transform or send data: {e}')
def __del__(self):
if hasattr(self, 'serial_conn') and self.serial_conn.is_open:
self.serial_conn.close()
self.get_logger().info('Serial port closed')
def main(args=None):
rclpy.init(args=args)
try:
node = SelfPositionSerial()
rclpy.spin(node)
except KeyboardInterrupt:
pass
finally:
if rclpy.ok():
rclpy.shutdown()
if __name__ == '__main__':
main()

View File

@ -1,241 +0,0 @@
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
import serial
import struct
import tf2_ros
from geometry_msgs.msg import TransformStamped
from rm_msgs.msg import DataAim
import math
import threading
from rclpy.executors import MultiThreadedExecutor
class ReceiveAndPubNode(Node):
def __init__(self):
super().__init__('receive_and_pub')
# 串口配置
self.receive_port = '/dev/ttyUSB2' # 接收串口
self.send_port = '/dev/ttyUSB3' # 发送串口
self.baud_rate = 115200
try:
# 接收串口
self.receive_serial = serial.Serial(
port=self.receive_port,
baudrate=self.baud_rate,
timeout=0.1
)
# 发送串口
self.send_serial = serial.Serial(
port=self.send_port,
baudrate=self.baud_rate,
timeout=1
)
self.get_logger().info(f'Serial ports opened: {self.receive_port}, {self.send_port}')
except Exception as e:
self.get_logger().error(f'Failed to open serial ports: {e}')
return
# TF广播器和监听器
self.tf_broadcaster = tf2_ros.TransformBroadcaster(self)
self.tf_buffer = tf2_ros.Buffer()
self.tf_listener = tf2_ros.TransformListener(self.tf_buffer, self)
# 订阅瞄准数据
self.subscription = self.create_subscription(
DataAim,
'/chassis/data_aim',
self.aim_callback,
10
)
# 存储接收到的位置信息和瞄准数据
self.received_position = {'x': 0.0, 'y': 0.0, 'z': 0.0, 'yaw': 0.0, 'valid': False}
self.aim_data = {'yaw': 0.0, 'distance': 0.0, 'valid': False}
# 启动接收线程
self.receive_thread = threading.Thread(target=self.receive_position_thread)
self.receive_thread.daemon = True
self.receive_thread.start()
# 定时发送数据
self.send_timer = self.create_timer(0.1, self.send_target_data) # 10Hz
self.get_logger().info('Receive and pub node started')
def receive_position_thread(self):
"""接收位置信息的线程"""
buffer = bytearray()
while rclpy.ok():
try:
if self.receive_serial.in_waiting > 0:
data = self.receive_serial.read(self.receive_serial.in_waiting)
buffer.extend(data)
# 查找完整的数据包
while len(buffer) >= 22: # 最小包长度:包头(1) + 数据(16) + 校验(1) + 包尾(1) = 19
# 查找包头
start_idx = buffer.find(0xFF)
if start_idx == -1:
break
# 移除包头前的数据
if start_idx > 0:
buffer = buffer[start_idx:]
# 检查包长度
if len(buffer) < 22:
break
# 查找包尾
if buffer[21] == 0xFE:
# 校验数据
checksum = 0
for i in range(1, 20):
checksum ^= buffer[i]
if checksum == buffer[20]:
# 解析数据
x = struct.unpack('<f', buffer[1:5])[0]
y = struct.unpack('<f', buffer[5:9])[0]
z = struct.unpack('<f', buffer[9:13])[0]
yaw = struct.unpack('<f', buffer[13:17])[0]
self.received_position = {
'x': x, 'y': y, 'z': z, 'yaw': yaw, 'valid': True
}
# 发布tf变换
self.publish_r2_transform(x, y, z, yaw)
self.get_logger().debug(f'Received position: x={x:.3f}, y={y:.3f}, z={z:.3f}, yaw={yaw:.3f}')
else:
self.get_logger().warn('Checksum error')
# 移除已处理的数据包
buffer = buffer[22:]
else:
# 包尾不匹配,移除包头继续查找
buffer = buffer[1:]
except Exception as e:
self.get_logger().error(f'Error in receive thread: {e}')
def publish_r2_transform(self, x, y, z, yaw):
"""发布R2到map的tf变换"""
try:
t = TransformStamped()
t.header.stamp = self.get_clock().now().to_msg()
t.header.frame_id = 'map'
t.child_frame_id = 'R2'
t.transform.translation.x = x
t.transform.translation.y = y
t.transform.translation.z = z
# 将yaw角转换为四元数
t.transform.rotation.x = 0.0
t.transform.rotation.y = 0.0
t.transform.rotation.z = math.sin(yaw / 2.0)
t.transform.rotation.w = math.cos(yaw / 2.0)
self.tf_broadcaster.sendTransform(t)
except Exception as e:
self.get_logger().error(f'Error publishing tf: {e}')
def aim_callback(self, msg):
"""接收瞄准数据"""
try:
self.aim_data = {
'yaw': msg.yaw,
'distance': msg.distance,
'valid': True
}
self.get_logger().debug(f'Received aim data: yaw={msg.yaw:.3f}, distance={msg.distance:.3f}')
except Exception as e:
self.get_logger().error(f'Error in aim callback: {e}')
def get_r2_target_data(self):
"""获取R2的瞄准数据"""
try:
if not self.received_position['valid']:
return 0.0, 0.0
# 这里可以根据R2的位置计算目标数据
# 简化处理返回R2的yaw角和到原点的距离
r2_yaw = self.received_position['yaw']
r2_distance = math.sqrt(
self.received_position['x']**2 +
self.received_position['y']**2
)
return r2_yaw, r2_distance
except Exception as e:
self.get_logger().error(f'Error getting R2 target data: {e}')
return 0.0, 0.0
def send_target_data(self):
"""发送目标数据"""
try:
# 获取原始目标数据
if self.aim_data['valid']:
original_yaw = self.aim_data['yaw']
original_distance = self.aim_data['distance']
else:
original_yaw = 0.0
original_distance = 0.0
# 获取R2目标数据
r2_yaw, r2_distance = self.get_r2_target_data()
# 构建发送数据包
# 格式: 包头(0xFF) + original_yaw(4字节) + original_distance(4字节) + r2_yaw(4字节) + r2_distance(4字节) + 校验和(1字节) + 包尾(0xFE)
packet = bytearray()
packet.append(0xFF) # 包头
packet.extend(struct.pack('<f', original_yaw)) # 原始yaw
packet.extend(struct.pack('<f', original_distance)) # 原始distance
packet.extend(struct.pack('<f', r2_yaw)) # R2 yaw
packet.extend(struct.pack('<f', r2_distance)) # R2 distance
# 计算校验和
checksum = 0
for i in range(1, len(packet)):
checksum ^= packet[i]
packet.append(checksum)
packet.append(0xFE) # 包尾
# 发送数据
self.send_serial.write(packet)
self.get_logger().debug(f'Sent target packet: original({original_yaw:.3f},{original_distance:.3f}) R2({r2_yaw:.3f},{r2_distance:.3f})')
except Exception as e:
self.get_logger().error(f'Error sending target data: {e}')
def __del__(self):
if hasattr(self, 'receive_serial') and self.receive_serial.is_open:
self.receive_serial.close()
if hasattr(self, 'send_serial') and self.send_serial.is_open:
self.send_serial.close()
self.get_logger().info('Serial ports closed')
def main(args=None):
rclpy.init(args=args)
try:
node = ReceiveAndPubNode()
executor = MultiThreadedExecutor()
executor.add_node(node)
executor.spin()
except KeyboardInterrupt:
pass
finally:
if rclpy.ok():
rclpy.shutdown()
if __name__ == '__main__':
main()

View File

@ -0,0 +1,65 @@
import rclpy
from rclpy.node import Node
from rm_msgs.msg import MoveGoal
from geometry_msgs.msg import TransformStamped
import tf2_ros
import sys
# 预设多组参数
MAP_CONFIGS = {
"map": {"split_x": 7.155, "goal1": (0.65, 3.95), "goal2": (13.66, 3.73)},
"map1": {"split_x": 7.085, "goal1": (0.54, -3.28), "goal2": (13.63, -3.37)},
"map2": {"split_x": 7.075, "goal1": (0.57, -3.34), "goal2": (13.58, -3.35)},
}
class AimSelector(Node):
def __init__(self, config):
super().__init__('aim_selector')
self.split_x = config["split_x"]
self.goal1_x, self.goal1_y = config["goal1"]
self.goal2_x, self.goal2_y = config["goal2"]
self.publisher = self.create_publisher(MoveGoal, '/move_goal', 10)
self.tf_buffer = tf2_ros.Buffer()
self.tf_listener = tf2_ros.TransformListener(self.tf_buffer, self)
self.timer = self.create_timer(0.05, self.timer_callback)
def timer_callback(self):
try:
trans: TransformStamped = self.tf_buffer.lookup_transform(
'map', 'base_link', rclpy.time.Time())
x = trans.transform.translation.x
self.get_logger().info(f'base_link x in map: {x:.2f}')
msg = MoveGoal()
if x < self.split_x:
msg.x = self.goal1_x
msg.y = self.goal1_y
else:
msg.x = self.goal2_x
msg.y = self.goal2_y
msg.angle = 0.0
msg.max_speed = 0.0
msg.tolerance = 0.1
msg.rotor = False
self.publisher.publish(msg)
except Exception as e:
self.get_logger().warn(f'Failed to get transform: {e}')
def main(args=None):
# 读取命令行参数
if len(sys.argv) < 2:
print("用法: python slect.py [map|map1|map2]")
sys.exit(1)
map_key = sys.argv[1]
if map_key not in MAP_CONFIGS:
print(f"未知参数: {map_key}")
sys.exit(1)
config = MAP_CONFIGS[map_key]
rclpy.init(args=args)
node = AimSelector(config)
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -7,7 +7,7 @@
filter_size_map: 0.5
cube_side_length: 1000.0
runtime_pos_log_enable: false
map_file_path: "src/rm_nav_bringup/PCD/RC2025.pcd"
map_file_path: "src/rm_nav_bringup/PCD/1.pcd"
common:
lid_topic: "/livox/lidar"

View File

@ -1,3 +1,3 @@
base_link2livox_frame:
xyz: "\"0.037 -0.354 0.41\""
xyz: "\"0.01906 -0.33 0.41\""
rpy: "\"0.0 0.0 0.0\""

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,7 @@
image: map1.pgm
mode: trinary
resolution: 0.05
origin: [-9.04, -13.8, 0]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.25

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,7 @@
image: map2.pgm
mode: trinary
resolution: 0.05
origin: [-7.08, -15.4, 0]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.25

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,7 @@
image: test.pgm
mode: trinary
resolution: 0.05
origin: [-9.04, -13.8, 0]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.25