机器人导航dwa(局部避障)分析

2023-05-16

前面部分引用http://blog.csdn.net/lqygame/article/details/72861439

(1)初始化:

在move_base节点中,通过类加载模块载入了BaseLocalPlanner(局部路径规划)的子类DWAPlannerROS的实例tc_,并调用其初始化函数,获取了一些初始状态信息比如机器人当前位置等,并创建了真正实现DWA算法的DWAPlanner类的实例dp_,最后设置了动态参数配置服务。dp_的构造函数做了一系列参数获取的操作,最重要的是将几种cost计算方法的实例加入一个名为critics的vector容器里。
(2)采样速度样本:
当move_base调用tc_的computeVelocityCommands方法后,tc_会调用dwaComputeVelocityCommands方法,并在其中调用dp_的findBestPath方法。findBestPath方法里调用SimpleTrajectoryGenerator类的实例generator_的initialise函数,这个函数就是主要负责速度采样的。
每个维度速度需要采样的养本数存放在vsamples_这个结构体内,vsamples_[0]是x方向样本数,vsamples_[1]是y方向样本数,vsamples_[2]是z方向样本数。首先计算各个方向的最大速度和最小速度,DWA算法只在第一步进行采样,所以最大速度为:
Max_vel=min(max_vel,vel+acc_lim*sim_period)
最小速度为:
Min_vel=max(min_vel,vel-acc_lim*sim_period)
其中max_vel,min_vel为人为设定的最大和最小速度,vel是当前速度,acc_lim是人为设定的最大加速度,sim_period是第一步的模拟时间,由人为设定的局部路径规划频率决定,默认为0.05。
当计算出各个维度的最大最小速度后,就创建三个VelocityIterator类的对象,并传入最大最小速度和样本数目,此对象的构造函数会生成同样数目的速度样本并放入samples_这个容器内。具体做法是先计算步长step_size:
step_size=(max-min)/(nums_samples-1)
max为最大速度,min为最小速度,nums_samples为样本数目。从最小速度每次多累加一次step_size即为一个速度样本,直到达到最大速度。将每个维度的速度样本取得后,再全部循环每个样本组里选择一个组合放入结构体vel_sample,最后将这些vel_sample放入sample_params_的容器里。至此,速度采样就完成了。
(3)样本评分
速度采样完成后,逐一循环对样本空间内的样本进行评分。对每一组速度调用scoreTrajectory函数计算其评分,而scoreTrajectory函数则对这一组速度调用所有critics容器里的costfunction计算每个cost从而累加算出总的cost。在计算过程中,一旦累加的cost大于当前最小的cost则抛弃这组速度。
之前说到的几种cost成本函数为下列所示:
ObstacleCostFunction
这个成本函数基于感知障碍物来评估轨迹。它或者由于轨迹通过障碍物而返回负值,或者0。
MapGridCostFunction
这个成本函数类基于轨迹离全局路径或者接近目标点有多近来评估轨迹。这个尝试利用距离预计算地图有相同距离的路径或者目标点的所有的规划,来优惠计算速度。
在 dwa_local_planner中,代价函数因为不同的目的,被多次实例化。保持轨迹接近于路径,使机器人朝局部目标前进,并且使机器人的前段点指向局部目标。代价函数是一个启发,可以带来坏的结果或者不合适的参数的失败。
OscillationCostFunction
震荡发生在X,Y,theta维度上,正/负值被连续的选择。为了阻止震荡,当机器人在任何方向移动时,与下一个循环相反的方向被标记为无效,直到机器人已经从所设置标记的位置移动而并且超过一定的距离。这个成本函数类帮助减少某些震荡,虽然这可以有效的阻止这些震荡,如果使用不合适的参数,但是有可能阻止良好的解。
PreferForwardCostFunction
考虑到好的激光扫描范围只在机器人的前面,这个成本函数类被设计在像PR2一样的机器人上。成本函数更喜欢正面向前运动,惩罚背面运用及扫射动作。在其他机器人上或者其他领域,这可能是非常不可取的行为。
(4)发布plan
通过上述几种评分机制,选取最优的一组速度样本,传递给move_base,并发布相应的local plan。move_base如果收到了可用的速度则发布给底盘,否则发布0速度,且如果寻找最优速度的时间超过了限制就会执行障碍物清理模式,state_会变为CLEARING。

move_base.cpp

