• 正文
  • 相关推荐
申请入驻 产业图谱

读读代码 | TinyNav:轻量级机器人导航系统的设计与实现

19小时前
235
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

转载自公众号:敢敢AUTOHUB

1. 引言

在机器人自主导航领域,系统的复杂度往往与其功能性成正比。传统的导航系统如ROS Navigation Stack虽然功能强大,但其庞大的代码库和复杂的配置流程给开发者带来了不小的学习成本。TinyNav项目的出现,为这一领域提供了一个全新的思路:用不到2000行的核心代码,实现一个完整的、可用于生产环境的机器人导航系统。

TinyNav是由Uniflex AI团队开发并维护的开源项目,其设计理念是**"Tiny but Robust"。该系统专为Intel RealSense深度相机NVIDIA Jetson平台优化,支持多种机器人平台,包括Unitree GO2四足机器人LeKiwi轮式机器人**。项目采用模块化架构,将导航任务分解为感知、建图、规划三个核心模块,每个模块职责清晰,接口简洁,便于理解和二次开发。

GitHub项目地址:https://github.com/UniflexAI/tinynav

1.1 核心创新点

与传统导航系统相比,TinyNav的创新之处在于其对深度学习技术的深度整合。在特征提取方面,系统使用SuperPoint网络进行关键点检测,相比传统ORB特征具有更强的鲁棒性,能够在光照变化和运动模糊场景下保持稳定的特征检测能力。在特征匹配环节,TinyNav采用LightGlue基于注意力机制的匹配网络,有效处理重复纹理和大视角变化带来的匹配难题,显著提升了匹配准确率。

对于场景识别任务,系统使用DINO v2提取全局描述子用于回环检测,无需预训练视觉词典即可实现高效的场景识别,大幅简化了系统部署流程。在地图表示方面,TinyNav支持**3D高斯散射(3D Gaussian Splatting)**技术,提供直观的地图可视化和编辑能力,使开发者能够直接在三维地图上标注目标点并规划路径。这些先进的神经网络模型显著提升了系统在复杂环境下的鲁棒性。

2. 系统架构概览

TinyNav采用经典的感知-建图-规划(Perception-Mapping-Planning)三层架构,这种设计模式在机器人导航领域已被广泛验证。系统基于ROS2(Robot Operating System 2)构建,利用其发布-订阅机制实现模块间的松耦合通信。

2.1 整体数据流

系统的数据流动遵循以下路径。首先是传感器数据采集,Intel RealSense D435等立体相机持续输出左右目图像和IMU数据。接着感知模块处理对图像进行特征提取、立体匹配,估计相机位姿和深度信息。然后建图模块维护构建全局地图,执行回环检测和位姿图优化。随后规划模块决策基于局部地图和目标点生成可执行的运动轨迹。最后控制指令输出将规划结果转换为机器人可执行的速度命令。

图1:TinyNav三层架构与数据流。展示了从传感器输入到控制输出的完整数据流动路径。

2.2 核心模块职责

2.2.1 感知节点(Perception Node)

感知节点负责处理传感器原始数据,其主要任务体现在多个关键环节。首先是立体视觉里程计估计,该功能通过特征匹配技术计算相机在空间中的运动轨迹,为后续定位提供基础数据。其次是深度图生成,系统使用神经网络进行立体匹配,从双目图像中恢复场景的三维几何信息。第三是关键帧选择,基于运动阈值筛选关键帧,确保只保留对建图有价值的图像帧,避免冗余计算。最后是IMU-视觉融合,结合惯性测量单元数据提高位姿估计精度,特别是在快速运动或光照变化等视觉退化场景下保持稳定性。该模块是系统的基础,其输出质量直接影响后续建图和规划的效果。

2.2.2 建图节点(Map Node)

建图节点维护机器人对环境的全局认知,其核心功能体现在多个技术层面。首先是全局特征提取与匹配,系统使用DINO v2视觉Transformer模型提取场景描述子,实现高效的场景识别和回环检测。其次是局部束调整优化,通过同时优化相机位姿和3D地图点,最小化重投影误差,提升局部地图的几何一致性。第三是回环检测与闭环,当机器人重新访问已知场景时,系统能够识别并利用这一信息消除长期累积的定位误差。最后是全局路径规划,基于A*算法在已构建的地图上规划从当前位置到目标点的最优路径。该模块确保机器人能够在大范围环境中保持定位精度。

