DWA仿真测试

2023-05-16

1 前言

        由于之前已经对相关论文进行了翻译,因此这里就不再对DWA的原理进行赘述。本文主要目的是根据相关的程序进一步强化对论文中所体现思想的理解。

2 示例1

        以下是使用python写的一个例子,其中比较核心的是把搜索空间减小到一个动态窗口的calc_dynamic_window(x, config)函数和筛选评价最高的calc_control_and_trajectory(x, dw, config, goal, ob)函数。

2.1 代码

import math
from enum import Enum

import matplotlib.pyplot as plt
import numpy as np

show_animation = True


""" Dynamic Window Approach control """
def dwa_control(x, config, goal, ob):

    dw = calc_dynamic_window(x, config)

    u, trajectory = calc_control_and_trajectory(x, dw, config, goal, ob)

    return u, trajectory

""" 机器人的类型 """
class RobotType(Enum):
    circle = 0
    rectangle = 1

""" 配置参数 """
class Config:

    def __init__(self):
        # robot parameter
        self.max_speed = 1.0  # [m/s]
        self.min_speed = -0.5  # [m/s]
        self.max_yaw_rate = 40.0 * math.pi / 180.0  # [rad/s]
        self.max_accel = 0.2  # [m/ss]
        self.max_delta_yaw_rate = 40.0 * math.pi / 180.0  # [rad/ss]
        self.v_resolution = 0.01  # [m/s]
        self.yaw_rate_resolution = 0.1 * math.pi / 180.0  # [rad/s]
        self.dt = 0.1  # [s] Time tick for motion prediction
        self.predict_time = 3.0  # [s]
        self.to_goal_cost_gain = 0.15
        self.speed_cost_gain = 1.0
        self.obstacle_cost_gain = 1.0
        self.robot_stuck_flag_cons = 0.001  # constant to prevent robot stucked
        self.robot_type = RobotType.circle

        # if robot_type == RobotType.circle
        # Also used to check if goal is reached in both types
        self.robot_radius = 1.0  # [m] for collision check

        # if robot_type == RobotType.rectangle
        self.robot_width = 0.5  # [m] for collision check
        self.robot_length = 1.2  # [m] for collision check
        # obstacles [x(m) y(m), ....]
        self.ob = np.array([[-1, -1],
                            [0, 2],
                            [4.0, 2.0],
                            [5.0, 4.0],
                            [5.0, 5.0],
                            [5.0, 6.0],
                            [5.0, 9.0],
                            [8.0, 9.0],
                            [7.0, 9.0],
                            [8.0, 10.0],
                            [9.0, 11.0],
                            [12.0, 13.0],
                            [12.0, 12.0],
                            [15.0, 15.0],
                            [13.0, 13.0]
                            ])

    @property
    def robot_type(self):
        return self._robot_type

    @robot_type.setter
    def robot_type(self, value):
        if not isinstance(value, RobotType):
            raise TypeError("robot_type must be an instance of RobotType")
        self._robot_type = value


config = Config()

""" 二轮差分底盘的运动学模型 """
def motion(x, u, dt):

    x[2] += u[1] * dt
    x[0] += u[0] * math.cos(x[2]) * dt
    x[1] += u[0] * math.sin(x[2]) * dt
    x[3] = u[0]
    x[4] = u[1]

    return x

""" 基于当前状态计算动态窗口 """
def calc_dynamic_window(x, config):

    # Dynamic window from robot specification
    Vs = [config.min_speed, config.max_speed,
          -config.max_yaw_rate, config.max_yaw_rate]

    # Dynamic window from motion model
    Vd = [x[3] - config.max_accel * config.dt,
          x[3] + config.max_accel * config.dt,
          x[4] - config.max_delta_yaw_rate * config.dt,
          x[4] + config.max_delta_yaw_rate * config.dt]

    #  [v_min, v_max, yaw_rate_min, yaw_rate_max]
    dw = [max(Vs[0], Vd[0]), min(Vs[1], Vd[1]),
          max(Vs[2], Vd[2]), min(Vs[3], Vd[3])]

    return dw