controller_costmap_ros_ = new costmap_2d::Costmap2DROS("local_costmap", tf_);
blp_loader_.isClassAvailable(local_planner)
tc_ = blp_loader_.createInstance(local_planner);
tc_->initialize(blp_loader_.getName(local_planner), &tf_, controller_costmap_ros_);
tc_->setPlan(*controller_plan_)
tc_->computeVelocityCommands(cmd_vel)

dwa相关参数:
/move_base/DWAPlannerROS/acc_lim_th
/move_base/DWAPlannerROS/acc_lim_theta
/move_base/DWAPlannerROS/acc_lim_x
/move_base/DWAPlannerROS/acc_lim_y
/move_base/DWAPlannerROS/acc_limit_trans
/move_base/DWAPlannerROS/angular_sim_granularity
/move_base/DWAPlannerROS/forward_point_distance
/move_base/DWAPlannerROS/global_frame_id
/move_base/DWAPlannerROS/goal_distance_bias
/move_base/DWAPlannerROS/holonomic_robot
/move_base/DWAPlannerROS/latch_xy_goal_tolerance
/move_base/DWAPlannerROS/max_rot_vel
/move_base/DWAPlannerROS/max_scaling_factor
/move_base/DWAPlannerROS/max_trans_vel
/move_base/DWAPlannerROS/max_vel_x
/move_base/DWAPlannerROS/max_vel_y
/move_base/DWAPlannerROS/meter_scoring
/move_base/DWAPlannerROS/min_rot_vel
/move_base/DWAPlannerROS/min_trans_vel
/move_base/DWAPlannerROS/min_vel_x
/move_base/DWAPlannerROS/min_vel_y
/move_base/DWAPlannerROS/occdist_scale
/move_base/DWAPlannerROS/oscillation_reset_angle
/move_base/DWAPlannerROS/oscillation_reset_dist
/move_base/DWAPlannerROS/path_distance_bias
/move_base/DWAPlannerROS/penalize_negative_x
/move_base/DWAPlannerROS/prune_plan
/move_base/DWAPlannerROS/publish_cost_grid_pc
/move_base/DWAPlannerROS/publish_traj_pc
/move_base/DWAPlannerROS/restore_defaults
/move_base/DWAPlannerROS/rot_stopped_vel
/move_base/DWAPlannerROS/scaling_speed
/move_base/DWAPlannerROS/sim_granularity
/move_base/DWAPlannerROS/sim_time
/move_base/DWAPlannerROS/stop_time_buffer
/move_base/DWAPlannerROS/trans_stopped_vel
/move_base/DWAPlannerROS/use_dwa
/move_base/DWAPlannerROS/vth_samples
/move_base/DWAPlannerROS/vtheta_samples
/move_base/DWAPlannerROS/vx_samples
/move_base/DWAPlannerROS/vy_samples
/move_base/DWAPlannerROS/xy_goal_tolerance
/move_base/DWAPlannerROS/yaw_goal_tolerance

最佳速度的代价函数:
  DWAPlanner::DWAPlanner(std::string name, base_local_planner::LocalPlannerUtil *planner_util) :
      planner_util_(planner_util),
      obstacle_costs_(planner_util->getCostmap()),
      path_costs_(planner_util->getCostmap()),
      goal_costs_(planner_util->getCostmap(), 0.0, 0.0, true),
      goal_front_costs_(planner_util->getCostmap(), 0.0, 0.0, true),
      alignment_costs_(planner_util->getCostmap())

    // set up all the cost functions that will be applied in order
    // (any function returning negative values will abort scoring, so the order can improve performance)
    std::vector<base_local_planner::TrajectoryCostFunction*> critics;
    critics.push_back(&oscillation_costs_); // discards oscillating motions (assisgns cost -1)
    critics.push_back(&obstacle_costs_); // discards trajectories that move into obstacles
    critics.push_back(&goal_front_costs_); // prefers trajectories that make the nose go towards (local) nose goal
    critics.push_back(&alignment_costs_); // prefers trajectories that keep the robot nose on nose path
    critics.push_back(&path_costs_); // prefers trajectories on global path
    critics.push_back(&goal_costs_); // prefers trajectories that go towards (local) goal, based on wave propagation

    oscillation_costs_.resetOscillationFlags();

    bool sum_scores;
    private_nh.param("sum_scores", sum_scores, false);
    obstacle_costs_.setSumScores(sum_scores);

    obstacle_costs_.setFootprint(footprint_spec);