2.2.3 规划节点(Planning Node)

规划节点负责生成机器人的运动轨迹,其实现基于动态窗口法(Dynamic Window Approach, DWA),能够在满足机器人动力学约束的前提下,实时规避障碍物并向目标点移动。核心功能体现在多个处理环节。首先是局部占据栅格地图构建,使用光线投射算法将深度图转换为二维栅格表示,标记自由空间和障碍物区域。其次是ESDF距离场计算,为每个栅格计算到最近障碍物的欧几里得距离,为障碍物规避提供安全距离信息,使机器人能够保持安全裕度。第三是候选轨迹生成与评分,在动力学约束下生成多条候选轨迹,综合考虑目标朝向、障碍物距离、速度等多个因素进行评分。最后是最优轨迹选择,从候选集中选出得分最高的轨迹并输出相应的速度命令,驱动机器人执行导航任务。

3. 感知模块:视觉里程计与深度估计

感知模块是TinyNav系统的眼睛,负责从原始传感器数据中提取机器人的位姿和环境的几何信息。该模块的核心是立体视觉里程计(Stereo Visual Odometry),通过连续帧间的特征匹配和3D-2D对应关系求解相机运动。

3.1 深度学习驱动的特征提取

传统的视觉SLAM系统多采用手工设计的特征描述子,如ORBSIFT等。TinyNav则采用了基于深度学习的特征提取方案,具体使用SuperPoint网络进行关键点检测和描述子提取。

3.1.1 SuperPoint特征提取器

SuperPoint是一个自监督学习的特征提取器,其优势在于多个方面。首先是光照鲁棒性,对光照变化具有更强的适应能力。其次是运动模糊抗性,能够处理快速运动导致的图像模糊。第三是重复性高,在不同视角下能够检测到相同的特征点。最后是描述子区分度强,特征描述子具有更好的区分能力。

在TinyNav的实现中,SuperPoint模型被转换为TensorRT格式以实现高效推理。系统在Jetson Orin平台上可以达到30Hz以上的特征提取速度,满足实时导航的需求。

图2:SuperPoint特征提取效果。左侧为原始图像,右侧为检测到的512个关键点。

特征提取代码实现

class PerceptionNode(Node):
    def __init__(self, verbose_timer: bool = True):
        super().__init__("perception_node")

        # 初始化SuperPoint特征提取器(TensorRT优化版本)
        self.superpoint = SuperPointTRT()
        # 初始化LightGlue特征匹配器
        self.light_glue = LightGlueTRT()
        # 初始化立体匹配引擎
        self.stereo_engine = StereoEngineTRT()

        # 关键帧管理
        self.last_keyframe_img = None
        self.last_keyframe_features = None
        self.keyframe_poses = []

        # 相机内参(从ROS参数服务器读取)
        self.K = None
        self.baseline = None

    async def extract_features(self, image: np.ndarray):
        """异步提取图像特征

        Args:
            image: 灰度图像 (H, W)

        Returns:
            keypoints: 关键点坐标 (N, 2)
            descriptors: 特征描述子 (N, 256)
            scores: 关键点置信度 (N,)
        """
        # 使用TensorRT加速推理
        with Timer(name="SuperPoint", logger=None):
            keypoints, descriptors, scores = await self.superpoint.infer(image)

        # 过滤低置信度特征点
        mask = scores > 0.015
        keypoints = keypoints[mask]
        descriptors = descriptors[mask]
        scores = scores[mask]

        return keypoints, descriptors, scores

3.2 特征匹配与位姿估计

在获得当前帧和参考帧的特征点后,系统使用LightGlue进行特征匹配。LightGlue是一个基于注意力机制的特征匹配网络,相比传统的最近邻匹配方法,其能够更好地处理重复纹理大视角变化的场景。

3.2.1 LightGlue匹配网络