""" 根据输入预测运动轨迹 """
def predict_trajectory(x_init, v, y, config):

    x = np.array(x_init)
    trajectory = np.array(x)
    time = 0
    while time <= config.predict_time:
        x = motion(x, [v, y], config.dt)
        trajectory = np.vstack((trajectory, x))
        time += config.dt

    return trajectory

""" 对动态窗口内的轨迹进行评价进而获取最优的控制速度 """
def calc_control_and_trajectory(x, dw, config, goal, ob):

    x_init = x[:]
    min_cost = float("inf")
    best_u = [0.0, 0.0]
    best_trajectory = np.array([x])

    # evaluate all trajectory with sampled input in dynamic window
    for v in np.arange(dw[0], dw[1], config.v_resolution):
        for y in np.arange(dw[2], dw[3], config.yaw_rate_resolution):

            trajectory = predict_trajectory(x_init, v, y, config)
            
            # 代价计算
            to_goal_cost = config.to_goal_cost_gain * calc_to_goal_cost(trajectory, goal)
            speed_cost = config.speed_cost_gain * (config.max_speed - trajectory[-1, 3])
            ob_cost = config.obstacle_cost_gain * calc_obstacle_cost(trajectory, ob, config)

            final_cost = to_goal_cost + speed_cost + ob_cost

            # search minimum trajectory
            if min_cost >= final_cost:
                min_cost = final_cost
                best_u = [v, y]
                best_trajectory = trajectory
                if abs(best_u[0]) < config.robot_stuck_flag_cons \
                        and abs(x[3]) < config.robot_stuck_flag_cons:
                    # to ensure the robot do not get stuck in
                    # best v=0 m/s (in front of an obstacle) and
                    # best omega=0 rad/s (heading to the goal with
                    # angle difference of 0)
                    best_u[1] = -config.max_delta_yaw_rate
    return best_u, best_trajectory

""" 与障碍物的间隙代价 """
def calc_obstacle_cost(trajectory, ob, config):
    """
    calc obstacle cost inf: collision
    """
    ox = ob[:, 0]
    oy = ob[:, 1]
    dx = trajectory[:, 0] - ox[:, None]
    dy = trajectory[:, 1] - oy[:, None]
    r = np.hypot(dx, dy)
    
    """ 碰撞检测 """
    if config.robot_type == RobotType.rectangle:
        yaw = trajectory[:, 2]
        rot = np.array([[np.cos(yaw), -np.sin(yaw)], [np.sin(yaw), np.cos(yaw)]]) #旋转矩阵
        rot = np.transpose(rot, [2, 0, 1])
        local_ob = ob[:, None] - trajectory[:, 0:2]
        local_ob = local_ob.reshape(-1, local_ob.shape[-1])
        local_ob = np.array([local_ob @ x for x in rot]) #矩阵乘法
        local_ob = local_ob.reshape(-1, local_ob.shape[-1])
        
        upper_check = local_ob[:, 0] <= config.robot_length / 2
        right_check = local_ob[:, 1] <= config.robot_width / 2
        bottom_check = local_ob[:, 0] >= -config.robot_length / 2
        left_check = local_ob[:, 1] >= -config.robot_width / 2
        
        if (np.logical_and(np.logical_and(upper_check, right_check),
                           np.logical_and(bottom_check, left_check))).any():
            return float("Inf")
    elif config.robot_type == RobotType.circle:
        if np.array(r <= config.robot_radius).any():
            return float("Inf")

    min_r = np.min(r)
    return 1.0 / min_r  # OK