{
    double resolution = planner_util_->getCostmap()->getResolution();
    pdist_scale_ = config.path_distance_bias;
    // pdistscale used for both path and alignment, set  forward_point_distance to zero to discard alignment
    path_costs_.setScale(resolution * pdist_scale_ * 0.5);
    alignment_costs_.setScale(resolution * pdist_scale_ * 0.5);

    gdist_scale_ = config.goal_distance_bias;
    goal_costs_.setScale(resolution * gdist_scale_ * 0.5);
    goal_front_costs_.setScale(resolution * gdist_scale_ * 0.5);

    occdist_scale_ = config.occdist_scale;
    obstacle_costs_.setScale(resolution * occdist_scale_);

    stop_time_buffer_ = config.stop_time_buffer;
    oscillation_costs_.setOscillationResetDist(config.oscillation_reset_dist, config.oscillation_reset_angle);
    forward_point_distance_ = config.forward_point_distance;
    goal_front_costs_.setXShift(forward_point_distance_);
    alignment_costs_.setXShift(forward_point_distance_);
 
    // obstacle costs can vary due to scaling footprint feature
    obstacle_costs_.setParams(config.max_trans_vel, config.max_scaling_factor, config.scaling_speed);

}


 void DWAPlanner::updatePlanAndLocalCosts(
      tf::Stamped<tf::Pose> global_pose,
      const std::vector<geometry_msgs::PoseStamped>& new_plan) {
    global_plan_.resize(new_plan.size());
    for (unsigned int i = 0; i < new_plan.size(); ++i) {
      global_plan_[i] = new_plan[i];
    }

    // costs for going away from path
    path_costs_.setTargetPoses(global_plan_);

    // costs for not going towards the local goal as much as possible
    goal_costs_.setTargetPoses(global_plan_);

    // alignment costs
    geometry_msgs::PoseStamped goal_pose = global_plan_.back();

    Eigen::Vector3f pos(global_pose.getOrigin().getX(), global_pose.getOrigin().getY(), tf::getYaw(global_pose.getRotation()));
    double sq_dist =
        (pos[0] - goal_pose.pose.position.x) * (pos[0] - goal_pose.pose.position.x) +
        (pos[1] - goal_pose.pose.position.y) * (pos[1] - goal_pose.pose.position.y);

    // we want the robot nose to be drawn to its final position
    // (before robot turns towards goal orientation), not the end of the
    // path for the robot center. Choosing the final position after
    // turning towards goal orientation causes instability when the
    // robot needs to make a 180 degree turn at the end
    std::vector<geometry_msgs::PoseStamped> front_global_plan = global_plan_;
    double angle_to_goal = atan2(goal_pose.pose.position.y - pos[1], goal_pose.pose.position.x - pos[0]);
    front_global_plan.back().pose.position.x = front_global_plan.back().pose.position.x +
      forward_point_distance_ * cos(angle_to_goal);
    front_global_plan.back().pose.position.y = front_global_plan.back().pose.position.y + forward_point_distance_ *
      sin(angle_to_goal);

    goal_front_costs_.setTargetPoses(front_global_plan);
    
    // keeping the nose on the path
    if (sq_dist > forward_point_distance_ * forward_point_distance_ * cheat_factor_) {
      double resolution = planner_util_->getCostmap()->getResolution();
      alignment_costs_.setScale(resolution * pdist_scale_ * 0.5);
      // costs for robot being aligned with path (nose on path, not ju
      alignment_costs_.setTargetPoses(global_plan_);
    } else {
      // once we are close to goal, trying to keep the nose close to anything destabilizes behavior.
      alignment_costs_.setScale(0.0);
    }
  }


  bool SimpleScoredSamplingPlanner::findBestTrajectory(Trajectory& traj, std::vector<Trajectory>* all_explored) {
    Trajectory loop_traj;
    Trajectory best_traj;
    double loop_traj_cost, best_traj_cost = -1;
    bool gen_success;
    int count, count_valid;
    for (std::vector<TrajectoryCostFunction*>::iterator loop_critic = critics_.begin(); loop_critic != critics_.end(); ++loop_critic) {
      TrajectoryCostFunction* loop_critic_p = *loop_critic;
      if (loop_critic_p->prepare() == false) {
        ROS_WARN("A scoring function failed to prepare");
        return false;
      }
    }

    for (std::vector<TrajectorySampleGenerator*>::iterator loop_gen = gen_list_.begin(); loop_gen != gen_list_.end(); ++loop_gen) {
      count = 0;
      count_valid = 0;
      TrajectorySampleGenerator* gen_ = *loop_gen;
      while (gen_->hasMoreTrajectories()) {
        gen_success = gen_->nextTrajectory(loop_traj);//生成一条轨迹(一组点)
        if (gen_success == false) {
          // TODO use this for debugging
          continue;
        }
        loop_traj_cost = scoreTrajectory(loop_traj, best_traj_cost);//评分
        if (all_explored != NULL) {
          loop_traj.cost_ = loop_traj_cost;
          all_explored->push_back(loop_traj);
        }

        if (loop_traj_cost >= 0) {
          count_valid++;
          if (best_traj_cost < 0 || loop_traj_cost < best_traj_cost) {
            best_traj_cost = loop_traj_cost;
            best_traj = loop_traj;
          }
        }
        count++;
        if (max_samples_ > 0 && count >= max_samples_) {
          break;
        }        
      }
      if (best_traj_cost >= 0) {
        traj.xv_ = best_traj.xv_;
        traj.yv_ = best_traj.yv_;
        traj.thetav_ = best_traj.thetav_;
        traj.cost_ = best_traj_cost;
        traj.resetPoints();
        double px, py, pth;
        for (unsigned int i = 0; i < best_traj.getPointsSize(); i++) {
          best_traj.getPoint(i, px, py, pth);
          traj.addPoint(px, py, pth);
        }
      }
      ROS_DEBUG("Evaluated %d trajectories, found %d valid", count, count_valid);
      if (best_traj_cost >= 0) {
        // do not try fallback generators
        break;
      }
    }
    return best_traj_cost >= 0;
  }