LightGlue的核心优势体现在多个方面。首先是自适应匹配,根据图像内容动态调整匹配策略。其次是上下文感知,利用全局信息辅助局部匹配。第三是高效推理,相比SuperGlue速度提升3-5倍。最后是鲁棒性强,对光照、视角变化具有更强的适应能力。

图3:LightGlue特征匹配效果。彩色连线表示匹配的特征对,系统成功匹配了156个对应点。

3.2.2 关键帧选择策略

关键帧选择策略对于视觉里程计的精度至关重要。TinyNav采用基于运动阈值的关键帧选择策略:

# 关键帧选择参数
_KEYFRAME_MIN_DISTANCE = 0.1    # 最小平移距离:0.1米
_KEYFRAME_MIN_ROTATE_DEGREE = 0.1 # 最小旋转角度:0.1度
_MIN_FEATURES = 20  # 最小特征点数量

def keyframe_check(T_i, T_j):
    """检查两个位姿之间是否满足关键帧条件

    Args:
        T_i: 上一关键帧位姿 (4, 4)
        T_j: 当前帧位姿 (4, 4)

    Returns:
        is_keyframe: 是否应该作为关键帧
    """
    # 计算相对位姿
    T_ij = se3_inv(T_i) @ T_j

    # 计算平移距离
    t_diff = np.linalg.norm(T_ij[:3, 3])

    # 计算旋转角度
    cos_theta = (np.trace(T_ij[:3, :3]) - 1) / 2
    cos_theta = np.clip(cos_theta, -1, 1)
    r_diff = np.degrees(np.arccos(cos_theta))

    # 判断是否满足关键帧条件
    return (t_diff > _KEYFRAME_MIN_DISTANCE or
            r_diff > _KEYFRAME_MIN_ROTATE_DEGREE)

这种策略确保关键帧之间有足够的基线,从而提高三角化的精度,同时避免冗余帧的处理开销。

3.3 IMU-视觉融合

TinyNav引入了IMU-视觉融合机制,显著提升了俯仰角估计的精度。系统使用GTSAM(Georgia Tech Smoothing and Mapping)库实现因子图优化,将IMU预积分约束视觉观测约束统一在一个优化框架中。

IMU预积分的实现基于GTSAM的PreintegratedCombinedMeasurements类,该类能够高效地处理IMU测量并计算预积分量。关键帧数据结构定义如下:

@dataclass
class Keyframe:
    """关键帧数据结构,融合视觉和IMU信息"""
    timestamp: float                    # 时间戳
    image: np.ndarray                   # 图像数据
    disparity: np.ndarray               # 视差图
    depth: np.ndarray                   # 深度图
    pose: np.ndarray                    # 位姿矩阵 (4x4)
    velocity: np.ndarray                # 速度向量 (3,)
    bias: gtsam.imuBias.ConstantBias   # IMU偏置估计
    preintegrated_imu: gtsam.PreintegratedCombinedMeasurements  # IMU预积分量
    latest_imu_timestamp: float         # 最新IMU时间戳
    imu_measurement_count: int = 0      # IMU测量计数

每个关键帧不仅存储图像和位姿信息,还保存了IMU的预积分结果偏置估计。这种设计使得系统能够在视觉跟踪失败时,利用IMU信息进行短时预测,提高系统的鲁棒性

图4:IMU-视觉融合的因子图结构。蓝色节点表示位姿,绿色节点表示速度和偏置,红色边表示IMU约束,蓝色边表示视觉约束。

3.4 立体深度估计

深度信息的获取是立体视觉系统的核心功能。TinyNav使用神经网络进行立体匹配,相比传统的SGBM(Semi-Global Block Matching)算法,神经网络方法在弱纹理区域光照变化场景下表现更优。

深度图生成后,系统通过相机内参矩阵将深度值转换为3D点云

def depth_to_point(kp, depth, K):
    """将2D关键点和深度值转换为3D点

    Args:
        kp: 关键点像素坐标 (u, v)
        depth: 深度值(米)
        K: 相机内参矩阵 3x3

    Returns:
        point_3d: 相机坐标系下的3D点 (X, Y, Z)
    """
    u, v = int(kp[0]), int(kp[1])
    Z = depth
    # 根据针孔相机模型反投影
    X = (u - K[0,2]) * Z / K[0,0]  # (u - cx) * Z / fx
    Y = (v - K[1,2]) * Z / K[1,1]  # (v - cy) * Z / fy
    return np.array([X, Y, Z])