""" heading target的代价 """
def calc_to_goal_cost(trajectory, goal):
    """
        calc to goal cost with angle difference
    """

    dx = goal[0] - trajectory[-1, 0]
    dy = goal[1] - trajectory[-1, 1]
    error_angle = math.atan2(dy, dx)
    cost_angle = error_angle - trajectory[-1, 2]
    cost = abs(math.atan2(math.sin(cost_angle), math.cos(cost_angle)))

    return cost

""" 绘制箭头 """
def plot_arrow(x, y, yaw, length=0.5, width=0.1):  # pragma: no cover
    plt.arrow(x, y, length * math.cos(yaw), length * math.sin(yaw),
              head_length=width, head_width=width)
    plt.plot(x, y)

""" 绘制机器人 """
def plot_robot(x, y, yaw, config):  # pragma: no cover
    if config.robot_type == RobotType.rectangle:
        outline = np.array([[-config.robot_length / 2, config.robot_length / 2,
                             (config.robot_length / 2), -config.robot_length / 2,
                             -config.robot_length / 2],
                            [config.robot_width / 2, config.robot_width / 2,
                             - config.robot_width / 2, -config.robot_width / 2,
                             config.robot_width / 2]])
        Rot1 = np.array([[math.cos(yaw), math.sin(yaw)],
                         [-math.sin(yaw), math.cos(yaw)]])
        outline = (outline.T.dot(Rot1)).T
        outline[0, :] += x
        outline[1, :] += y
        plt.plot(np.array(outline[0, :]).flatten(),
                 np.array(outline[1, :]).flatten(), "-k")
    elif config.robot_type == RobotType.circle:
        circle = plt.Circle((x, y), config.robot_radius, color="b")
        plt.gcf().gca().add_artist(circle)
        out_x, out_y = (np.array([x, y]) +
                        np.array([np.cos(yaw), np.sin(yaw)]) * config.robot_radius)
        plt.plot([x, out_x], [y, out_y], "-k")


def main(gx=10.0, gy=10.0, robot_type=RobotType.circle):
    print(__file__ + " start!!")
    # initial state [x(m), y(m), yaw(rad), v(m/s), omega(rad/s)]
    x = np.array([0.0, 0.0, math.pi / 8.0, 0.0, 0.0])
    # goal position [x(m), y(m)]
    goal = np.array([gx, gy])

    # input [forward speed, yaw_rate]

    config.robot_type = robot_type
    trajectory = np.array(x)
    ob = config.ob
    while True:
        u, predicted_trajectory = dwa_control(x, config, goal, ob)
        x = motion(x, u, config.dt)  # simulate robot
        trajectory = np.vstack((trajectory, x))  # store state history

        if show_animation:
            plt.cla()
            # for stopping simulation with the esc key.
            plt.gcf().canvas.mpl_connect(
                'key_release_event',
                lambda event: [exit(0) if event.key == 'escape' else None])
            plt.plot(predicted_trajectory[:, 0], predicted_trajectory[:, 1], "-g")
            plt.plot(x[0], x[1], "xr")
            plt.plot(goal[0], goal[1], "xb")
            plt.plot(ob[:, 0], ob[:, 1], "ok")
            plot_robot(x[0], x[1], x[2], config)
            plot_arrow(x[0], x[1], x[2])
            plt.axis("equal")
            plt.grid(True)
            plt.pause(0.0001)

        # check reaching goal
        dist_to_goal = math.hypot(x[0] - goal[0], x[1] - goal[1])
        if dist_to_goal <= config.robot_radius:
            print("Goal!!")
            break

    print("Done")
    if show_animation:
        plt.plot(trajectory[:, 0], trajectory[:, 1], "-r")
        plt.pause(0.0001)

    plt.show()


if __name__ == '__main__':
    main(robot_type=RobotType.rectangle)
    # main(robot_type=RobotType.circle)

2.2 测试结果

DWA仿真测试结果
DWA仿真测试结果

3 示例2

        在示例2中,我们将测试在ROS中封装好的DWA算法(A*/Dijstra+AMCL+DWA)。