ObstacleCostFunction:
    double f_cost = footprintCost(px, py, pth,
        scale, footprint_spec_,
        costmap_, world_model_);
  double footprint_cost = world_model->footprintCost(x, y, th, footprint_spec);

class WorldModel{
      double footprintCost(double x, double y, double theta, const std::vector<geometry_msgs::Point>& footprint_spec, double inscribed_radius = 0.0, double circumscribed_radius=0.0)
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

机器人导航dwa(局部避障)分析 的相关文章

  • Android实战SDK对接机智云平台(基础篇) > 6、配网界面的UI搭建 学习笔记

  • 如何保证APP与服务端通信安全

    如何保证APP与服务端通信安全
  • 奎享雕刻使用教程

    软件下载地址 提取码 xff1a g3zk 将类似于u盘似的加密狗插在电脑上 机器和软件连接 xff1a 参数配置 xff1a 实心图 xff1a 1 打开要绘制的图片 2 选择绘制方式 xff1a 笔记 页面宽 xff1a 纸张的宽 左边
  • 万用表的使用方法,焊接

    万用表的使用方法 测量电容时 xff0c 现将电容 短接放电 测量电流时 xff0c 先将电路断开 通断挡在70欧姆以下认为导通 吸锡带 引脚密集的贴片元件在焊接的过程中 xff0c 很容易造成焊锡过多导致引脚短路的现象 xff0c 使用吸
  • STM32学习教程

    STM32学习教程 硬石电子 资料下载库的区分启动模式选择NVICDMAstm32 hal库 pb3做普通ioUSART 串口通讯DMA 直接存储寄存器读取DMA USART1接发RS 485通信 洋桃电子 STM32入门100步第33步U
  • 写字机器人使用教程

    一次制作写字机器人的过程 xff08 含制作教程 xff09 arduino 写字机器人制作教程 写字机器人制作教程2 0 购买链接 资料下载地址 xff1a 智宇科技 写字机器人 光盘资料 xff08 A盘资料 xff09 解压密码 xf
  • Inter RealSenseT265测试总结

    1 光线对定位有影响 xff0c 在一定范围内 xff0c 光线越充足 xff0c 定位精度越高 xff0c 但是当光线达到一定条件之后 xff0c 光照强度就不再跟定位精度成正比了 xff1b 2 周围环境对定位有影响 xff0c 周围的
  • 论文小技巧

    文件 选项 LM3405AXMKE NOPB與LM3405AXMK NOPB LM3405AXMKX NOPB對比 激光二极管 期刊查询 在word里面插入图片时怎样才成是100 比例的 文献 封装与功率 高手支招 xff1a 教你利用裸露
  • 激光啄木鸟使用教程