这个简洁的函数实现了从像素坐标相机坐标系的转换,是后续建图和规划的基础。通过批量处理所有特征点,系统可以快速构建稠密点云用于障碍物检测。

4. 建图模块:全局定位与回环检测

建图模块负责维护机器人对环境的全局认知,其核心任务是在大范围环境中保持定位精度,并通过回环检测消除累积误差。TinyNav的建图模块采用了基于特征的SLAM方法,结合深度学习技术实现高效的场景识别和位姿优化。

4.1 全局特征提取与场景识别

传统的回环检测方法多基于词袋模型(Bag of Words),需要预先训练视觉词典。TinyNav采用了更先进的方案:使用DINO v2(Vision Transformer)提取全局图像描述子。DINO v2是Meta AI开发的自监督视觉模型,其提取的特征具有强大的语义表达能力,能够识别不同视角下的同一场景。

在TinyNav的实现中,每个关键帧都会提取一个全局描述子,用于后续的相似度计算

class MapNode(Node):
    def __init__(self):
        super().__init__("map_node")
        # 初始化DINO v2全局特征提取器
        self.dinov2 = Dinov2TRT()
        # 初始化数据库用于存储关键帧信息
        self.db = TinyNavDB()
        # 位姿图优化器
        self.pose_graph = PoseGraph()

当新的关键帧到来时,系统会计算其与历史关键帧的特征相似度。如果相似度超过阈值,则触发回环检测流程。这种基于深度学习的方法相比传统词袋模型,具有更高的召回率和更低的误匹配率

4.2 局部束调整优化

束调整(Bundle Adjustment)是视觉SLAM中的核心优化问题,其目标是同时优化相机位姿3D地图点,使得重投影误差最小化。TinyNav使用Ceres Solver实现高效的非线性优化

系统采用滑动窗口策略,只优化最近的N个关键帧,这样既保证了优化效率,又能及时修正累积误差。优化问题的数学表达式为:

minimize Σ ||π(K * T_i * X_j) - u_ij||²

其中π表示投影函数,K是相机内参,T_i是第i帧的位姿,X_j是第j个3D点,u_ij是观测到的像素坐标。

4.3 回环检测与位姿图优化

当检测到回环时,系统需要调整整个轨迹以消除累积误差。TinyNav使用位姿图优化(Pose Graph Optimization)实现全局一致性约束。位姿图是一个图结构,节点表示关键帧位姿,边表示位姿约束(来自视觉里程计或回环检测)。

位姿图优化的实现基于GTSAM库,其核心代码如下:

def solve_pose_graph(nodes, edges):
    """求解位姿图优化问题

    Args:
        nodes: 节点列表,每个节点包含初始位姿估计
        edges: 边列表,每个边包含相对位姿约束和信息矩阵

    Returns:
        优化后的节点位姿
    """
    graph = gtsam.NonlinearFactorGraph()
    initial_estimate = gtsam.Values()

    # 添加节点初始值
    for i, node in enumerate(nodes):
        initial_estimate.insert(X(i), Matrix4x4ToGtsamPose3(node.pose))

    # 添加边约束
    for edge in edges:
        noise_model = gtsam.noiseModel.Gaussian.Information(edge.information)
        factor = gtsam.BetweenFactorPose3(
            X(edge.from_id), X(edge.to_id),
            Matrix4x4ToGtsamPose3(edge.relative_pose),
            noise_model
        )
        graph.add(factor)

    # 执行优化
    optimizer = gtsam.LevenbergMarquardtOptimizer(graph, initial_estimate)
    result = optimizer.optimize()

    return result

这个函数实现了标准的位姿图优化流程,通过最小化所有边约束的误差,得到全局一致的轨迹估计

图5:位姿图优化过程。左侧为优化前的轨迹(存在累积误差),右侧为优化后的轨迹(全局一致)。