3.1 准备

sudo apt install ros-melodic-turtlebot3* 
sudo apt install ros-melodic-gmapping
sudo apt install ros-melodic-navigation

3.2 建图

3.2.1 启动ROS

roscore

 3.2.2 启动仿真环境

export TURTLEBOT3_MODEL=burger
roslaunch turtlebot3_gazebo turtlebot3_world.launch

 3.2.3 启动键盘控制

export TURTLEBOT3_MODEL=burger
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch

 3.2.4 启动SLAM算法

export TURTLEBOT3_MODEL=burger
roslaunch turtlebot3_slam turtlebot3_slam.launch slam_methods:=gmapping

 3.2.5 建图和保存

rosrun map_server map_saver -f ~/map
地图
地图的相关参数

3.3 定位和导航

3.3.1 启动仿真环境

export TURTLEBOT3_MODEL=burger
roslaunch turtlebot3_gazebo turtlebot3_world.launch

3.3.2 启动导航程序

export TURTLEBOT3_MODEL=burger
roslaunch turtlebot3_navigation turtlebot3_navigation.launch map_file:=$HOME/map.yaml

3.2.3 launch文件分析

move_base.launch默认的局部路径规划算法是DWA,默认的定位算法是AMCL。

3.2.4 测试结果

DWA仿真测试结果

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

DWA仿真测试 的相关文章

  • 用IO口模拟串口(外部中断+定时器)--附程序附测试结果

    给大家分享一下我用IO口模拟串口的一种方法 xff0c 经测试使用这种方法发送能支持115200波特率 xff0c 接收9600波特率测试没问题 xff0c 接收波特率能否提高受制于用户应用场景是否能允许微妙级别的频繁中断了 xff0c 我
  • gazebo和moveit联合机械臂运动规划仿真(包含realsense视觉点云)

    1 gazebo仿真环境搭建 最终的场景 xff1a 使用的机械臂 xff1a AR3工业六轴机械臂 系统环境 xff1a ubuntu18 43 ros melodic 注 xff1a 机械臂description包在github上下载的
  • 串口接收中断+空闲中断实现多个数据帧接收与处理

    在一些应用场合中 xff0c 要求串口接收的数据不能丢同时又方便帧解析 xff0c 我之前的做法是定义一个二维数组data n m m的大小要大于最大帧长度 xff0c n用来指定帧缓存个数 xff0c 每次接收到一帧数据二维数组下标n加1
  • 使用STM32L4系列SPI字节收发异常原因查找

    使用STM32F1 F4 xff0c L1等系列MCU的SPI时 xff0c 不用hal库自带的收发函数时我们会用下面这种收发函数 xff1a 收发一个字节 uint8 t SPI Rw Byte uint8 t data while HA
  • Qt学习总结之QMessageBox

    QMessageBox主要用来通知用户或者请求用户提问和接收应答一个模态对话框 一 对话框的构成 图标是有标准图标的 xff0c 可以直接调用 我们声明的消息框 xff0c 初始状态都是模态的 阻塞程序 xff0c 这里就不演示了 xff0
  • 嵌入式MCU工程师毕业1年,接下来要学的东西有:

    刚毕业 nbsp 1 nbsp 年多了 接下来感觉有好多东西要学习 一 单片机方面的 比如 COSii和 COSiii 还有FreeRTOS等微型操作系统 除了操作系统之外 还要学习诸如emwin界面设计 还想搞一下Wifi 以太网 蓝牙B
  • RT-THREAD 线程同步与通讯:信号量、互斥量、事件、邮箱、队列、信号

    线程同步包括 xff1a 信号量 互斥量 事件 线程通讯包括 xff1a 邮箱 队列 信号 rt thread源文件说明 xff1a ipc c xff1a 信号量 xff08 sem xff09 互斥信号 xff08 mutex xff0
  • easyflash 教程

    可以看easyflash下的docs文档 xff0c 万一你们手头没有文档呢 这里我就直接黏贴了 API 说明文档 xff1a docs zh api md 通用移植文档 xff1a docs zh port md EasyFlash AP
  • 微秒(us)延时 程序

    微秒级的延时最好用systick 1 来计算 使用方法3 xff08 wait loop index xff09 时间变动会比较大 函数10us100us500us900usus delay111 2101 2501 3901 2us de
  • 发送一个字节数据要花多少时间,串口每秒可以发送多少数据

    以波特率250000为力 1s 250 000 61 4us 不是很严谨的以下图反推 xff0c 一个bit的时间正好就是4usec 波特率的单位应该就是比特每秒bit s bsp不好说明到底是bit 还是 byte 每个字节包含11个bi
  • lwip组播实现和原理-STM32F407

    实现 在lwipopts h中定义LWIP IGMP define LWIP IGMP 1LWIP初始化添加进入组播代码 span class token class name err t span err span class token
  • RTT WK2412 spi-uart

    1 添加软件包 xff0c 打开硬件 2 代码里根据硬件配置spi span class token macro property span class token directive hash span span class token
  • gazebo导入sdf模型

    模型文件 模型文件结构 xff1a simple car model config model sdf model config span class token operator lt span span class token oper