    软件下载地址 1 红色方框内的按钮长按开机 2 红色方框内的按钮轻触自动对焦 3 打开手机APP选择要雕刻的素材 4 设置要雕刻区域的大小 xff0c 开始预览可以查看雕刻的位置 5 打开蓝牙 xff0c 点击连接设备 6 选择被雕刻物件的
  • STM32 HAL库

    STM32 HAL库 第三章 MDK5 软件入门bug解决关键文件介绍程序仿真User Keywords语法提示代码编辑 查看技巧 第四章 STM32F1 基础知识入门MDK 下 C 语言基础复习STM32F103 时钟系统STM32F10
  • LWIP网络-基于STM32平台

    LWIP P1无操作系统移植RAW UDP实验RAW TCP实验Webserver实验 P1无操作系统移植 MAC 43 PHY 通过符合 IEEE802 3的MII和RMII接口与外接快速以太网PHY进行通信 MII和RMII实现数据交换
  • 树莓派学习

    树莓派学习教程 系统安装数据源的更新与配置命令设定固定IP网络地址 xff1a 法一法二 给树莓派安装中文环境和中文输入法远程控制树莓派SSH方式 xff1a 通过putty软件实现 xff08 不需要屏幕 xff09 VNC方式 xff0
  • C++学习教程

    C 43 43 学习教程 C 43 43 内存分区模型数据类型循环语句for循环语句 跳转语句指针指针 数组 函数 结构体指针 内存分区模型 工具vs codeDEV C 43 43 C 43 43 内存分区模型 程序运行前 全局区和代码区
  • core dumped ?完了?

    微信公众号 xff1a linux码头 core dumped xff1a 当程序在运行过程中发生异常 xff0c 这时linux系统可以把程序出错的内存 内容存储在一个core文件中 xff0c 又叫核心转存 应用程序在运行过程汇总经常会
  • Ubuntu18.04安装网络调试助手 NetAssist

    下载地址 链接 xff1a https pan baidu com s 1DUqZBtxFh pGTsRR2kXaPA 提取码 xff1a fp32 安装步骤 1 xff09 建立依赖关系 sudo apt get install f 2
  • C语言中左移(<<)和右移(>>)的理解

    lt lt 左移 xff1a 相当于乘法 a lt lt b 61 a 2 b 举例 xff1a 1 lt lt 5 xff0c 相当于1 2 5 61 32 1 lt lt 0 xff0c 相当于1 2 0 61 1 gt gt 右移 x
  • 《Linux运维总结:firewalld防火墙使用教程》

    文章目录 一 firewalld基础知识1 1 firewalld基本介绍1 2 firewalld与iptables关系与区别1 3 firewalld默认策略1 4 firewalld配置模式1 5 firewalld配置方法1 6 f
  • ROS常用的功能包

    坐标系 坐标变换 xff08 tf xff09 tf功能包提供了一个基于ROS的分布式框架 xff0c 可以随着时间的推移计算多个坐标系的位置 3D可视化工具 xff08 rviz xff09 机器人模型的可视化 图像数据的可视化 地图数据
  • 树莓派4B+Ubuntu 18.04 LTS + 桌面desktop + ros安装@树莓派4B、Ubuntu、desktop、ros

    树莓派4B 43 Ubuntu 18 04 LTS 43 桌面desktop 43 ros安装 64 树莓派4B Ubuntu desktop ros 久违的一篇博客 xff0c 说实话CSDN的编辑器还是用不太习惯 xff0c 记录一下树
  • 云台控制协议总结(VISCA/PELCOD/PELCOP)

随机推荐

  • error: #20: identifier "TIM_TimeBaseInitTypeDef" is undefined

    如果出现多句错误 xff1a identifier 34 34 is undefined 解决问题方法一 xff1a C C 43 43 include paths 把文件路径添加进去 解决问题方法二 xff1a 在stm32f10x co
  • 使用pyqt5实现键盘(含组合键)鼠标事件响应

    使用pyqt5实现键盘 xff08 含组合键 xff09 鼠标事件响应 使用python3 6 xff0c pyqt5 xff0c 在macOS上测试有效 span class hljs keyword import span sys sp
  • 递归思想刷题总结

    核心思想 我们在调用递归函数的时候 xff0c 把递归函数当做普通函数 xff08 黑箱 xff09 来调用 xff0c 即明白该函数的输入输出是什么 xff0c 而不用管此函数内部在做什么 xff08 千万不要跳进去了 xff0c 你脑袋
  • anonymous unions are only supported in --gnu mode, or when enabled with #pragma anon_unions