4.4 地图存储与管理

TinyNav使用键值数据库(基于Pythonshelve模块)存储地图数据,这种设计使得地图的读写操作非常高效。地图数据包括关键帧的图像、位姿、特征点、描述子等信息。

v0.2版本中,TinyNav引入了3D高斯散射(3D Gaussian Splatting)作为可选的地图表示方式。3DGS是一种新兴的场景表示方法,能够以高质量渲染场景,同时支持实时编辑。开发者可以在3DGS地图上直观地标注目标点,系统会自动规划路径。

5. 规划模块:动态窗口法与障碍物规避

规划模块是连接感知与控制的桥梁,其任务是根据当前位姿、局部地图和目标点,生成一条安全可行的运动轨迹。TinyNav采用动态窗口法(Dynamic Window Approach, DWA)实现局部路径规划,这是一种经典且高效的方法,特别适合实时性要求高的移动机器人应用。

5.1 局部占据栅格地图构建

在进行路径规划之前,系统需要构建一个局部占据栅格地图(Occupancy Grid Map),用于表示机器人周围的障碍物分布。TinyNav使用**光线投射(Ray Casting)**算法将深度图转换为占据栅格。

光线投射的核心思想是:从相机位置向每个深度像素发射一条射线,射线经过的栅格标记为自由空间,射线终点的栅格标记为占据。为了提高计算效率,TinyNav使用Numba JIT编译器优化了这一过程:

@njit(cache=True)
def run_raycasting_loopy(depth_image, T_cam_to_world, grid_shape,
                         fx, fy, cx, cy, origin, step, resolution,
                         filter_ground=False):
    """使用光线投射算法构建占据栅格地图

    Args:
        depth_image: 深度图像
        T_cam_to_world: 相机到世界坐标系的变换矩阵
        grid_shape: 栅格地图的形状 (x, y, z)
        fx, fy, cx, cy: 相机内参
        origin: 栅格地图的原点坐标
        step: 采样步长,用于降低计算量
        resolution: 栅格分辨率(米/格)
        filter_ground: 是否过滤地面点

    Returns:
        occupancy_grid: 占据栅格地图
    """
    occupancy_grid = np.zeros(grid_shape)
    depth_height, depth_width = depth_image.shape

    # 计算相机在栅格地图中的位置
    cam_orig_x = T_cam_to_world[0, 3]
    cam_orig_y = T_cam_to_world[1, 3]
    cam_orig_z = T_cam_to_world[2, 3]

    start_voxel_x = int(np.floor((cam_orig_x - origin[0]) / resolution))
    start_voxel_y = int(np.floor((cam_orig_y - origin[1]) / resolution))
    start_voxel_z = int(np.floor((cam_orig_z - origin[2]) / resolution))

    # 遍历深度图像的每个像素(按步长采样)
    for v in range(0, depth_height, step):
        for u in range(0, depth_width, step):
            d = depth_image[v, u]
            if (not np.isfinite(d)) or d <= 0:
                continue

            # 将像素坐标转换为相机坐标系
            px = (u - cx) * d / fx
            py = (v - cy) * d / fy
            pz = d

            # 可选:过滤地面点
            is_ground = py > 0
            if filter_ground and is_ground:
                continue

            # 变换到世界坐标系并标记占据
            # ... (省略具体的变换和标记代码)

    return occupancy_grid

这个函数使用Numba的JIT编译,将Python代码编译为机器码,性能接近C++实现。通过调整step参数,可以在精度和速度之间取得平衡。

图6:光线投射算法原理。从相机位置向深度像素发射射线,标记自由空间和占据空间。

5.2 ESDF地图与安全距离场

TinyNav引入了ESDF(Euclidean Signed Distance Field)地图,用于改善障碍物规避的质量。ESDF地图中的每个栅格存储的是到最近障碍物的距离,这使得机器人不仅能够避开障碍物,还能保持一个安全距离

ESDF的计算使用欧几里得距离变换(Euclidean Distance Transform),这是一个经典的图像处理算法:

from scipy.ndimage import distance_transform_edt

