ROS联合webots实战案例(六)实现cartographer建图与导航[1]
实现cartographer建图与导航[1](2021.01.25)
为了能和读者进一步讨论问题,建立了一个微信群,方便给大家解答问题,也可以一起讨论问题。
加群链接
注意:
- 再学习本系列教程时,应该已经安装过ROS了并且需要有一些ROS的基本知识
webots版本:2020b rev1
ros版本:melodic
1.前言
花了将近3-4天时间完成了Cartographer在ROS1和Webots之间的移植。baidu+google了很多资料,发现各大仿真软件中都有前人移植过的例子,但是在ROS1和Webots之间没有先例,所以只能笔者自己移植。
在这几天也花了点时间看了2016年谷歌发表的Cartographer论文《Real-Time Loop Closure in 2D LIDAR SLAM》,下面简单介绍一下这个算法。
2.cartographer 算法
2016年谷歌推出了Cartographer。当时,谷歌制作了一个背包,将传感器安装在背包上,使用Cartographer算法由实验人员在室内行走,便可以同时绘测室内的二维地图或三维地图。一开始并不是在ROS系统中使用,经过开发者移植后创建了一个名为cartographer_ros 可在 ROS 系统中使用的功能包。cartographer 包是该理论的底层使用,负责通过整合多种传感器的数据来搭建地图,cartographer_ros是上层应用,负责获取符合ROS通信机制的传感器数据转换成底层使用的格式来处理。
有关Cartographer算法的一些细节还是去看谷歌发表的论文比较好,也有大佬翻译好的:Google Cartographer 《Real-Time Loop Closure in 2D LIDAR SLAM》翻译 (中英对照)
2.1 Cartographer 算法原理
该算法可以通过激光测距仪等传感器测量的数据生成分辨率为5cm的实时栅格地图。Cartographer采用基于图优化方法的SLAM理论框架,分为前端和后端两部分:前端主要负责Scan-to-Submap和回环检测,将处理后的激光雷达数据与子图进行匹配,同时当生成一个子图且没有新的数据帧插入的时候会进行局部回环检测。子图创建完成后,如果找到了与当前估计位姿最佳的匹配结果,则将其添加到回环约束中。后端主要负责对位姿估计进行优化,采用分支定界和预先计算的网格来实现全局闭环检测。
2.2 什么是图优化SLAM算法
基于图优化SLAM算法与基于滤波方法的思路完全不同,它不再只修正机器人当前时刻的位姿,使当前时刻的位姿尽可能的准确,还通过回环检测等来优化之前时刻的机器人位姿。图优化SLAM算法的基本思路是利用保存的所有传感器测量信息以及它们之间的空间约束关系,通过各个位姿间的约束关系来对移动机器人的运动轨迹及地图进行估计。这种方法用节点来代表移动机器人的位姿,而图中节点之间的边代表位姿间的空间约束关系,所得到的图被称为位姿图。在完成位姿图的构造后,通过对位姿序列进行调整,使其能够最优地满足边所表示的约束关系,优化后的结果即为机器人的运动轨迹及地图。
2.安装Cartographer
好了,理论的东西不讲太多,直接开始安装。
在之前我就写过一篇有关安装Cartographer,并且成功测试过的博客,主要安装测试过程都在这篇博客上面:Ubuntu 18.04 安装cartographer
3.在自己的机器人上使用Cartographer
我想大家在第二节已经能够成功安装cartographer包了,仿真数据跑成功后,就要用自己的机器人跑算法了。一般来说,跑仿真数据或者跑demo很容易,只要照着教程一步一步来,基本都能成功建图,但是跑自己的机器人就会因为各种问题导致崩溃啦~~~不过大家不用怕,跟着笔者一定能在webots下跑通Cartographer。
3.1 修改launch文件
因为我们的机器人是两轮差动式的,所以看了一下只有cartographer_ros/launch/demo_revo_lds.launch
这个启动文件符合。
官方的demo_revo_lds.launch文件如下:
<launch><param name="/use_sim_time" value="true" /><!-- 因为cartographer使用的是lua作为配置文件,而且我们是以双轮差速型小车作为基础的,所以使用revo_lds.lua --><node name="cartographer_node" pkg="cartographer_ros"type="cartographer_node" args="-configuration_directory $(find cartographer_ros)/configuration_files-configuration_basename revo_lds.lua"output="screen"><!-- 将from=“scan” to后面的内容换成自己激光雷达发布的激光topic --><remap from="scan" to="/volcano/Sick_LMS_291/laser_scan/layer0" /></node><!-- 这个包是用来建图的 --><node name="cartographer_occupancy_grid_node" pkg="cartographer_ros"type="cartographer_occupancy_grid_node" args="-resolution 0.05" /><node name="rviz" pkg="rviz" type="rviz" required="true"args="-d $(find cartographer_ros)/configuration_files/demo_2d.rviz" /><!-- 为了跑自己的机器人才注释的 --><!-- <node name="playbag" pkg="rosbag" type="play"args="- -clock $(arg bag_filename)" /> -->
</launch>
在这里我们需要修改两个地方:
1.注释到最后一个playbag node
2.将from=“scan” to后面的内容换成自己激光雷达发布的激光topic
3.1.1由于use_sim_time需要的topic
一般来说当我们跑.bag
文件时需要将/use_sim_time
改为true
,则不跑时应该为false
,但是当我们仿真时只需要给它一个/clock
话题来同步时间即可解决问题。
方法很简单,我们可以在robot_broadcaster.cpp
中更改:
#include <rosgraph_msgs/Clock.h>
ros::Publisher time = n->advertise<rosgraph_msgs::Clock>("/clock",10);//订阅/clock话题
while (ros::ok()) {if (!timeStepClient.call(timeStepSrv) || !timeStepSrv.response.success) {ROS_ERROR("Failed to call service time_step for next step.");break;}rosgraph_msgs::Clock clock;clock.clock = ros::Time::now();time.publish(clock);//实时发布rosgraph_msgs::Clock信息ros::spinOnce();
}
修改好,编译一下即可。
不过不要着急,我们还有很多前期步骤没有弄好。
3.2修改lua配置文件
launch文件配置好了,那接下来看看所需要的lua配置文件,文件地址cartographer_ros/cartographer_ros/configuration_files/revo_lds.lua
:
这些参数的解释可以看官方发布的教程:Lua configuration reference documentation
include "map_builder.lua"
include "trajectory_builder.lua"options = {map_builder = MAP_BUILDER,trajectory_builder = TRAJECTORY_BUILDER,map_frame = "map",tracking_frame = "horizontal_laser_link",published_frame = "horizontal_laser_link",odom_frame = "odom",provide_odom_frame = true,publish_frame_projected_to_2d = false,use_pose_extrapolator = true,use_odometry = false,use_nav_sat = false,use_landmarks = false,num_laser_scans = 1,num_multi_echo_laser_scans = 0,num_subdivisions_per_laser_scan = 1,num_point_clouds = 0,lookup_transform_timeout_sec = 0.2,submap_publish_period_sec = 0.3,pose_publish_period_sec = 5e-3,trajectory_publish_period_sec = 30e-3,rangefinder_sampling_ratio = 1.,odometry_sampling_ratio = 1.,fixed_frame_pose_sampling_ratio = 1.,imu_sampling_ratio = 1.,landmarks_sampling_ratio = 1.,
}MAP_BUILDER.use_trajectory_builder_2d = trueTRAJECTORY_BUILDER_2D.submaps.num_range_data = 35
TRAJECTORY_BUILDER_2D.min_range = 0.3
TRAJECTORY_BUILDER_2D.max_range = 8.
TRAJECTORY_BUILDER_2D.missing_data_ray_length = 1.
TRAJECTORY_BUILDER_2D.use_imu_data = false
TRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching = true
TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.linear_search_window = 0.1
TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.translation_delta_cost_weight = 10.
TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.rotation_delta_cost_weight = 1e-1POSE_GRAPH.optimization_problem.huber_scale = 1e2
POSE_GRAPH.optimize_every_n_nodes = 35
POSE_GRAPH.constraint_builder.min_score = 0.65return options
因为下面要修改的东西还是比较多的,为了不耽误大家阅读的时间,这次我就只提供以下这两种方式吧,其实还有更多优化的方式,
3.2.1 只使用激光雷达数据
当我们只使用激光雷达时主要修改:
tracking_frame = "horizontal_laser_link",
published_frame = "horizontal_laser_link",
odom_frame = "odom",
我们需要查一下我们的tf_tree才能知道我们要怎么改,执行操作如下:
$ roslaunch webots_demo webots.launch
$ rosrun webots_demo robot_broadcaster
$ rosrun rqt_tf_tree rqt_tf_tree
可以看到:
从上图中我们可以看到更改方案如下:
tracking_frame = "base_link",
published_frame = "base_link",
odom_frame = "odom",
3.2.2 使用激光雷达数据+里程计数据
改变以下数据:
tracking_frame = "base_link",
published_frame = "odom",
odom_frame = "odom",
provide_odom_frame = false, --闭环
use_odometry = true,
3.3 测试
3.3.1 只使用激光雷达数据
当我们修改万3.2.1所示的内容后,我们可以尝试测试一下效果如何。
$ roslaunch webots_demo webots.launch
$ rosrun webots_demo robot_broadcaster
$ rosrun webots_demo velocity_keyboard
$ roslaunch cartographer_ros demo_revo_lds.launch
效果所示:
可以看到,效果不是很理想,base_link位姿非常不稳定,甚至还会闪现!!
不过大家不要怕,经过几天的摸索,也找到一些解决方法:
1.将激光雷达的位置移动到机器人中心位置。
2.我们需要更换机器人的移动方式,目前的移动方式不适合利用cartographer建图,在odom中会产生很大的累计误差。
说干就干:
我们直接将本来直接控制机器人的移动方式改掉,利用线速度和角速度来控制机器人的移动。
可以在原来的velocity_keyboard上直接改,也可以重新建一个cpp文件,这个随便大家。
直接附上代码:
#include <signal.h>
#include <std_msgs/String.h>
#include "ros/ros.h"
#include <locale.h>
#include <nav_msgs/Odometry.h>
#include <webots_ros/set_float.h>
#include <webots_ros/set_int.h>
#include <webots_ros/Int32Stamped.h>using namespace std;#define TIME_STEP 32 //时钟
#define NMOTORS 2 //电机数量
#define MAX_SPEED 2.0 //电机最大速度ros::NodeHandle *n;static int controllerCount;
static std::vector<std::string> controllerList; ros::ServiceClient timeStepClient; //时钟通讯客户端
webots_ros::set_int timeStepSrv; //时钟服务数据ros::ServiceClient set_velocity_client;
webots_ros::set_float set_velocity_srv;ros::ServiceClient set_position_client;
webots_ros::set_float set_position_srv; ros::Publisher pub_speed;double speeds[NMOTORS]={0.0,0.0};// 四电机速度值 0~100
float linear_temp=0, angular_temp=0; //暂存的线速度和角速度
// 匹配电机名
static const char *motorNames[NMOTORS] ={"left_motor", "right_motor"};/*******************************************************
* Function name :updateSpeed
* Description :将速度请求以set_float的形式发送给set_velocity_srv
* Parameter :无
* Return :无
**********************************************************/
void updateSpeed() { nav_msgs::Odometry speed_data;//两轮之间的距离float L = 0.6;speeds[0] = 10.0*(2.0*linear_temp - L*angular_temp)/2.0;speeds[1] = 10.0*(2.0*linear_temp + L*angular_temp)/2.0;for (int i = 0; i < NMOTORS; ++i) {// 更新速度set_velocity_client = n->serviceClient<webots_ros::set_float>(string("/volcano/") + string(motorNames[i]) + string("/set_velocity")); set_velocity_srv.request.value = speeds[i];set_velocity_client.call(set_velocity_srv);}speed_data.header.stamp = ros::Time::now();speed_data.twist.twist.linear.x = linear_temp;speed_data.twist.twist.angular.z = angular_temp;pub_speed.publish(speed_data);speeds[0]=0;speeds[1]=0;
}/*******************************************************
* Function name :controllerNameCallback
* Description :控制器名回调函数,获取当前ROS存在的机器人控制器
* Parameter :@name 控制器名
* Return :无
**********************************************************/
// catch names of the controllers availables on ROS network
void controllerNameCallback(const std_msgs::String::ConstPtr &name) { controllerCount++; controllerList.push_back(name->data);//将控制器名加入到列表中ROS_INFO("Controller #%d: %s.", controllerCount, controllerList.back().c_str());}/*******************************************************
* Function name :quit
* Description :退出函数
* Parameter :@sig 信号
* Return :无
**********************************************************/
void quit(int sig) {ROS_INFO("User stopped the '/volcano' node.");timeStepSrv.request.value = 0; timeStepClient.call(timeStepSrv); ros::shutdown();exit(0);
}
/*******************************************************
* Function name :键盘返回函数
* Description :当键盘动作,就会进入此函数内
* Parameter :@value 返回的值
* Return :无
**********************************************************/
void keyboardDataCallback(const webots_ros::Int32Stamped::ConstPtr &value)
{switch (value->data){case 314:angular_temp-=0.1;break;case 315:linear_temp += 0.1;break;case 316:angular_temp+=0.1;break;case 317:linear_temp-=0.1;break;case 32:linear_temp = 0;angular_temp = 0;break;default:break;}
}int main(int argc, char **argv) {std::string controllerName;// 在ROS网络中创建一个名为volcano_init的节点ros::init(argc, argv, "volcano_init", ros::init_options::AnonymousName);n = new ros::NodeHandle;// 截取退出信号signal(SIGINT, quit);// 订阅webots中所有可用的model_nameros::Subscriber nameSub = n->subscribe("model_name", 100, controllerNameCallback);while (controllerCount == 0 || controllerCount < nameSub.getNumPublishers()) {ros::spinOnce();ros::spinOnce();ros::spinOnce();}ros::spinOnce();// 服务订阅time_step和webots保持同步timeStepClient = n->serviceClient<webots_ros::set_int>("volcano/robot/time_step");timeStepSrv.request.value = TIME_STEP;// 如果在webots中有多个控制器的话,需要让用户选择一个控制器if (controllerCount == 1)controllerName = controllerList[0];else {int wantedController = 0;std::cout << "Choose the # of the controller you want to use:\n";std::cin >> wantedController;if (1 <= wantedController && wantedController <= controllerCount)controllerName = controllerList[wantedController - 1];else {ROS_ERROR("Invalid number for controller choice.");return 1;}}ROS_INFO("Using controller: '%s'", controllerName.c_str());// 退出主题,因为已经不重要了nameSub.shutdown();//初始化电机for (int i = 0; i < NMOTORS; ++i) {// position速度控制时设置为缺省值INFINITY set_position_client = n->serviceClient<webots_ros::set_float>(string("/volcano/") + string(motorNames[i]) + string("/set_position")); set_position_srv.request.value = INFINITY;if (set_position_client.call(set_position_srv) && set_position_srv.response.success) ROS_INFO("Position set to INFINITY for motor %s.", motorNames[i]); else ROS_ERROR("Failed to call service set_position on motor %s.", motorNames[i]);// velocity初始速度设置为0 set_velocity_client = n->serviceClient<webots_ros::set_float>(string("/volcano/") + string(motorNames[i]) + string("/set_velocity")); set_velocity_srv.request.value = 0.0; if (set_velocity_client.call(set_velocity_srv) && set_velocity_srv.response.success == 1) ROS_INFO("Velocity set to 0.0 for motor %s.", motorNames[i]); else ROS_ERROR("Failed to call service set_velocity on motor %s.", motorNames[i]);} pub_speed = n->advertise<nav_msgs::Odometry>("/vel",10);// 服务订阅键盘ros::ServiceClient keyboardEnableClient;webots_ros::set_int keyboardEnablesrv;keyboardEnableClient = n->serviceClient<webots_ros::set_int>("/volcano/keyboard/enable");keyboardEnablesrv.request.value = TIME_STEP;if (keyboardEnableClient.call(keyboardEnablesrv) && keyboardEnablesrv.response.success){ros::Subscriber keyboardSub;keyboardSub = n->subscribe("/volcano/keyboard/key",1,keyboardDataCallback);while (keyboardSub.getNumPublishers() == 0) {}setlocale(LC_CTYPE,"zh_CN.utf8");//设置中文ROS_INFO("Keyboard enabled.");ROS_INFO("控制方向:");ROS_INFO(" ↑ ");ROS_INFO("← ↓ →");ROS_INFO("刹车:空格键");ROS_INFO("Use the arrows in Webots window to move the robot.");ROS_INFO("Press the End key to stop the node.");while (ros::ok()) { ros::spinOnce();updateSpeed();if (!timeStepClient.call(timeStepSrv) || !timeStepSrv.response.success){ ROS_ERROR("Failed to call service time_step for next step."); break; } ros::spinOnce();} }elseROS_ERROR("Could not enable keyboard, success = %d.", keyboardEnablesrv.response.success);timeStepSrv.request.value = 0;timeStepClient.call(timeStepSrv);ros::shutdown(); return 0;
}
在程序中笔者已经将线速度和角速度以nav_msgs/Odometry
类型的消息发布到/vel
话题上了。下面会用到
算法嘛,也就是之前第5章导航功能2中提到的,同样的图哦~~:
接下来不多说,直接编译看效果吧~~:
看上去还是有点歪,说明还是有累计误差的存在的,不过已经比刚刚好很多了,继续往下看。
3.3.2 使用激光雷达数据+里程计数据
因为需要里程计数据,所以我们需要自己发布一个数据。
在这里笔者是直接在robot_broadcaster.cpp
中更改的。
我们可以先看一下odom需要的是什么类型的数据,这是我从tianbot_mini上截下来的数据如下所示:
- position->因为仿真中用到了GPS,所以这里可以用上GPS数据,也可以自己算。。
- orientation->我们需要IMU数据
- linear->线速度,只需要x
- angular->角速度,只需要z
直接放上代码,代码下面讲解细节~~:
#include <signal.h>
#include <std_msgs/String.h>
#include <sensor_msgs/NavSatFix.h>
#include <sensor_msgs/Imu.h>
#include <nav_msgs/Odometry.h>
#include <rosgraph_msgs/Clock.h>
#include <tf/transform_broadcaster.h>
#include "ros/ros.h"#include <webots_ros/set_float.h>
#include <webots_ros/set_int.h>
#include <webots_ros/Int32Stamped.h>using namespace std;
#define TIME_STEP 32 //时钟
#define NMOTORS 2 //电机数量
#define MAX_SPEED 2.0 //电机最大速度ros::NodeHandle *n;static int controllerCount;
static vector<string> controllerList; ros::ServiceClient timeStepClient; //时钟通讯客户端
webots_ros::set_int timeStepSrv; //时钟服务数据ros::Publisher odompub;double GPSvalues[6]; // gps数据
int gps_flag=1;
double Inertialvalues[4]; // inertial_unit数据
double liner_speed=0;
double angular_speed=0;
/*******************************************************
* Function name :controllerNameCallback
* Description :控制器名回调函数,获取当前ROS存在的机器人控制器
* Parameter :@name 控制器名
* Return :无
**********************************************************/
void controllerNameCallback(const std_msgs::String::ConstPtr &name) { controllerCount++; controllerList.push_back(name->data);//将控制器名加入到列表中ROS_INFO("Controller #%d: %s.", controllerCount, controllerList.back().c_str());}/*******************************************************
* Function name :quit
* Description :退出函数
* Parameter :@sig 信号
* Return :无
**********************************************************/
void quit(int sig) {ROS_INFO("User stopped the '/robot' node.");timeStepSrv.request.value = 0; timeStepClient.call(timeStepSrv); ros::shutdown();exit(0);
}void broadcastTransform()
{static tf::TransformBroadcaster br;tf::Transform transform;transform.setOrigin(tf::Vector3(-(GPSvalues[2]-GPSvalues[5]),GPSvalues[0]-GPSvalues[3],GPSvalues[1]));// 设置原点tf::Quaternion q(Inertialvalues[0],Inertialvalues[1],Inertialvalues[2],Inertialvalues[3]);q = q.inverse();transform.setRotation(q);br.sendTransform(tf::StampedTransform(transform,ros::Time::now(),"odom","base_link"));transform.setIdentity();br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "base_link", "/robot/Sick_LMS_291"));
}void send_odom_data()
{nav_msgs::Odometry odom;odom.header.frame_id = "odom";odom.child_frame_id = "base_link";odom.header.stamp = ros::Time::now();odom.pose.pose.position.x = -(GPSvalues[2]-GPSvalues[5]);odom.pose.pose.position.y = GPSvalues[0]-GPSvalues[3];odom.pose.pose.position.z = 0;odom.pose.pose.orientation.x = 0;odom.pose.pose.orientation.y = 0;odom.pose.pose.orientation.z = Inertialvalues[2];odom.pose.pose.orientation.w = -Inertialvalues[3];odom.twist.twist.linear.x = liner_speed;odom.twist.twist.angular.z = angular_speed;odompub.publish(odom);}void gpsCallback(const sensor_msgs::NavSatFix::ConstPtr &values)
{GPSvalues[0] = values->latitude;GPSvalues[1] = values->altitude;GPSvalues[2] = values->longitude;if (gps_flag){GPSvalues[3] = values->latitude;GPSvalues[4] = values->altitude;GPSvalues[5] = values->longitude;gps_flag=0;}broadcastTransform();
}void inertial_unitCallback(const sensor_msgs::Imu::ConstPtr &values)
{Inertialvalues[0] = values->orientation.x;Inertialvalues[1] = values->orientation.y;Inertialvalues[2] = values->orientation.z;Inertialvalues[3] = values->orientation.w;broadcastTransform();
}
void velCallback(const nav_msgs::Odometry::ConstPtr &value)
{liner_speed = value->twist.twist.linear.x;angular_speed = value->twist.twist.angular.z;send_odom_data();
}int main(int argc, char **argv) {setlocale(LC_ALL, ""); // 用于显示中文字符string controllerName;// 在ROS网络中创建一个名为robot_init的节点ros::init(argc, argv, "robot_init", ros::init_options::AnonymousName);n = new ros::NodeHandle;// 截取退出信号signal(SIGINT, quit);// 订阅webots中所有可用的model_nameros::Subscriber nameSub = n->subscribe("model_name", 100, controllerNameCallback);while (controllerCount == 0 || controllerCount < nameSub.getNumPublishers()) {ros::spinOnce();}ros::spinOnce();// 服务订阅time_step和webots保持同步timeStepClient = n->serviceClient<webots_ros::set_int>("robot/robot/time_step");timeStepSrv.request.value = TIME_STEP;// 如果在webots中有多个控制器的话,需要让用户选择一个控制器if (controllerCount == 1)controllerName = controllerList[0];else {int wantedController = 0;cout << "Choose the # of the controller you want to use:\n";cin >> wantedController;if (1 <= wantedController && wantedController <= controllerCount)controllerName = controllerList[wantedController - 1];else {ROS_ERROR("Invalid number for controller choice.");return 1;}}ROS_INFO("Using controller: '%s'", controllerName.c_str());// 退出主题,因为已经不重要了nameSub.shutdown();// 使能lidarros::ServiceClient lidar_Client; webots_ros::set_int lidar_Srv; lidar_Client = n->serviceClient<webots_ros::set_int>("/robot/Sick_LMS_291/enable");lidar_Srv.request.value = TIME_STEP;if (lidar_Client.call(lidar_Srv) && lidar_Srv.response.success) {ROS_INFO("gps enabled.");} else {if (!lidar_Srv.response.success)ROS_ERROR("Failed to enable lidar.");return 1;}// 订阅gps服务ros::ServiceClient gps_Client; webots_ros::set_int gps_Srv; ros::Subscriber gps_sub;gps_Client = n->serviceClient<webots_ros::set_int>("/robot/gps/enable");gps_Srv.request.value = TIME_STEP;if (gps_Client.call(gps_Srv) && gps_Srv.response.success) {ROS_INFO("gps enabled.");gps_sub = n->subscribe("/robot/gps/values", 1, gpsCallback);ROS_INFO("Topic for gps initialized.");while (gps_sub.getNumPublishers() == 0) {}ROS_INFO("Topic for gps connected.");} else {if (!gps_Srv.response.success)ROS_ERROR("Sampling period is not valid.");ROS_ERROR("Failed to enable gps.");return 1;}// 订阅inertial_unit服务ros::ServiceClient inertial_unit_Client; webots_ros::set_int inertial_unit_Srv; ros::Subscriber inertial_unit_sub;inertial_unit_Client = n->serviceClient<webots_ros::set_int>("/robot/inertial_unit/enable");inertial_unit_Srv.request.value = TIME_STEP;if (inertial_unit_Client.call(inertial_unit_Srv) && inertial_unit_Srv.response.success) {ROS_INFO("inertial_unit enabled.");inertial_unit_sub = n->subscribe("/robot/inertial_unit/roll_pitch_yaw", 1, inertial_unitCallback);ROS_INFO("Topic for inertial_unit initialized.");while (inertial_unit_sub.getNumPublishers() == 0) {}ROS_INFO("Topic for inertial_unit connected.");} else {if (!inertial_unit_Srv.response.success)ROS_ERROR("Sampling period is not valid.");ROS_ERROR("Failed to enable inertial_unit.");return 1;}ROS_INFO("You can now start the creation of the map using 'rosrun gmapping slam_gmapping ""scan:=/volcano/Sick_LMS_291/laser_scan/layer0 _xmax:=30 _xmin:=-30 _ymax:=30 _ymin:=-30 _delta:=0.2'.");ROS_INFO("You can now visualize the sensors output in rqt using 'rqt'.");ros::Subscriber sub_speed;sub_speed = n->subscribe("/vel", 1, velCallback);ros::Publisher time = n->advertise<rosgraph_msgs::Clock>("/clock",10);//订阅/clock话题odompub = n->advertise<nav_msgs::Odometry>("/odom",10);// main loopwhile (ros::ok()) {if (!timeStepClient.call(timeStepSrv) || !timeStepSrv.response.success) {ROS_ERROR("Failed to call service time_step for next step.");break;}rosgraph_msgs::Clock clock;clock.clock = ros::Time::now();time.publish(clock);//实时发布rosgraph_msgs::Clock信息ros::spinOnce();}timeStepSrv.request.value = 0;timeStepClient.call(timeStepSrv);ros::shutdown(); return 0;
}
改完记得编译哦~
还有lua配置文件不要忘记根据上面的教程更改哦。
测试:
先rostopic看一下,这就是所有的话题,发布的/odom、/clock、/vel都有:
$ roslaunch webots_demo webots.launch
$ rosrun webots_demo robot_broadcaster
$ rosrun webots_demo velocity_keyboard_v2 #刚刚改的控制方式的程序,改成自己的
$ roslaunch cartographer_ros demo_revo_lds.launch
效果:
结语
本文也是基于笔者的学习和使用经验总结的,主观性较强,如果有哪些不对的地方或者不明白的地方,欢迎评论区留言交流~
✌Bye
此项目github地址:https://github.com/JackyMao1999/webots_demo
Reference:
[1]贾浩. 基于Cartographer算法的SLAM与导航机器人设计[D].山东大学,2019.
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- ROS 两轮差速自主导航小车记录(基础系列)
小张实习记录 ROS学习之路第一步:第一个node 第一个订阅第二步:odom里程计信息第三步:robot_pose_ekf第四步:tf_tree第五步:hector_mapping & karto_mapping第六步:amcl第七步:navigationRE…...
2024/4/21 12:46:33 - Ionic开发App中重要的部分
写在前面 APP赶在了春节之前上线了,所以这次我们分享一下使用Ionic3 Angular5构建一个Hybird App过程中的经验。什么是Hybird App以及一些技术的选型这里就不讨论了。我每次完成一个部分就写一部分,所以有文章有点长。如果有错误的地方感谢大家指正~ 为…...
2024/4/20 16:15:01 - h5学习笔记(3) 导航菜单
手写练习一下js,最近在别人的APP的时候看到菜单的时候,一直很困扰该如何弄css,该如何去写js,平时很少写这些所以现在要把这个bug 修复一下。使用jq确实是方便很多处理dom的方面,而使用angular 的时候对一些单页面应用确…...
2024/4/20 16:14:59 - move_base导航的源码心得
参考move_base当中的代码的学习。 http://www.cnblogs.com/shhu1993/p/6323699.html 关于planner主要关注的就是: nav_core::BaseGlobalPlanner nav_core::BaseLocalPlanner nav_core::RecoveryBehavior 上面的这个三个东西都是插件的形式进行存储,十…...
2024/4/28 18:53:17 - angularJS的指令封装
什么是angular的指令?指令,说的直白一点就是一个标签,只要贴上这个标签,那么就是执行某个函数,完成某个动作!在angular框架理念中,指令也是核心的模块之一。这么说吧,web前端原生开发…...
2024/4/20 16:14:57 - 机器人SLAM与自主导航(二)——必备条件
机器人SLAM与自主导航(二)——必备条件 目录总述一、传感器信息二、仿真平台总述 ROS中SLAMda和自主导航的相关功能包可以通用于各种移动机器人平台,但为达到最佳效果,对机器人的硬件仍然有以下三个要求。 1)导航功能…...
2024/4/21 12:46:31 - 埋线双眼皮去割
...
2024/4/21 12:46:32 - 南昌割双眼皮高效*爱思特mei名
...
2024/5/2 21:14:16 - 双眼皮做后疼不疼
...
2024/4/21 12:46:28 - 做双眼皮需要准备
...
2024/4/21 12:46:27 - 清潭first割双眼皮为什么不痛
...
2024/4/21 12:46:26 - 内眦眼皮怎么变做了双眼皮显老怎么不
...
2024/4/21 12:46:25 - 现在割双眼皮恢复快吗
...
2024/4/21 12:46:24 - 双眼皮提肌能做几次
...
2024/4/21 12:46:24 - 双眼皮亚韩
...
2024/4/21 12:46:22 - AJAX:判断用户是否存在及用户名密码是否正确问题
概念:AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。AJAX 不是新的编程语言,而是一种使用现有标准的新方法。AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。AJAX是一种用于创建快速动态网页的技术。优点:通过在后台与服务器…...
2024/4/21 12:46:21 - 做埋线双眼皮失败的四种情况(图)
...
2024/4/21 12:46:27 - 广扇形双眼皮怎么化妆
...
2024/4/20 16:15:08 - angular4学习笔记(第一章 基础篇)
1.环境搭配 安装nodejs 使用npm -v 来查看版本安装angular cli 使用命令(npm install -g angular/cli) 使用 ng v 来查看版本 安装开发工具,使用的是 visual studio code 创建项目 ng new projectname进入项目 cd projectname启动项目 ng serve 2.认识angular项目的…...
2024/4/20 16:15:09 - 在广州割双眼皮出众-美来
...
2024/5/2 10:57:15
最新文章
- C#面:当线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法
不能,一个对象的一个synchronized方法只能由一个线程访问 当一个线程进入一个对象的synchronized方法后,其他线程是无法进入该对象的其他synchronized方法的。这是因为synchronized关键字可以确保同一时间只有一个线程可以进入被标记为synchronized的方…...
2024/5/6 7:32:09 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - 【Java】假如把集合体系看作购物中心
购物中心入口:Java集合框架 “Java集合广场”的购物中心,这是一个集合了各种奇特商店的地方,每个商店都充满了不同的宝藏(数据结构)。 一楼:基础集合区 - Collection接口 一楼是基础集合区,这…...
2024/5/5 15:55:12 - k8s_入门_kubelet安装
安装 在大致了解了一些k8s的基本概念之后,我们实际部署一个k8s集群,做进一步的了解 1. 裸机安装 采用三台机器,一台机器为Master(控制面板组件)两台机器为Node(工作节点) 机器的准备有两种方式…...
2024/5/4 14:33:56 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/5/4 23:54:56 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/5/4 23:54:56 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/5/4 23:54:56 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/5/4 23:55:17 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/5/4 23:54:56 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/5/4 23:55:05 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/5/4 23:54:56 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/5/4 23:55:16 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/5/4 23:54:56 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/5/6 1:40:42 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/5/4 23:54:56 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/5/4 23:55:17 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/5/4 23:55:06 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/5/4 23:54:56 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/5/4 23:55:06 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/5/5 8:13:33 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/5/4 23:55:16 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/5/4 23:54:58 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/5/4 23:55:01 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/5/4 23:54:56 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57