随机推荐

  • MOS管的<控制电路>与<防反接电路>

    为了方便记忆 xff0c 我不管D与S xff0c 只说MOS管中的二极管方向 另外G是控制端 这是一篇只管结果的文章 xff0c 大家只要记住就行 懂原理vs记结果 懂原理以分析一切现象 xff0c 但每次使用都要分析一次 xff1b 记
  • rt-thread studio 开启easyflash(env)

    文章目录 前言一 启用外部norflash补充说明 前言 提示 xff1a 这里可以添加本文要记录的大概内容 xff1a 环境 xff1a Art pi开发板 bsp版本1 2 1 RT Thread 4 0 3 否则添加不了fal软件包
  • 常见开源物联网平台

    下面是我用过的 JetLink 重庆 ThingsPanel 国内 ThingsBoard 国外
  • 串口工具 和 终端工具的区别 -个人猜测

    总体来说 xff0c 都是人机交互的工具 xff0c 和图形控制软件并列 可以叫命令行工具 xff1f 串口工具 显示 输入分屏 xff1a 接收和发送分开 xff0c 输入输出相互独立 输入是文本框 xff0c 点击发送时才发送 记录lo
  • RT-Thread 添加设备初始化的方式-- INIT_BOARD_EXPORT(fn)

    代码用的是rtthread simulator v0 1 0 最开始不知道rt thread在哪里给硬件初始化 xff0c 或者在哪里添加新硬件的初始化函数 例如要添加GPIO的初始化 xff0c 和操作 1 关键的就是INIT BOARD
  • Visual Studio c#生成exe可执行文件

    生成exe可执行文件方式 1 调试完毕 xff0c 确认程序无误后 xff1a 生成 生成解决方案 2 程序所在文件夹 文件名Inverter Ver0102 2019 09 20 debug Inverter bin x64 Debug
  • 在emwin中,调用GUI_Delay()函数,程序卡死,黑屏

    没有OS TimeMS 43 1 可以在systick里或者定时器里 定时 43 1
  • STM32 堆栈大小的设置及分析

    一 通过map文件了解堆栈分配 STM32 MDK5 避免堆栈溢出 环境 xff1a STM32F103C8T6 MDK5 在最近的一个项目的开发中 xff0c 每当调用到一个函数 xff0c 程序就直接跑飞 debug跟进去看不出什么逻辑
  • C# VS2017中Windows窗体更改图标

    一 图片准备 1 需要 ICO格式的文件 2 矢量图下载可在阿里巴巴的矢量图库中下载 xff08 https www iconfont cn xff09 3 下载PNF文件的图片后需转成 ICO格式 xff08 https www uupo
  • 关于RS485的DMA发送,以及EN使能脚的自动切换

    一 电路设计 1 低成本非隔离 xff1a 3 3v系统同样 xff0c 将5V改为3 3即可 同时采用TX连接三极管 xff0c 实现三极管驱动RS485芯片的EN使能脚 xff0c 从而省下一个IO口控制 隔离只需要将两个信号线用光耦隔
  • 百度2014校园招聘笔试题(武汉站 9.28)

    一 简答题 xff08 本题共30分 xff09 动态链接库与静态链接库分别有什么优缺点 xff1f xff08 10分 xff09 轮训任务调度和抢占式任务调度有什么区别 xff1f xff08 10分 xff09 请列出数据库中常用的锁
  • c语言栈溢出的原因及解决办法_STM32编程:是时候深入理解栈了

    导读 从这篇文章开始 xff0c 将会不定期更新关于嵌入式C语言编程相关的个人认为比较重要的知识点 xff0c 或者踩过的坑 为什么要深入理解栈 xff1f 做C语言开发如果栈设置不合理或者使用不对 xff0c 栈就会溢出 xff0c 溢出
  • 时钟芯片DS1302异常

    异常现象 xff1a DS1302时间不走时 xff0c 秒位是一个大于60的错误数字 分析原因 xff1a DS1302受到干扰 xff0c 软件仿真发现DS1302的秒寄存器最高位被置为1 xff08 为时钟停止位 xff09 解决方法
  • STM32 下载调试口(JTAG+SWD)禁用及作为普通IO口

    1 RCC APB2PeriphClockCmd RCC APB2Periph AFIO ENABLE 开启AFIO时钟 2 GPIO PinRemapConfig GPIO Remap SWJ JTAGDisable ENABLE 改变指
  • 波特率的解析及转换为字节传输速率

    波特率115200 xff1d 115200 位 秒 以最普通的串口 xff08 起始位 43 8位数据 43 停止位 xff09 为例 xff1a 除以 10 xff0c 得到的是每秒字节数 xff1a 波特率115200 xff1d 1
  • 如何判断CAN总线空闲以及帧间隙,计算传输速率

    一 如何判断总线忙还是空闲呢 进入 正常模式之前 xff0c bxCAN 必须始终在 CAN 总线上实现 同步 为了进行同步 xff0c bxCAN 将等待 CAN 总线空闲 xff08 即 xff0c 已监测到CANRX 上的 11 个隐
  • STM32 DMA传输出错的防错机制

    一 DMA 中断 对于每个 DMA 数据流 xff0c 可在发生以下事件时产生中断 xff1a 达到半传输 xff08 每次传输都会触发 xff0c 属于正常触发 xff09 传输完成 传输错误 FIFO 错误 xff08 上溢 下溢或 F
  • IAR的View视图菜单中Watch、 Live Watch、 Quick Watch、 Auto、 Locals、 Statics这几个子菜单的含义和区别

    一 简述IAR的View视图菜单 View这个菜单的意思就是打开 xff08 已关闭的 xff09 视图窗口 xff0c 比如我们的工作空间窗口不见了 xff0c 就可以通过该菜单打开 不瞒大家 xff0c 以前我初学软件的时候 xff0c
  • DWA论文翻译

    摘要 本文介绍了一种能够令机器人进行自主避障的动态窗口法 xff08 dynamic window approach xff0c DWA xff09 该方法是从机器人的运动动力学直接推导出的 xff0c 因此特别适合在高速运动的机器人 与以
  • DWA仿真测试

    1 前言 由于之前已经对相关论文进行了翻译 xff0c 因此这里就不再对DWA的原理进行赘述 本文主要目的是根据相关的程序进一步强化对论文中所体现思想的理解 2 示例1 以下是使用python写的一个例子 xff0c 其中比较核心的是把搜索