def compute_esdf(occupancy_grid, resolution):
    """计算欧几里得符号距离场

    Args:
        occupancy_grid: 二值占据栅格地图(0=自由,1=占据)
        resolution: 栅格分辨率(米/格)

    Returns:
        esdf: 符号距离场,正值表示到障碍物的距离
    """
    # 计算到最近障碍物的距离
    distance_map = distance_transform_edt(1 - occupancy_grid)
    # 转换为实际距离(米)
    esdf = distance_map * resolution
    return esdf

有了ESDF地图,规划器可以生成更加平滑和安全的轨迹,机器人会自然地远离障碍物,而不是紧贴障碍物边缘行驶。

图7:ESDF距离场可视化。颜色越深表示距离障碍物越近,机器人倾向于在浅色区域行驶。

5.3 动态窗口法轨迹生成

动态窗口法的核心思想是:在机器人当前速度的基础上,考虑动力学约束(最大加速度、最大速度),生成一系列候选轨迹,然后根据多个目标函数对这些轨迹进行评分,选择得分最高的轨迹执行。

TinyNav的DWA实现考虑了以下评价指标。首先是目标朝向(Heading),衡量轨迹终点朝向目标点的程度。其次是障碍物距离(Clearance),计算轨迹与障碍物的最小距离。最后是速度(Velocity),鼓励机器人以较高速度前进。

轨迹评分函数的实现如下:

def score_trajectory(trajectory, goal_position, esdf_map, weights):
    """评估候选轨迹的质量

    Args:
        trajectory: 轨迹点序列 [(x, y, theta), ...]
        goal_position: 目标点位置 (x, y)
        esdf_map: ESDF距离场地图
        weights: 各项指标的权重 (w_heading, w_clearance, w_velocity)

    Returns:
        score: 轨迹总分
    """
    # 计算目标朝向得分
    end_point = trajectory[-1]
    direction_to_goal = np.arctan2(
        goal_position[1] - end_point[1],
        goal_position[0] - end_point[0]
    )
    heading_error = abs(direction_to_goal - end_point[2])
    heading_score = 1.0 - heading_error / np.pi

    # 计算障碍物距离得分
    min_clearance = float('inf')
    for point in trajectory:
        grid_x, grid_y = world_to_grid(point[0], point[1])
        clearance = esdf_map[grid_x, grid_y]
        min_clearance = min(min_clearance, clearance)
    clearance_score = min(min_clearance / 1.0, 1.0)  # 归一化到[0,1]

    # 计算速度得分(鼓励快速移动)
    velocity = compute_trajectory_velocity(trajectory)
    velocity_score = velocity / max_velocity

    # 加权求和
    total_score = (weights[0] * heading_score +
                   weights[1] * clearance_score +
                   weights[2] * velocity_score)

    return total_score

这个评分函数综合考虑了多个因素,通过调整权重参数,可以改变机器人的行为特性。例如,增大clearance权重会使机器人更加保守,远离障碍物;增大velocity权重会使机器人更加激进,追求速度。

图8:DWA候选轨迹评分。绿色轨迹得分最高,红色轨迹因接近障碍物得分较低。

5.4 机器人运动学约束

不同类型的机器人具有不同的运动学特性。TinyNav通过配置文件定义机器人的几何参数运动约束

@dataclass
class RobotConfig:
    """机器人几何配置"""
    name: str = 'go2'
    shape: str = 'square'  # 'square' 或 'circle'
    length: float = 0.7    # 机器人长度(米)
    width: float = 0.3     # 机器人宽度(米)
    radius: float = 0.3    # 圆形机器人的半径
    camera_x: float = 0.35 # 相机相对控制中心的x偏移
    camera_y: float = 0.0  # 相机相对控制中心的y偏移
    control_x: float = 0.0 # 控制中心的x坐标
    control_y: float = 0.0 # 控制中心的y坐标
    safety_radius: float = 0.1  # 安全半径(额外的碰撞检测边界)

# Unitree GO2四足机器人配置
GO2_CONFIG = RobotConfig(
    name='go2', shape='square',
    length=0.7, width=0.3,
    camera_x=0.35, camera_y=0.0,
    control_x=0.0, control_y=0.0,
    safety_radius=0.1,
)

