前言
在机器人户外导航开发中,我们经常面临一个尴尬的局面:人在室内写代码,机器人在吃灰。因为要测试 GPS 融合定位或地图显示功能,往往需要把机器人搬到室外空旷处。
有没有一种方法,能在室内、无硬件(甚至无机器人)的情况下,在 RViz 中模拟出一个 GPS 信号,并且能像玩游戏一样通过键盘(WASD)控制机器人在真实的高德卫星地图上行走?
本文将通过一个 Python 脚本配合 rviz_satellite 插件,带你实现这套零成本的仿真环境。
准备工作
-
操作系统:Ubuntu 20.04
-
ROS 版本:Noetic
-
所需插件:
rviz_satellite
1. 安装核心插件
我们需要一个能让 RViz 加载瓦片地图的插件。
Bash
sudo apt install ros-noetic-rviz-satellite
核心步骤一:编写 GPS + TF 模拟器
RViz 的显示逻辑依赖于 TF (坐标变换),而地图插件依赖于 GPS (/fix)。因此,我们的模拟脚本必须同时做两件事:
-
发布
/fix话题:告诉地图插件“我在地球的哪个经纬度”,以便加载对应的瓦片图片。 -
发布 TF (
map->base_link):告诉 RViz “机器人在地图坐标系下的 (x, y) 坐标”,以便让机器人模型动起来。
在你的工作空间(如 ~/catkin_ws/src/your_pkg/scripts/)下新建文件 gps_simulator.py:
Python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import rospy
from sensor_msgs.msg import NavSatFix
import tf
import sys, select, termios, tty, threading, math
# === 配置区域 ===
# 初始位置:这里以西安长安大学附近为例
INIT_LAT = 34.373056
INIT_LON = 108.896667
INIT_ALT = 0.0
# 移动步长:每次按键移动 5 米
MOVE_STEP_M = 5.0
# 频率
RATE = 10.0
# 简易经纬度换算系数 (近似值)
METERS_PER_LAT = 111000.0
METERS_PER_LON = 111000.0 * math.cos(math.radians(INIT_LAT))
class GpsSimNode:
def __init__(self):
rospy.init_node('gps_simulator', anonymous=True)
# 1. 发布 GPS 话题 (给地图插件用)
self.pub = rospy.Publisher('/fix', NavSatFix, queue_size=10)
# 2. 广播 TF 变换 (给 RViz 坐标显示用)
self.tf_broadcaster = tf.TransformBroadcaster()
self.x = 0.0 # 相对原点的东向距离 (米)
self.y = 0.0 # 相对原点的北向距离 (米)
self.running = True
self.lock = threading.Lock()
print("=== GPS 模拟器已启动 ===")
print(f"初始坐标: Lat {INIT_LAT}, Lon {INIT_LON}")
print("控制方式: W(北) A(西) S(南) D(东) Q(退出)")
def publish_loop(self):
rate = rospy.Rate(RATE)
while not rospy.is_shutdown() and self.running:
with self.lock:
cx, cy = self.x, self.y
# 计算当前的经纬度
current_lat = INIT_LAT + (cy / METERS_PER_LAT)
current_lon = INIT_LON + (cx / METERS_PER_LON)
# A. 发布 GPS
msg = NavSatFix()
msg.header.stamp = rospy.Time.now()
msg.header.frame_id = "base_link"
msg.latitude = current_lat
msg.longitude = current_lon
msg.altitude = INIT_ALT
self.pub.publish(msg)
# B. 发布 TF (map -> base_link)
# 这让 RViz 知道机器人在哪里,从而消除 "Fixed Frame [map] does not exist" 报错
self.tf_broadcaster.sendTransform(
(cx, cy, 0.0),
tf.transformations.quaternion_from_euler(0, 0, 0),
rospy.Time.now(),
"base_link", "map"
)
rate.sleep()
def get_key(self):
# 非阻塞键盘读取
tty.setraw(sys.stdin.fileno())
rlist, _, _ = select.select([sys.stdin], [], [], 0.1)
key = sys.stdin.read(1) if rlist else ''
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)
return key
def run(self):
t = threading.Thread(target=self.publish_loop)
t.start()
try:
while not rospy.is_shutdown():
key = self.get_key()
if key:
with self.lock:
if key == 'w': self.y += MOVE_STEP_M
elif key == 's': self.y -= MOVE_STEP_M
elif key == 'a': self.x -= MOVE_STEP_M
elif key == 'd': self.x += MOVE_STEP_M
elif key in ['q', '\x03']:
self.running = False
break
print(f"\r当前偏移: X={self.x:.1f}m, Y={self.y:.1f}m ", end="")
finally:
self.running = False
t.join()
if __name__ == '__main__':
settings = termios.tcgetattr(sys.stdin)
try:
GpsSimNode().run()
except rospy.ROSInterruptException: pass
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)
(别忘了给脚本加权限:chmod +x gps_simulator.py)
核心步骤二:在 RViz 中接入高德地图
国内网络环境下,Google Maps 经常无法加载,而高德地图(AutoNavi)提供了极其稳定的 XYZ 瓦片服务。
-
启动 ROS:
打开终端运行 roscore。
-
运行模拟器:
打开新终端运行 python3 gps_simulator.py。
-
打开 RViz:
打开新终端运行 rviz。
-
配置 RViz (关键):
-
Global Options -> Fixed Frame: 手动输入
map。(注意:因为我们的脚本发布了 map->base_link 的 TF,所以这里必须填 map)。 -
Add: 点击左下角 Add,选择
AerialMapDisplay。 -
AerialMapDisplay 参数设置:
-
Topic: 选择
/fix。 -
Map URL: 填入以下高德卫星图链接:
Plaintexthttp://webst01.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z} -
Zoom: 设置为 18 或 19。(设置太小如 0-10 可能导致加载不出图片)。
-
Blocks: 设置为 4。
-
-
效果展示与“云行走”

完成上述配置后,你应该能看到 RViz 的黑色背景瞬间变成了高清的卫星地图。
回到运行 Python 脚本的终端,按下键盘上的 W / A / S / D:
-
现象 1:RViz 正中心的坐标轴(代表机器人)会开始移动。
-
现象 2:随着机器人的移动,周围的地图瓦片会自动加载更新,不仅实现了“定位”,还实现了“地图跟随”。
进阶技巧:如何使用离线地图?
如果你需要在断网环境下演示,可以将 QGIS 导出的图片切片放在本地文件夹(例如 /home/user/map/z/x/y.png),然后在该文件夹下运行:
Bash
python3 -m http.server 8000
最后将 RViz 中的 Map URL 改为 http://127.0.0.1:8000/{z}/{x}/{y}.png 即可完美欺骗插件加载离线图。
总结
通过本文的方法,我们解决了两个痛点:
-
解决了 RViz 报错:通过脚本广播 TF,解决了
Fixed Frame [map] does not exist的经典错误。 -
解决了地图源问题:使用了高德地图 URL,无需翻墙,无需申请 Key,加载速度极快。
现在,你可以在温暖的室内,随意模拟机器人在城市街道、校区内的行驶轨迹,调试你的路径规划算法了!

被折叠的 条评论
为什么被折叠?