    在keil工程下移植代码 xff0c 编译出现了这个问题 xff0c 字面上解决办法有 xff1a 1 打开GNU模式 option gt GNU extensions 2 在代码前加上 pragma anon union 就是代表支持匿名
  • 串口的深入理解

    1 串口是如何发送数据的 xff1f 一般说来 xff0c 串口发送数据是往数据寄存器sbuf填写数据 xff0c 一个字节一个字节的写入 xff0c 如果有串口中断 xff0c 那么发送完一个字节的数据 xff0c 就会进入串口中断一次
  • CMakeLists.txt的简单使用

    Makefile和CMakeLists的关系 环境准备 xff1a 需要安装gcc xff0c g 43 43 xff0c make sudo apt get install gcc g 43 43 sudo apt get isntall
  • .so文件的基本理解,使用。

    一 基本概念 Linux下的 so是基于Linux下的动态链接 其功能和作用类似与windows下 dll文件 代码编译 xff0c 链接 xff0c 最后生成可执行文件 xff1b 这个可执行文件就可看作是一个静态链接 xff0c 因为代
  • jz2440:QT控制LED灯点亮熄灭(11)

    1 LED灯的驱动 xff1a 首先要准备好在驱动文件 xff0c 通过insmod led ko来加载模块 xff0c 然后在QT的代码里面配合调用open xff0c write read函数来点亮 xff0c 关闭LED灯 这一步 x
  • win10下安装ubuntu双系统

    本文章记录自己在Win10系统下安装ubuntu双系统的过程 xff0c 以及注意事项 另一个不错的安装教程 1 下载系统镜像 在官网或清华镜像 xff0c 根据需要的ubuntu版本下载需要的ubuntu镜像文件 这里要注意 xff0c
  • C++ shared_ptr的reset 用法

    include lt iostream gt include lt memory gt class Tmp public Tmp int a Tmp void print a std cout lt lt 34 value 61 34 lt
  • C++ 模板类的继承

    模板类 xff1a template lt typename T gt 说白了就是向之后的内容传递参数类型 xff0c 把T当作一个数据类型传递 xff0c 而在声明一个变量的时候 xff0c 通过base lt xxxx gt pp xx
  • linuxptp源码研究

    目录 1 检查网卡是否支持相应的时间戳 2 linuxptp的目录架构 3 ptp4l的大致流程分析 4 gptp协议对应的sync follow up delay request delay response消息在代码的位置 5 slav
  • xv6---Lab3: page tables

    目录 参考资料 RISC V页表的简化图如下所示 编辑 多级页表 xv6内核页表 3 6 Process Address Space 3 7 Code Sbrk 3 8 Code Exec Print a page table A kern
  • 内存管理---分页机制

    目录 物理内存管理带来的问题 直接映射 一级页表 二级页表 参考 xff1a xff08 C语言内存七 xff09 分页机制究竟是如何实现的 xff1f Smah 博客园 物理内存管理带来的问题 比如4GB的flash 如果应用程序可直接访
  • xv6---Lab4 traps

    参考 xff1a Lab Traps 关于寄存器s0和堆栈 https pdos csail mit edu 6 828 2020 lec l riscv slides pdf RISC V assembly Q 哪些寄存器包含函数的参数
  • stm32F4 hal库之CAN通信的实现

    本文的目的是为了能够实现功能 xff0c 故写的时候比较简略 参考资料 xff1a https blog csdn net u012308586 article details 81001102 正点原子开发手册 目标 xff1a 通过ca
  • 调试sim800L模块

  • 51单片机 串口中断

    1 什么是中断 广义上的中断是指一个过程 xff0c 举个简单的例子 xff0c 打开了电脑 xff0c 你正在放音乐 xff0c 点击了暂停按钮 xff0c 于是歌停了 这就是一个很明显的中断的例子 CPU正在做自己的事情 xff08 放
  • STM32CubeMX应用 -- 定时器输入脉冲计数

    目录 参考链接 一 实现过程 二 STM32CubeMX配置示例 三 C语言示例程序 参考链接 https blog csdn net m0 37845735 article details 105395643 一 实现过程 当选择外部的同
  • 机器人导航dwa(局部避障)分析

    前面部分引用http blog csdn net lqygame article details 72861439 xff08 1 xff09 初始化 xff1a 在move base节点中 xff0c 通过类加载模块载入了BaseLoca