这种配置化的设计使得TinyNav能够轻松适配不同的机器人平台,只需修改配置参数即可。

图9:Unitree GO2机器人的几何配置。展示了相机位置、控制中心和安全半径的关系。

6. 快速上手:从零到运行

TinyNav的设计目标之一是降低使用门槛,让开发者能够快速上手。项目采用Dev Container技术,提供了开箱即用的开发环境,避免了复杂的依赖安装和环境配置过程。

6.1 环境准备

在开始之前,需要确保系统满足以下要求。在硬件要求方面,x86_64平台需要配备NVIDIA GPU的PC,推荐RTX 3060或更高;ARM平台需要NVIDIA Jetson Orin系列,需要JetPack 6.2或更高版本;立体相机方面支持Intel RealSense D435或Looper相机。在软件要求方面,需要安装DockerDocker ComposeNVIDIA Container Toolkit(用于GPU支持)、GitGit LFS(用于下载大文件)以及Visual Studio Code(推荐)和Dev Containers扩展

环境检查脚本会自动验证这些依赖:

git clone <https://github.com/UniflexAI/tinynav.git>
cd tinynav
bash scripts/check_env.sh

如果所有检查通过,会看到如下输出:

✅ Docker is installed.
✅ Docker daemon is running and accessible.
✅ NVIDIA runtime is available in Docker.
✅ Git LFS is installed.
✅ devcontainer.json patched for your x86 platform.

6.2 启动开发容器

TinyNav使用Dev Container提供一致的开发环境。在VS Code中打开项目文件夹,编辑器会自动检测到.devcontainer配置并提示重新打开容器。容器启动后,所有依赖都已预装,包括ROS2CUDATensorRT等。

首次进入容器后,需要初始化Python虚拟环境

uv venv --system-site-packages
uv sync

这个命令会创建虚拟环境并安装所有Python依赖。如果需要支持特定的机器人平台或地图表示,可以安装可选依赖

# Unitree GO2机器人支持
uv sync --extra unitree

# 3D高斯散射地图支持
uv sync --extra 3dgs

# 组合多个扩展
uv sync --extra unitree --extra 3dgs

6.3 运行示例数据集

TinyNav提供了预录制的数据集用于快速验证系统功能。运行示例的脚本会自动下载数据集、启动导航节点并打开RViz可视化界面

bash /tinynav/scripts/run_rosbag_examples.sh

这个脚本执行以下操作:

    1. 从Hugging Face下载示例数据集(约500MB)2. 启动ROS2节点:perception_node和planning_node3. 播放录制的传感器数据4. 启动RViz进行实时可视化

RViz窗口中,可以看到机器人的实时位姿局部地图规划轨迹等信息。通过2D Nav Goal工具可以交互式地设置目标点,观察系统的路径规划和执行过程。

6.4 连接真实机器人

Unitree GO2为例,连接真实机器人需要以下步骤。首先是网络配置,确保计算机与机器人在同一网段(192.168.123.x):

# 查看网络接口
ip addr

# 配置静态IP
sudo ip addr add 192.168.123.100/24 dev eno1
sudo ip link set eno1 up

# 测试连接
ping 192.168.123.161

其次是启动驱动节点,TinyNav提供了针对不同机器人平台的驱动节点

# 启动Unitree GO2驱动
python -m tinynav.core.driver_node --robot unitree_go2

最后是启动导航系统,在另一个终端启动感知和规划节点

# 启动感知节点
python -m tinynav.core.perception_node

# 启动规划节点
python -m tinynav.core.planning_node --robot-config GO2_CONFIG

系统启动后,机器人会开始接收传感器数据并进行实时定位。通过RViz设置目标点,机器人会自动规划路径并执行导航任务。

7. 结语

TinyNav是一个年轻但充满活力的项目,它用实际行动证明了 "小而美"的系统设计理念。对于想要学习机器人导航技术的开发者,TinyNav提供了一个绝佳的学习案例;对于需要快速原型开发的研究者,TinyNav提供了一个可靠的基础平台;对于追求产品化的工程师,TinyNav展示了从原型到生产的完整路径

相关推荐