ROS 移动机器人 STM32 Kinect2 智能车
基于ROS平台的移动机器人-目录
说明
本系列博文将介绍基于ROS平台的移动机器人的搭建,包括小车的底盘的制作,控制和与上位机的通信,建图和导航。
目录
- 基于ROS平台的移动机器人-1-小车底盘的搭建
- 基于ROS平台的移动机器人-2-小车底盘控制
- 基于ROS平台的移动机器人-3-小车底盘与ROS的通信
- 基于ROS平台的移动机器人-4-通过ROS利用键盘控制小车移动
- 基于ROS平台的移动机器人-5-Kinect2驱动的安装和ROS下的测试
- 基于ROS平台的移动机器人-6-使用Kinect2获取激光数据
- 基于ROS平台的移动机器人-7-使用Kinect2建图
- 基于ROS平台的移动机器人-8-使用Kinect2导航
注意
本人Ubuntu版本为14.04,ROS版本为indigo
基于ROS平台的移动机器人-1-小车底盘的搭建
说明
本博文将介绍小车底盘的搭建需要的硬件和搭建过程
物品清单
- 亚克力板或者铝合金小车底板一套
- 小车轮子一对
- 带编码器减速电机一对
- 万向轮一个
- 12V充电电池一个
- 降压模块一个
- 电机驱动模块一个
- STM32核心板一块
- Kinect2一个
- 工控机或者笔记本一个
搭建步骤
- 分别将电池,降压模块,电机,万向轮,电机驱动板,STM32核心板,Kinect2和工控机装好在底盘板上
- 将轮子分别装上电机
- 将电池电源引出两路,一路接在降压模块,一路接在电机驱动模块
- 将电机驱动线接到驱动模块
- 降压模块得到的5V给STM32核心板供电
- 将STM32核心板的串口接到工控机
- 将Kinect2的usb口接到工控机的USB3.0口
- 小车搭建完成
- 基于ROS平台的移动机器人-2制-小车底盘控
-
说明
本博文将介绍小车底盘控制的原理,如PID控制,控制程序的编写等。
小车控制思想
- 控制电机转动。电机的控制我们分为两部分,一部分为电机转动方向的控制,另一个为电机转速的控制。电机转动的方向我们用两个MCU引脚来控制,假如PIN_A=1,PIN_B=0 时,电机正转;PIN_A=0,PIN_B=1 时,电机反转;PIN_A=0,PIN_B=0 时,电机停止。电机速度的控制则需要一个PWM输出引脚,我们通过控制输出不同的PWM值来控制电机转动的速度。
- PID控制。如果我们想控制小车以一米每秒的速度做直线,但由于地面的摩擦阻力的影响,会造成左右轮速度与我们想控制的速度不同,所以会走不直,这时我们就需要加入PID控制,PID控制的思想就是我实时的把轮子真正的速度采集回来和控制的速度对比,差则补,多则减。这样基本就可以实现理想控制。详细PID介绍查看。
- 小车转弯控制。一般我们要是想控制小车以多少的速度前进或者后退,我们只需要PID控制两个轮子的速度一致就可以基本做到。但如果要想控制小车以多少的角速度转弯,我们需要做一定的计算,如图所示:
-
推算过程这里就不算了,我们可以得到左右轮速度和线速度角速度之间的关系如下:
通过以上的公式我们就可以控制小车的任意行走了。
程序结构
以下为我的STM32工程主要文件
1.main.c 接收和发送串口数据,控制电机
/*********************************************** 说明 ***************************************************************** * * 1.串口接收 * (1)内容:小车左右轮速度,单位:mm/s(所有数据都为 float型,float型占4字节) * (2)格式:10字节 [右轮速度4字节][左轮速度4字节][结束符"\r\n"2字节] * * 2.串口发送 * (1)内容:里程计(x,y坐标、线速度、角速度和方向角,单位依次为:mm,mm,mm/s,rad/s,rad,所有数据都为float型,float型占4字节) * (2)格式:21字节 [x坐标4字节][y坐标4字节][方向角4字节][线速度4字节][角速度4字节][结束符"\n"1字节] * ************************************************************************************************************************/ #include "stm32f10x.h" #include "stm32f10x_it.h"#include "delay.h" #include "nvic_conf.h" #include "rcc_conf.h"#include "usart.h" #include "encoder.h" #include "contact.h" #include "gpio_conf.h" #include "tim2_5_6.h" #include "odometry.h" #include "tim2_5_6.h"#include "stdbool.h" #include <stdio.h> #include "string.h" #include "math.h" /*********************************************** 输出 *****************************************************************/char odometry_data[21]={0}; //发送给串口的里程计数据数组float odometry_right=0,odometry_left=0;//串口得到的左右轮速度/*********************************************** 输入 *****************************************************************/extern float position_x,position_y,oriention,velocity_linear,velocity_angular; //计算得到的里程计数值extern u8 USART_RX_BUF[USART_REC_LEN]; //串口接收缓冲,最大USART_REC_LEN个字节. extern u16 USART_RX_STA; //串口接收状态标记 extern float Milemeter_L_Motor,Milemeter_R_Motor; //dt时间内的左右轮速度,用于里程计计算/*********************************************** 变量 *****************************************************************/u8 main_sta=0; //用作处理主函数各种if,去掉多余的flag(1打印里程计)(2调用计算里程计数据函数)(3串口接收成功)(4串口接收失败)union recieveData //接收到的数据 {float d; //左右轮速度unsigned char data[4]; }leftdata,rightdata; //接收的左右轮数据union odometry //里程计数据共用体 {float odoemtry_float;unsigned char odometry_char[4]; }x_data,y_data,theta_data,vel_linear,vel_angular; //要发布的里程计数据,分别为:X,Y方向移动的距离,当前角度,线速度,角速度/****************************************************************************************************************/ int main(void) { u8 t=0; u8 i=0,j=0,m=0;RCC_Configuration(); //系统时钟配置 NVIC_Configuration(); //中断优先级配置 GPIO_Configuration(); //电机方向控制引脚配置 USART1_Config(); //串口1配置TIM2_PWM_Init(); //PWM输出初始化 ENC_Init(); //电机处理初始化 TIM5_Configuration(); //速度计算定时器初始化 TIM1_Configuration(); //里程计发布定时器初始化while (1) { if(main_sta&0x01)//执行发送里程计数据步骤{//里程计数据获取x_data.odoemtry_float=position_x;//单位mmy_data.odoemtry_float=position_y;//单位mmtheta_data.odoemtry_float=oriention;//单位radvel_linear.odoemtry_float=velocity_linear;//单位mm/svel_angular.odoemtry_float=velocity_angular;//单位rad/s//将所有里程计数据存到要发送的数组for(j=0;j<4;j++){odometry_data[j]=x_data.odometry_char[j];odometry_data[j+4]=y_data.odometry_char[j];odometry_data[j+8]=theta_data.odometry_char[j];odometry_data[j+12]=vel_linear.odometry_char[j];odometry_data[j+16]=vel_angular.odometry_char[j];}odometry_data[20]='\n';//添加结束符//发送数据要串口for(i=0;i<21;i++){USART_ClearFlag(USART1,USART_FLAG_TC); //在发送第一个数据前加此句,解决第一个数据不能正常发送的问题 USART_SendData(USART1,odometry_data[i]);//发送一个字节到串口 while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //等待发送结束 }main_sta&=0xFE;//执行计算里程计数据步骤}if(main_sta&0x02)//执行计算里程计数据步骤{odometry(Milemeter_R_Motor,Milemeter_L_Motor);//计算里程计main_sta&=0xFD;//执行发送里程计数据步骤} if(main_sta&0x08) //当发送指令没有正确接收时{USART_ClearFlag(USART1,USART_FLAG_TC); //在发送第一个数据前加此句,解决第一个数据不能正常发送的问题for(m=0;m<3;m++){USART_SendData(USART1,0x00); while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);} USART_SendData(USART1,'\n'); while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); main_sta&=0xF7;}if(USART_RX_STA&0x8000) // 串口1接收函数{ //接收左右轮速度for(t=0;t<4;t++){rightdata.data[t]=USART_RX_BUF[t];leftdata.data[t]=USART_RX_BUF[t+4];}//储存左右轮速度odometry_right=rightdata.d;//单位mm/sodometry_left=leftdata.d;//单位mm/sUSART_RX_STA=0;//清楚接收标志位}car_control(rightdata.d,leftdata.d); //将接收到的左右轮速度赋给小车 }//end_while }//end main /*********************************************END OF FILE**************************************************/
-
2.odometry.c 里程计计算
#include "odometry.h"/*********************************************** 输出 *****************************************************************/float position_x=0,position_y=0,oriention=0,velocity_linear=0,velocity_angular=0;/*********************************************** 输入 *****************************************************************/extern float odometry_right,odometry_left;//串口得到的左右轮速度/*********************************************** 变量 *****************************************************************/float wheel_interval= 268.0859f;// 272.0f; // 1.0146 //float wheel_interval=276.089f; //轴距校正值=原轴距/0.987float multiplier=4.0f; //倍频数 float deceleration_ratio=90.0f; //减速比 float wheel_diameter=100.0f; //轮子直径,单位mm float pi_1_2=1.570796f; //π/2 float pi=3.141593f; //π float pi_3_2=4.712389f; //π*3/2 float pi_2_1=6.283186f; //π*2 float dt=0.005f; //采样时间间隔5ms float line_number=4096.0f; //码盘线数 float oriention_interval=0; //dt时间内方向变化值float sin_=0; //角度计算值 float cos_=0;float delta_distance=0,delta_oriention=0; //采样时间间隔内运动的距离float const_frame=0,const_angle=0,distance_sum=0,distance_diff=0;float oriention_1=0;u8 once=1;/****************************************************************************************************************///里程计计算函数 void odometry(float right,float left) { if(once) //常数仅计算一次{const_frame=wheel_diameter*pi/(line_number*multiplier*deceleration_ratio);const_angle=const_frame/wheel_interval;once=0;}distance_sum = 0.5f*(right+left);//在很短的时间内,小车行驶的路程为两轮速度和distance_diff = right-left;//在很短的时间内,小车行驶的角度为两轮速度差//根据左右轮的方向,纠正短时间内,小车行驶的路程和角度量的正负if((odometry_right>0)&&(odometry_left>0)) //左右均正{delta_distance = distance_sum;delta_oriention = distance_diff;}else if((odometry_right<0)&&(odometry_left<0)) //左右均负{delta_distance = -distance_sum;delta_oriention = -distance_diff;}else if((odometry_right<0)&&(odometry_left>0)) //左正右负{delta_distance = -distance_diff;delta_oriention = -2.0f*distance_sum; }else if((odometry_right>0)&&(odometry_left<0)) //左负右正{delta_distance = distance_diff;delta_oriention = 2.0f*distance_sum;}else{delta_distance=0;delta_oriention=0;}oriention_interval = delta_oriention * const_angle;//采样时间内走的角度 oriention = oriention + oriention_interval;//计算出里程计方向角oriention_1 = oriention + 0.5f * oriention_interval;//里程计方向角数据位数变化,用于三角函数计算sin_ = sin(oriention_1);//计算出采样时间内y坐标cos_ = cos(oriention_1);//计算出采样时间内x坐标position_x = position_x + delta_distance * cos_ * const_frame;//计算出里程计x坐标position_y = position_y + delta_distance * sin_ * const_frame;//计算出里程计y坐标velocity_linear = delta_distance*const_frame / dt;//计算出里程计线速度velocity_angular = oriention_interval / dt;//计算出里程计角速度//方向角角度纠正if(oriention > pi){oriention -= pi_2_1;}else{if(oriention < -pi){oriention += pi_2_1;}} }
-
3.PID.c PID处理函数
#include "PID.h"extern int span;float MaxValue=9;//输出最大限幅 float MinValue=-9;//输出最小限幅float OutputValue;//PID输出暂存变量,用于积分饱和抑制float PID_calculate(struct PID *Control,float CurrentValue_left )//位置PID计算B {float Value_Kp;//比例分量float Value_Ki;//积分分量float Value_Kd;//微分分量Control->error_0 = Control->OwenValue - CurrentValue_left + 0*span;//基波分量,Control->OwenValue为想要的速度,CurrentValue_left为电机真实速度Value_Kp = Control->Kp * Control->error_0 ;Control->Sum_error += Control->error_0; /***********************积分饱和抑制********************************************/OutputValue = Control->OutputValue;if(OutputValue>5 || OutputValue<-5) {Control->Ki = 0; }/*******************************************************************/Value_Ki = Control->Ki * Control->Sum_error;Value_Kd = Control->Kd * ( Control->error_0 - Control->error_1);Control->error_1 = Control->error_0;//保存一次谐波Control->OutputValue = Value_Kp + Value_Ki + Value_Kd;//输出值计算,注意加减//限幅if( Control->OutputValue > MaxValue)Control->OutputValue = MaxValue;if (Control->OutputValue < MinValue)Control->OutputValue = MinValue;return (Control->OutputValue) ; }
-
4.encoder.c 电机编码处理
#include "encoder.h"/****************************************************************************************************************/s32 hSpeed_Buffer2[SPEED_BUFFER_SIZE]={0}, hSpeed_Buffer1[SPEED_BUFFER_SIZE]={0};//左右轮速度缓存数组 static unsigned int hRot_Speed2;//电机A平均转速缓存 static unsigned int hRot_Speed1;//电机B平均转速缓存 unsigned int Speed2=0; //电机A平均转速 r/min,PID调节 unsigned int Speed1=0; //电机B平均转速 r/min,PID调节static volatile u16 hEncoder_Timer_Overflow1;//电机B编码数采集 static volatile u16 hEncoder_Timer_Overflow2;//电机A编码数采集//float A_REMP_PLUS;//电机APID调节后的PWM值缓存 float pulse = 0;//电机A PID调节后的PWM值缓存 float pulse1 = 0;//电机B PID调节后的PWM值缓存int span;//采集回来的左右轮速度差值static bool bIs_First_Measurement2 = true;//电机A以清除速度缓存数组标志位 static bool bIs_First_Measurement1 = true;//电机B以清除速度缓存数组标志位struct PID Control_left ={0.01,0.1,0.75,0,0,0,0,0,0};//左轮PID参数,适于新电机4096 struct PID Control_right ={0.01,0.1,0.75,0,0,0,0,0,0};//右轮PID参数,适于新电机4096/****************************************************************************************************************/s32 hPrevious_angle2, hPrevious_angle1;/****************************************************************************************************************/void ENC_Init2(void)//电机A码盘采集定时器,TIM4编码器模式 {TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_ICInitTypeDef TIM_ICInitStructure; GPIO_InitTypeDef GPIO_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_StructInit(&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);TIM_DeInit(ENCODER2_TIMER);TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_Period = (4*ENCODER2_PPR)-1;TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(ENCODER2_TIMER, &TIM_TimeBaseStructure);TIM_EncoderInterfaceConfig(ENCODER2_TIMER, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);TIM_ICStructInit(&TIM_ICInitStructure);TIM_ICInitStructure.TIM_ICFilter = ICx_FILTER;TIM_ICInit(ENCODER2_TIMER, &TIM_ICInitStructure);TIM_ClearFlag(ENCODER2_TIMER, TIM_FLAG_Update);TIM_ITConfig(ENCODER2_TIMER, TIM_IT_Update, ENABLE);TIM_Cmd(ENCODER2_TIMER, ENABLE); }void ENC_Init1(void)//电机B码盘采集定时器,TIM3编码器模式 {TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_ICInitTypeDef TIM_ICInitStructure;GPIO_InitTypeDef GPIO_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_StructInit(&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);TIM_DeInit(ENCODER1_TIMER);TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);TIM_TimeBaseStructure.TIM_Prescaler = 0;TIM_TimeBaseStructure.TIM_Period = (4*ENCODER1_PPR)-1; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(ENCODER1_TIMER, &TIM_TimeBaseStructure);TIM_EncoderInterfaceConfig(ENCODER1_TIMER, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);TIM_ICStructInit(&TIM_ICInitStructure);TIM_ICInitStructure.TIM_ICFilter = ICx_FILTER;TIM_ICInit(ENCODER1_TIMER, &TIM_ICInitStructure);TIM_ClearFlag(ENCODER1_TIMER, TIM_FLAG_Update);TIM_ITConfig(ENCODER1_TIMER, TIM_IT_Update, ENABLE);TIM_Cmd(ENCODER1_TIMER, ENABLE); }/****************************************************************************************************************/s16 ENC_Calc_Rot_Speed2(void)//计算电机A的编码数 { s32 wDelta_angle;u16 hEnc_Timer_Overflow_sample_one;u16 hCurrent_angle_sample_one;s32 temp;s16 haux;if (!bIs_First_Measurement2)//电机A以清除速度缓存数组{ hEnc_Timer_Overflow_sample_one = hEncoder_Timer_Overflow2; hCurrent_angle_sample_one = ENCODER2_TIMER->CNT;hEncoder_Timer_Overflow2 = 0;haux = ENCODER2_TIMER->CNT; if ( (ENCODER2_TIMER->CR1 & TIM_CounterMode_Down) == TIM_CounterMode_Down) {// encoder timer down-counting 反转的速度计算 wDelta_angle = (s32)((hEnc_Timer_Overflow_sample_one) * (4*ENCODER2_PPR) -(hCurrent_angle_sample_one - hPrevious_angle2));}else {//encoder timer up-counting 正转的速度计算wDelta_angle = (s32)(hCurrent_angle_sample_one - hPrevious_angle2 + (hEnc_Timer_Overflow_sample_one) * (4*ENCODER2_PPR));} temp=wDelta_angle;} else{bIs_First_Measurement2 = false;//电机A以清除速度缓存数组标志位temp = 0;hEncoder_Timer_Overflow2 = 0;haux = ENCODER2_TIMER->CNT; }hPrevious_angle2 = haux; return((s16) temp); }s16 ENC_Calc_Rot_Speed1(void)//计算电机B的编码数 { s32 wDelta_angle;u16 hEnc_Timer_Overflow_sample_one;u16 hCurrent_angle_sample_one;s32 temp;s16 haux;if (!bIs_First_Measurement1)//电机B以清除速度缓存数组{ hEnc_Timer_Overflow_sample_one = hEncoder_Timer_Overflow1; //得到采样时间内的编码数 hCurrent_angle_sample_one = ENCODER1_TIMER->CNT;hEncoder_Timer_Overflow1 = 0;//清除脉冲数累加haux = ENCODER1_TIMER->CNT; if ( (ENCODER1_TIMER->CR1 & TIM_CounterMode_Down) == TIM_CounterMode_Down) {// encoder timer down-counting 反转的速度计算wDelta_angle = (s32)((hEnc_Timer_Overflow_sample_one) * (4*ENCODER1_PPR) -(hCurrent_angle_sample_one - hPrevious_angle1)); }else {//encoder timer up-counting 正转的速度计算wDelta_angle = (s32)(hCurrent_angle_sample_one - hPrevious_angle1 + (hEnc_Timer_Overflow_sample_one) * (4*ENCODER1_PPR));}temp=wDelta_angle;} else{bIs_First_Measurement1 = false;//电机B以清除速度缓存数组标志位temp = 0;hEncoder_Timer_Overflow1 = 0;haux = ENCODER1_TIMER->CNT; }hPrevious_angle1 = haux; return((s16) temp); }/****************************************************************************************************************/void ENC_Clear_Speed_Buffer(void)//速度存储器清零 { u32 i;//清除左右轮速度缓存数组for (i=0;i<SPEED_BUFFER_SIZE;i++){hSpeed_Buffer2[i] = 0;hSpeed_Buffer1[i] = 0;}bIs_First_Measurement2 = true;//电机A以清除速度缓存数组标志位bIs_First_Measurement1 = true;//电机B以清除速度缓存数组标志位 }void ENC_Calc_Average_Speed(void)//计算三次电机的平均编码数 { u32 i;signed long long wtemp3=0;signed long long wtemp4=0;//累加缓存次数内的速度值for (i=0;i<SPEED_BUFFER_SIZE;i++){wtemp4 += hSpeed_Buffer2[i];wtemp3 += hSpeed_Buffer1[i];}//取平均,平均脉冲数单位为 个/s wtemp3 /= (SPEED_BUFFER_SIZE);wtemp4 /= (SPEED_BUFFER_SIZE); //平均脉冲数 个/s //将平均脉冲数单位转为 r/minwtemp3 = (wtemp3 * SPEED_SAMPLING_FREQ)*60/(4*ENCODER1_PPR);wtemp4 = (wtemp4 * SPEED_SAMPLING_FREQ)*60/(4*ENCODER2_PPR); hRot_Speed2= ((s16)(wtemp4));//平均转速 r/minhRot_Speed1= ((s16)(wtemp3));//平均转速 r/minSpeed2=hRot_Speed2;//平均转速 r/minSpeed1=hRot_Speed1;//平均转速 r/min }/****************************************************************************************************************/void Gain2(void)//设置电机A PID调节 PA2 {//static float pulse = 0;span=1*(Speed1-Speed2);//采集回来的左右轮速度差值pulse= pulse + PID_calculate(&Control_right,hRot_Speed2);//PID调节//pwm幅度抑制if(pulse > 3600) pulse = 3600;if(pulse < 0) pulse = 0;//A_REMP_PLUS=pulse;//电机APID调节后的PWM值缓存 }void Gain1(void)//设置电机B PID调节 PA1 {//static float pulse1 = 0;span=1*(Speed2-Speed1);//采集回来的左右轮速度差值pulse1= pulse1 + PID_calculate(&Control_left,hRot_Speed1);//PID调节pwm 幅度抑制if(pulse1 > 3600) pulse1 = 3600;if(pulse1 < 0) pulse1 = 0;TIM2->CCR2 = pulse1;//电机B赋值PWM//TIM2->CCR3 = A_REMP_PLUS;//电机A赋值PWMTIM2->CCR3 = pulse;//电机A赋值PWM }/****************************************************************************************************************/void ENC_Init(void)//电机处理初始化 {ENC_Init2(); //设置电机A TIM4编码器模式PB6 PB7 右电机ENC_Init1(); //设置电机B TIM3编码器模式PA6 PA7 左电机ENC_Clear_Speed_Buffer();//速度存储器清零 }/****************************************************************************************************************/void TIM4_IRQHandler (void)//执行TIM4(电机A编码器采集)计数中断 { TIM_ClearFlag(ENCODER2_TIMER, TIM_FLAG_Update);if (hEncoder_Timer_Overflow2 != U16_MAX)//不超范围 {hEncoder_Timer_Overflow2++; //脉冲数累加} }void TIM3_IRQHandler (void)//执行TIM3(电机B编码器采集)计数中断 { TIM_ClearFlag(ENCODER1_TIMER, TIM_FLAG_Update);if (hEncoder_Timer_Overflow1 != U16_MAX)//不超范围 {hEncoder_Timer_Overflow1++; //脉冲数累加} }
-
5.contact.c 电机控制函数
#include "contact.h"/*********************************************** 输出 *****************************************************************//*********************************************** 输入 *****************************************************************/extern struct PID Control_left;//左轮PID参数,适于新电机4096 extern struct PID Control_right;//右轮PID参数,适于新电机4096/*********************************************** 变量 *****************************************************************//*******************************************************************************************************************/void LeftMovingSpeedW(unsigned int val)//左轮方向和速度控制函数 { if(val>10000){ GPIO_SetBits(GPIOC, GPIO_Pin_6); GPIO_ResetBits(GPIOC, GPIO_Pin_7); Control_left.OwenValue=(val-10000);//PID调节的目标编码数 }else if(val<10000){ GPIO_SetBits(GPIOC, GPIO_Pin_7); GPIO_ResetBits(GPIOC, GPIO_Pin_6); Control_left.OwenValue=(10000-val);//PID调节的目标编码数 } else{GPIO_SetBits(GPIOC, GPIO_Pin_6); GPIO_SetBits(GPIOC, GPIO_Pin_7);Control_left.OwenValue=0;//PID调节的目标编码数} }void RightMovingSpeedW(unsigned int val2)//右轮方向和速度控制函数 { if(val2>10000){ /* motor A 正转*/GPIO_SetBits(GPIOC, GPIO_Pin_10); GPIO_ResetBits(GPIOC, GPIO_Pin_11); Control_right.OwenValue=(val2-10000);//PID调节的目标编码数}else if(val2<10000){ /* motor A 反转*/GPIO_SetBits(GPIOC, GPIO_Pin_11); GPIO_ResetBits(GPIOC, GPIO_Pin_10); Control_right.OwenValue=(10000-val2);//PID调节的目标编码数 } else{GPIO_SetBits(GPIOC, GPIO_Pin_10); GPIO_SetBits(GPIOC, GPIO_Pin_11);Control_right.OwenValue=0;//PID调节的目标编码数} }void car_control(float rightspeed,float leftspeed)//小车速度转化和控制函数 {float k2=17.179; //速度转换比例,转/分钟 //将从串口接收到的速度转换成实际控制小车的速度?还是PWM?int right_speed=(int)k2*rightspeed;int left_speed=(int)k2*leftspeed;RightMovingSpeedW(right_speed+10000);LeftMovingSpeedW(left_speed+10000); }//void Contact_Init(void)//左右轮方向和速度初始化 //{ // LeftMovingSpeedW(12000); //电机B // RightMovingSpeedW(12000);//电机A //}
-
完整工程代码下载
版权声明:本文为博主原创文章,如若转载,请标明作者和原文出处! https://blog.csdn.net/Forrest_Z/article/details/55001231
-
基于ROS平台的移动机器人-3-小车底盘与ROS的通信
1.ROS平台与底盘通信协议
ROS平台与小车底盘的通信一般是通过串口或者CAN总线。我这里采用的是串口,以下为我自定义的通信数据格式:
(1)底盘串口部分
-
1.串口接收(1)内容:小车左右轮速度,单位:mm/s(所有数据都为 float型,float型占4字节)(2)格式:10字节 [右轮速度4字节][左轮速度4字节][结束符"\r\n"2字节]2.串口发送(1)内容:里程计(x,y坐标、线速度、角速度和方向角,单位依次为:mm,mm,mm/s,rad/s,rad,所有数据都为float型,float型占4字节)(2)格式:21字节 [x坐标4字节][y坐标4字节][方向角4字节][线速度4字节][角速度4字节][结束符"\n"1字节]
-
(2)ROS平台串口节点部分
1.写入串口 (1)内容:左右轮速度,单位为mm/s (2)格式:10字节,[右轮速度4字节][左轮速度4字节][结束符"\r\n"2字节] 2.读取串口 (1)内容:小车x,y坐标,方向角,线速度,角速度,单位依次为:mm,mm,rad,mm/s,rad/s (2)格式:21字节,[X坐标4字节][Y坐标4字节][方向角4字节][线速度4字节][角速度4字节][结束符"\n"1字节]
-
(1)小车底盘串口处理程序。
底盘串口处理的程序主要写在了 main.c 文件中。
底盘向串口发送里程计代码:
if(main_sta&0x01)//执行发送里程计数据步骤 {//里程计数据获取x_data.odoemtry_float=position_x;//单位mmy_data.odoemtry_float=position_y;//单位mmtheta_data.odoemtry_float=oriention;//单位radvel_linear.odoemtry_float=velocity_linear;//单位mm/svel_angular.odoemtry_float=velocity_angular;//单位rad/s//将所有里程计数据存到要发送的数组for(j=0;j<4;j++){odometry_data[j]=x_data.odometry_char[j];odometry_data[j+4]=y_data.odometry_char[j];odometry_data[j+8]=theta_data.odometry_char[j];odometry_data[j+12]=vel_linear.odometry_char[j];odometry_data[j+16]=vel_angular.odometry_char[j];}odometry_data[20]='\n';//添加结束符//发送数据要串口for(i=0;i<21;i++){USART_ClearFlag(USART1,USART_FLAG_TC); //在发送第一个数据前加此句,解决第一个数据不能正常发送的问题 USART_SendData(USART1,odometry_data[i]);//发送一个字节到串口 while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //等待发送结束 }main_sta&=0xFE;//执行计算里程计数据步骤 }
-
底盘接收串口发来的速度代码:
if(USART_RX_STA&0x8000) // 串口1接收函数 { //接收左右轮速度for(t=0;t<4;t++){rightdata.data[t]=USART_RX_BUF[t];leftdata.data[t]=USART_RX_BUF[t+4];}//储存左右轮速度odometry_right=rightdata.d;//单位mm/sodometry_left=leftdata.d;//单位mm/sUSART_RX_STA=0;//清楚接收标志位 }
-
(2)ROS平台串口处理程序
ROS平台串口处理程序主要写在 base_controller.cpp 文件中。
ROS平台向串口发送速度代码:
void callback(const geometry_msgs::Twist & cmd_input)//订阅/cmd_vel主题回调函数 {string port("/dev/ttyUSB0"); //小车串口号unsigned long baud = 115200; //小车串口波特率serial::Serial my_serial(port, baud, serial::Timeout::simpleTimeout(1000)); //配置串口angular_temp = cmd_input.angular.z ;//获取/cmd_vel的角速度,rad/slinear_temp = cmd_input.linear.x ;//获取/cmd_vel的线速度.m/s//将转换好的小车速度分量为左右轮速度left_speed_data.d = linear_temp - 0.5f*angular_temp*D ;right_speed_data.d = linear_temp + 0.5f*angular_temp*D ;//存入数据到要发布的左右轮速度消息left_speed_data.d*=ratio; //放大1000倍,mm/sright_speed_data.d*=ratio;//放大1000倍,mm/sfor(int i=0;i<4;i++) //将左右轮速度存入数组中发送给串口{speed_data[i]=right_speed_data.data[i];speed_data[i+4]=left_speed_data.data[i];}//在写入串口的左右轮速度数据后加入”/r/n“speed_data[8]=data_terminal0;speed_data[9]=data_terminal1;//写入数据到串口my_serial.write(speed_data,10); }
-
ROS平台接收串口发来的里程计代码:
rec_buffer =my_serial.readline(25,"\n"); //获取串口发送来的数据 const char *receive_data=rec_buffer.data(); //保存串口发送来的数据
2.串口通信处理程序
-
基于ROS平台的移动机器人-4-通过ROS利用键盘控制小车移动
准备工作
1.下载串口通信的ROS包
(1)cd ~/catkin_ws/src (2)git clone https://github.com/Forrest-Z/serial.git
-
2.下载键盘控制的ROS包
(1)cd ~/catkin_ws/src (2)git clone https://github.com/Forrest-Z/teleop_twist_keyboard.git
-
进入下载好的ROS包的文件夹,选中 keyboard_teleop_zbot.py ,右键>属性>权限>勾选 允许作为程序执行文件。
最后一步:(1)cd ~/catkin_ws(2)catkin_make
-
这样子我们的键盘控制包就能使用了。
3.新建 base_controller ROS 包
(1)cd ~/catkin_ws/src (2)catkin_create_pkg base_controller roscpp
-
在新建好的ROS包文件夹下新建一个“src”的文件夹,然后进入该文件夹,新建一个base_controller.cpp文件,将本博文最后提供的代码粘贴进去,然后修改一下 CMakeLists.txt :
第一处修改
find_package(catkin REQUIRED COMPONENTSroscpprospystd_msgsmessage_generationserialtfnav_msgs )
-
第二处修改
catkin_package( # INCLUDE_DIRS include # LIBRARIES base_controllerCATKIN_DEPENDS roscpp rospy std_msgs # DEPENDS system_lib )
-
第三处修改
include_directories(${catkin_INCLUDE_DIRS}${serial_INCLUDE_DIRS} )
-
第四处修改
add_executable(base_controller src/base_controller.cpp) target_link_libraries(base_controller ${catkin_LIBRARIES})
-
然后修改一下 package.xml :
<?xml version="1.0"?> <package><name>base_controller</name><version>0.0.0</version><description>The base_controller package</description> email="siat@todo.todo">siat</maintainer><license>TODO</license><!-- <test_depend>gtest</test_depend> --><buildtool_depend>catkin</buildtool_depend><build_depend>roscpp</build_depend><build_depend>rospy</build_depend><build_depend>std_msgs</build_depend><build_depend>message_generation</build_depend> <build_depend>tf</build_depend><build_depend>nav_msgs</build_depend> <run_depend>roscpp</run_depend><run_depend>rospy</run_depend><run_depend>std_msgs</run_depend><run_depend>message_runtime</run_depend> <run_depend>tf</run_depend><run_depend>nav_msgs</run_depend><!-- The export tag contains other, unspecified, tags --><export><!-- Other tools can request additional information be placed here --></export> </package>
-
控制原理
1.当我们按下键盘时,teleop_twist_keyboard 包会发布 /cmd_vel 主题发布速度
2.我们在 base_controller 节点订阅这个话题,接收速度数据,在转换成与底盘通信的格式,然后写入串口
3.我们在 base_controller 节点读取底盘向串口发来的里程计数据,然后进行处理再将里程计发布出去,同时更新tf
4.当小车底盘接收到串口发来的速度后,就控制电机运转,从而实现键盘控制小车的移动
运行
1.启动键盘节点
rosrun teleop_twist_keyboard teleop_twist_keyboard.py
-
2.启动小车底盘控制节点
rosrun base_controller base_controller
-
注意事项
1.我们在启动小车底盘控制节点时,有可以启动不了,大多数是因为串口的端口号不对,在 base_controller.cpp 文件里,我用的是”/dev/ttyUSB0”串口端口号
2.我们在启动启动小车底盘控制节点前,应该查看一下我们底盘的串口号是否正确,查看指令如下:
ls -l /dev |grep ttyUSB
-
如果运行后显示的端口号和我们程序中的一样,那就没问题,如果不一样,我们将程序的代码改动一下便可。
-
base_controller.cpp 完整代码:
-
/****************************************************************** 基于串口通信的ROS小车基础控制器,功能如下: 1.实现ros控制数据通过固定的格式和串口通信,从而达到控制小车的移动 2.订阅了/cmd_vel主题,只要向该主题发布消息,就能实现对控制小车的移动 3.发布里程计主题/odm串口通信说明: 1.写入串口 (1)内容:左右轮速度,单位为mm/s (2)格式:10字节,[右轮速度4字节][左轮速度4字节][结束符"\r\n"2字节] 2.读取串口 (1)内容:小车x,y坐标,方向角,线速度,角速度,单位依次为:mm,mm,rad,mm/s,rad/s (2)格式:21字节,[X坐标4字节][Y坐标4字节][方向角4字节][线速度4字节][角速度4字节][结束符"\n"1字节] *******************************************************************/ #include "ros/ros.h" //ros需要的头文件 #include <geometry_msgs/Twist.h> #include <tf/transform_broadcaster.h> #include <nav_msgs/Odometry.h> //以下为串口通讯需要的头文件 #include <string> #include <iostream> #include <cstdio> #include <unistd.h> #include <math.h> #include "serial/serial.h" /****************************************************************************/ using std::string; using std::exception; using std::cout; using std::cerr; using std::endl; using std::vector; /*****************************************************************************/ float ratio = 1000.0f ; //转速转换比例,执行速度调整比例 float D = 0.2680859f ; //两轮间距,单位是m float linear_temp=0,angular_temp=0;//暂存的线速度和角速度 /****************************************************/ unsigned char data_terminal0=0x0d; //“/r"字符 unsigned char data_terminal1=0x0a; //“/n"字符 unsigned char speed_data[10]={0}; //要发给串口的数据 string rec_buffer; //串口数据接收变量//发送给下位机的左右轮速度,里程计的坐标和方向 union floatData //union的作用为实现char数组和float之间的转换 {float d;unsigned char data[4]; }right_speed_data,left_speed_data,position_x,position_y,oriention,vel_linear,vel_angular; /************************************************************/ void callback(const geometry_msgs::Twist & cmd_input)//订阅/cmd_vel主题回调函数 {string port("/dev/ttyUSB0"); //小车串口号unsigned long baud = 115200; //小车串口波特率serial::Serial my_serial(port, baud, serial::Timeout::simpleTimeout(1000)); //配置串口angular_temp = cmd_input.angular.z ;//获取/cmd_vel的角速度,rad/slinear_temp = cmd_input.linear.x ;//获取/cmd_vel的线速度.m/s//将转换好的小车速度分量为左右轮速度left_speed_data.d = linear_temp - 0.5f*angular_temp*D ;right_speed_data.d = linear_temp + 0.5f*angular_temp*D ;//存入数据到要发布的左右轮速度消息left_speed_data.d*=ratio; //放大1000倍,mm/sright_speed_data.d*=ratio;//放大1000倍,mm/sfor(int i=0;i<4;i++) //将左右轮速度存入数组中发送给串口{speed_data[i]=right_speed_data.data[i];speed_data[i+4]=left_speed_data.data[i];}//在写入串口的左右轮速度数据后加入”/r/n“speed_data[8]=data_terminal0;speed_data[9]=data_terminal1;//写入数据到串口my_serial.write(speed_data,10); }int main(int argc, char **argv) {string port("/dev/ttyUSB0");//小车串口号unsigned long baud = 115200;//小车串口波特率serial::Serial my_serial(port, baud, serial::Timeout::simpleTimeout(1000));//配置串口ros::init(argc, argv, "base_controller");//初始化串口节点ros::NodeHandle n; //定义节点进程句柄ros::Subscriber sub = n.subscribe("cmd_vel", 20, callback); //订阅/cmd_vel主题ros::Publisher odom_pub= n.advertise<nav_msgs::Odometry>("odom", 20); //定义要发布/odom主题static tf::TransformBroadcaster odom_broadcaster;//定义tf对象geometry_msgs::TransformStamped odom_trans;//创建一个tf发布需要使用的TransformStamped类型消息nav_msgs::Odometry odom;//定义里程计对象geometry_msgs::Quaternion odom_quat; //四元数变量//定义covariance矩阵,作用为解决文职和速度的不同测量的不确定性float covariance[36] = {0.01, 0, 0, 0, 0, 0, // covariance on gps_x0, 0.01, 0, 0, 0, 0, // covariance on gps_y0, 0, 99999, 0, 0, 0, // covariance on gps_z0, 0, 0, 99999, 0, 0, // large covariance on rot x0, 0, 0, 0, 99999, 0, // large covariance on rot y0, 0, 0, 0, 0, 0.01}; // large covariance on rot z //载入covariance矩阵for(int i = 0; i < 36; i++){odom.pose.covariance[i] = covariance[i];;} ros::Rate loop_rate(10);//设置周期休眠时间while(ros::ok()){rec_buffer =my_serial.readline(25,"\n"); //获取串口发送来的数据const char *receive_data=rec_buffer.data(); //保存串口发送来的数据if(rec_buffer.length()==21) //串口接收的数据长度正确就处理并发布里程计数据消息{for(int i=0;i<4;i++)//提取X,Y坐标,方向,线速度,角速度{position_x.data[i]=receive_data[i];position_y.data[i]=receive_data[i+4];oriention.data[i]=receive_data[i+8];vel_linear.data[i]=receive_data[i+12];vel_angular.data[i]=receive_data[i+16];}//将X,Y坐标,线速度缩小1000倍position_x.d/=1000; //mposition_y.d/=1000; //mvel_linear.d/=1000; //m/s//里程计的偏航角需要转换成四元数才能发布odom_quat = tf::createQuaternionMsgFromYaw(oriention.d);//将偏航角转换成四元数//载入坐标(tf)变换时间戳odom_trans.header.stamp = ros::Time::now();//发布坐标变换的父子坐标系odom_trans.header.frame_id = "odom"; odom_trans.child_frame_id = "base_footprint"; //tf位置数据:x,y,z,方向odom_trans.transform.translation.x = position_x.d;odom_trans.transform.translation.y = position_y.d;odom_trans.transform.translation.z = 0.0;odom_trans.transform.rotation = odom_quat; //发布tf坐标变化odom_broadcaster.sendTransform(odom_trans);//载入里程计时间戳odom.header.stamp = ros::Time::now(); //里程计的父子坐标系odom.header.frame_id = "odom";odom.child_frame_id = "base_footprint"; //里程计位置数据:x,y,z,方向odom.pose.pose.position.x = position_x.d; odom.pose.pose.position.y = position_y.d;odom.pose.pose.position.z = 0.0;odom.pose.pose.orientation = odom_quat; //载入线速度和角速度odom.twist.twist.linear.x = vel_linear.d;//odom.twist.twist.linear.y = odom_vy;odom.twist.twist.angular.z = vel_angular.d; //发布里程计odom_pub.publish(odom);ros::spinOnce();//周期执行loop_rate.sleep();//周期休眠}//程序周期性调用//ros::spinOnce(); //callback函数必须处理所有问题时,才可以用到}return 0; }
-
基于ROS平台的移动机器人-5-Kinect2驱动的安装和ROS下的测试
说明
我们这里要测试的对象是Kinect2!!!
实物如图:
驱动安装
1.首先git下载代码,很快下载好,放到~下面
git clone https://github.com/OpenKinect/libfreenect2.git
-
2.然后安装依赖项如下,最好事先编译安装好OpenCV
sudo apt-get install build-essential cmake pkg-config libturbojpeg libjpeg-turbo8-dev mesa-common-dev freeglut3-dev libxrandr-dev libxi-dev
-
3.然后安装libusb。此处需要添加一个PPA
sudo apt-add-repository ppa:floe/libusb sudo apt-get update sudo apt-get install libusb-1.0-0-dev
-
4.接着运行下面的命令,安装GLFW3
sudo apt-get install libglfw3-dev
-
如果没有成功的话,使用下面的命令,来代替上面的
cd libfreenect2/depends sh install_ubuntu.sh sudo dpkg -i libglfw3*_3.0.4-1_*.deb
-
5.接着编译库
cd .. mkdir build && cd build cmake .. make sudo make install
-
6.测试
(1)需要把libfreenect2文件夹下面的rules里面的一个90开头的文件复制到/etc/udev/rules.d/下面
sudo cp ../platform/linux/udev/90-kinect2.rules /etc/udev/rules.d/
-
(2)插上kinect2,此时黄灯变成白色的,表示有驱动。注意:只能用于USB3的接口
(3)在中断进入刚才上面新建的build文件夹里的bin文件夹,运行:
./bin/Protonect
-
不出意外的话就可以看到显示的图像了。
ROS下测试
1.安装iai-kinect2 ROS包
cd ~/catkin_ws/src/ git clone https://github.com/code-iai/iai_kinect2.git cd iai_kinect2 rosdep install -r --from-paths . cd ~/catkin_ws catkin_make -DCMAKE_BUILD_TYPE="Release" rospack profile
-
2.测试
(1)启动kinect2驱动
roslaunch kinect2_bridge kinect2_bridge.launch
-
(2)启动显示界面
rosrun kinect2_viewer kinect2_viewer
-
如果能显示出画面的话就没问题了
注意事项
Kinect2只能用于USB3的接口!!!
-
基于ROS平台的移动机器人-6-使用Kinect2获取激光数据
ready
此教程我们将利用KinectV2在ROS平台上将KinectV2获得的深度图片转化为激光数据,以便我们下面的建图和导航。
go
1.我们这里需要一个将深度图转为激光数据的包
(1)cd ~/catkin_ws/src (2)git clone https://github.com/ros-perception/depthimage_to_laserscan.git
-
2.我这里新建了一个 bringup 的包来专门存放 launch 文件
(1)cd ~/catkin_ws/src (2)catkin_create_pkg bringup roscpp
-
3.在 bringup 包内我们新建一个 launch 文件夹 ,然后 在launch文件夹里添加
kinect2_depthimage_to_laserscan_rviz_view.launch
文件<launch><!-- start sensor--> <include file="$(find kinect2_bridge)/launch/kinect2_bridge.launch"><arg name="base_name" value="kinect2"/><arg name="sensor" value=""/><arg name="publish_tf" value="true"/><arg name="base_name_tf" value="kinect2"/><arg name="fps_limit" value="-1.0"/><arg name="calib_path" value="$(find kinect2_bridge)/data/"/><arg name="use_png" value="false"/><arg name="jpeg_quality" value="90"/><arg name="png_level" value="1"/><arg name="depth_method" value="default"/><arg name="depth_device" value="-1"/><arg name="reg_method" value="default"/><arg name="reg_device" value="-1"/><arg name="max_depth" value="12.0"/><arg name="min_depth" value="0.1"/><arg name="queue_size" value="5"/><arg name="bilateral_filter" value="true"/><arg name="edge_aware_filter" value="true"/><arg name="worker_threads" value="4"/></include> <!-- Run the depthimage_to_laserscan node --><node pkg="depthimage_to_laserscan" type="depthimage_to_laserscan" name="depthimage_to_laserscan" output="screen"><!--输入图像--><remap from="image" to="/kinect2/qhd/image_depth_rect"/><!--相关图像的相机信息。通常不需要重新变形,因为camera_info将从与图像相同的命名空间订阅。--><remap from="camera_info" to="/kinect2/qhd/camera_info" /><!--输出激光数据的话题--><remap from="scan" to="/scan" /> <!--激光扫描的帧id。对于来自具有Z向前的“光学”帧的点云,该值应该被设置为具有X向前和Z向上的相应帧。--><param name="output_frame_id" value="/kinect2_depth_frame"/><!--用于生成激光扫描的像素行数。对于每一列,扫描将返回在图像中垂直居中的那些像素的最小值。--><param name="scan_height" value="30"/><!--返回的最小范围(以米为单位)。小于该范围的输出将作为-Inf输出。--><param name="range_min" value="0.45"/><!--返回的最大范围(以米为单位)。大于此范围将输出为+ Inf。--><param name="range_max" value="8.00"/></node><!-- static_transform_publisher x y z yaw pitch roll frame_id child_frame_id period_in_ms --> <node pkg="tf" type="static_transform_publisher" name="base_footprint_to_base_link" args="0 0 0.5 0 0 0 base_footprint base_link 50" /><node pkg="tf" type="static_transform_publisher" name="base_link_to_laser" args="0 0 0.5 0 0 0 base_link laser 50" /><node pkg="tf" type="static_transform_publisher" name="base_link_to_kinect2laser" args="0 0 0.5 0 0 0 base_link kinect2_depth_frame 50" /><node pkg="tf" type="static_transform_publisher" name="base_link_to_kinect2_link" args="0 0 0.5 -1.57 0 -1.57 base_link kinect2_link 50" /><!--start rviz view --><node name="rviz" pkg="rviz" type="rviz" args="-d $(find bringup)/rviz/kinect2_depthimage_to_laserscan_view.rviz" /></launch>
-
4.在 bringup 包里新建 rviz 文件夹,然后在 rviz 文件夹里添加
kinect2_depthimage_to_laserscan_view.rviz
文件Panels:- Class: rviz/DisplaysHelp Height: 78Name: DisplaysProperty Tree Widget:Expanded:- /Global Options1- /Status1- /LaserScan1Splitter Ratio: 0.5Tree Height: 566- Class: rviz/SelectionName: Selection- Class: rviz/Tool PropertiesExpanded:- /2D Pose Estimate1- /2D Nav Goal1- /Publish Point1Name: Tool PropertiesSplitter Ratio: 0.588679- Class: rviz/ViewsExpanded:- /Current View1Name: ViewsSplitter Ratio: 0.5- Class: rviz/TimeExperimental: falseName: TimeSyncMode: 0SyncSource: LaserScan Visualization Manager:Class: ""Displays:- Alpha: 0.5Cell Size: 1Class: rviz/GridColor: 160; 160; 164Enabled: trueLine Style:Line Width: 0.03Value: LinesName: GridNormal Cell Count: 0Offset:X: 0Y: 0Z: 0Plane: XYPlane Cell Count: 10Reference Frame: <Fixed Frame>Value: true- Alpha: 1Autocompute Intensity Bounds: trueAutocompute Value Bounds:Max Value: 0Min Value: 0Value: trueAxis: ZChannel Name: intensityClass: rviz/LaserScanColor: 255; 255; 255Color Transformer: AxisColorDecay Time: 0Enabled: trueInvert Rainbow: falseMax Color: 255; 255; 255Max Intensity: 4096Min Color: 0; 0; 0Min Intensity: 0Name: LaserScanPosition Transformer: XYZQueue Size: 10Selectable: trueSize (Pixels): 3Size (m): 0.01Style: PointsTopic: /scanUnreliable: falseUse Fixed Frame: trueUse rainbow: trueValue: true- Class: rviz/TFEnabled: trueFrame Timeout: 15Frames:All Enabled: truebase_footprint:Value: truekinect2_depth_frame:Value: truekinect2_ir_optical_frame:Value: truekinect2_link:Value: truekinect2_rgb_optical_frame:Value: truelaser:Value: trueMarker Scale: 1Name: TFShow Arrows: trueShow Axes: trueShow Names: trueTree:base_footprint:kinect2_depth_frame:{}kinect2_link:kinect2_rgb_optical_frame:kinect2_ir_optical_frame:{}laser:{}Update Interval: 0Value: trueEnabled: trueGlobal Options:Background Color: 48; 48; 48Fixed Frame: laserFrame Rate: 30Name: rootTools:- Class: rviz/InteractHide Inactive Objects: true- Class: rviz/MoveCamera- Class: rviz/Select- Class: rviz/FocusCamera- Class: rviz/Measure- Class: rviz/SetInitialPoseTopic: /initialpose- Class: rviz/SetGoalTopic: /move_base_simple/goal- Class: rviz/PublishPointSingle click: trueTopic: /clicked_pointValue: trueViews:Current:Class: rviz/OrbitDistance: 10Enable Stereo Rendering:Stereo Eye Separation: 0.06Stereo Focal Distance: 1Swap Stereo Eyes: falseValue: falseFocal Point:X: 0Y: 0Z: 0Name: Current ViewNear Clip Distance: 0.01Pitch: 0.810398Target Frame: <Fixed Frame>Value: Orbit (rviz)Yaw: 3.2504Saved: ~ Window Geometry:Displays:collapsed: falseHeight: 846Hide Left Dock: falseHide Right Dock: trueQMainWindow State: 000000ff00000000fd00000004000000000000016a000002c4fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006100fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c0061007900730100000028000002c4000000d600fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002c4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a005600690065007700730000000028000002c4000000ac00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004b00000003efc0100000002fb0000000800540069006d00650100000000000004b0000002f600fffffffb0000000800540069006d0065010000000000000450000000000000000000000340000002c400000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000Selection:collapsed: falseTime:collapsed: falseTool Properties:collapsed: falseViews:collapsed: trueWidth: 1200X: 50Y: 45
-
5.基本工作我们都做完了,现在我们需要编译一下
(1)cd ~/catkin_ws (2)catkin_make (3)rospack profile
-
6.我们现在可以接上KinectV2(注意!!!接USB3.0口),执行
roslaunch bringup kinect2_depthimage_to_laserscan_rviz_view.launch
-
没有问题的话我们可以看到一下界面:
查看TF树:文件生成在主文件夹
rosrun tf view_frames
-
这是我的TF树
-
基于ROS平台的移动机器人-7-使用Kinect2建图
ready
此教程我将利用KinectV2得到的激光数据和Gmapping来建图(PS:这里你需要一个可以通过ROS控制的移动底盘和一个KinectV2)
go
1.安装Gmapping包
(1)cd ~/catkin_ws/src (2)git clone https://github.com/ros-perception/slam_gmapping.git (3)cd ~/catkin_ws (4)catkin_make (5)rospack profile
-
2.在我们之前的建的bringup/launch/下新建
kinect2_gmapping.launch
文件<?xml version="1.0"?><launch> <!-- start kinect2--> <include file="$(find kinect2_bridge)/launch/kinect2_bridge.launch"><arg name="base_name" value="kinect2"/><arg name="sensor" value=""/><arg name="publish_tf" value="true"/><arg name="base_name_tf" value="kinect2"/><arg name="fps_limit" value="-1.0"/><arg name="calib_path" value="$(find kinect2_bridge)/data/"/><arg name="use_png" value="false"/><arg name="jpeg_quality" value="90"/><arg name="png_level" value="1"/><arg name="depth_method" value="default"/><arg name="depth_device" value="-1"/><arg name="reg_method" value="default"/><arg name="reg_device" value="-1"/><arg name="max_depth" value="12.0"/><arg name="min_depth" value="0.1"/><arg name="queue_size" value="5"/><arg name="bilateral_filter" value="true"/><arg name="edge_aware_filter" value="true"/><arg name="worker_threads" value="4"/></include> <!-- Run the depthimage_to_laserscan node --><node pkg="depthimage_to_laserscan" type="depthimage_to_laserscan" name="depthimage_to_laserscan" output="screen"><!--输入图像--><remap from="image" to="/kinect2/qhd/image_depth_rect"/><!--相关图像的相机信息。通常不需要重新变形,因为camera_info将从与图像相同的命名空间订阅。--><remap from="camera_info" to="/kinect2/qhd/camera_info" /><!--输出激光数据的话题--><remap from="scan" to="/scan" /> <!--激光扫描的帧id。对于来自具有Z向前的“光学”帧的点云,该值应该被设置为具有X向前和Z向上的相应帧。--><param name="output_frame_id" value="/kinect2_depth_frame"/><!--用于生成激光扫描的像素行数。对于每一列,扫描将返回在图像中垂直居中的那些像素的最小值。--><param name="scan_height" value="30"/><!--返回的最小范围(以米为单位)。小于该范围的输出将作为-Inf输出。--><param name="range_min" value="0.45"/><!--返回的最大范围(以米为单位)。大于此范围将输出为+ Inf。--><param name="range_max" value="8.00"/></node><!--start gmapping node --><node pkg="gmapping" type="slam_gmapping" name="simple_gmapping" output="screen"><param name="map_update_interval" value="5.0"/> <param name="maxUrange" value="5.0"/> <param name="maxRange" value="6.0"/> <param name="sigma" value="0.05"/> <param name="kernelSize" value="1"/> <param name="lstep" value="0.05"/> <param name="astep" value="0.05"/> <param name="iterations" value="5"/> <param name="lsigma" value="0.075"/> <param name="ogain" value="3.0"/> <param name="lskip" value="0"/> <param name="minimumScore" value="50"/> <param name="srr" value="0.1"/> <param name="srt" value="0.2"/> <param name="str" value="0.1"/> <param name="stt" value="0.2"/> <param name="linearUpdate" value="1.0"/> <param name="angularUpdate" value="0.5"/> <param name="temporalUpdate" value="3.0"/> <param name="resampleThreshold" value="0.5"/> <param name="particles" value="50"/> <param name="xmin" value="-5.0"/> <param name="ymin" value="-5.0"/> <param name="xmax" value="5.0"/> <param name="ymax" value="5.0"/> <param name="delta" value="0.05"/> <param name="llsamplerange" value="0.01"/> <param name="llsamplestep" value="0.01"/> <param name="lasamplerange" value="0.005"/> <param name="lasamplestep" value="0.005"/> </node><!--start serial-port and odometry node--><node name="base_controller" pkg="base_controller" type="base_controller"/><!-- static_transform_publisher x y z yaw pitch roll frame_id child_frame_id period_in_ms --> <node pkg="tf" type="static_transform_publisher" name="base_footprint_to_base_link" args="0 0 0.5 0 0 0 base_footprint base_link 50" /><node pkg="tf" type="static_transform_publisher" name="base_link_to_laser" args="0 0 0.5 0 0 0 base_link laser 50" /><node pkg="tf" type="static_transform_publisher" name="base_link_to_kinect2laser" args="0 0 0.5 0 0 0 base_link kinect2_depth_frame 50" /><node pkg="tf" type="static_transform_publisher" name="base_link_to_kinect2_link" args="0 0 0.5 -1.57 0 -1.57 base_link kinect2_link 50" /></launch>
-
3.在我们之前的建的bringup/launch/下新建
kinect2_gmapping_rviz_view.launch
文件PS:我们这里不把启动RVIZ写在
kinect2_gmapping.launch
里是方便以后的远程启动<?xml version="1.0"?><launch><!--start rviz view --><node name="rviz" pkg="rviz" type="rviz" args="-d $(find bringup)/rviz/kinect2_gmapping.rviz" /></launch>
-
4.还有在新建bringup/rviz/下新建
kinect2_gmapping.rviz
文件Panels:- Class: rviz/DisplaysHelp Height: 78Name: DisplaysProperty Tree Widget:Expanded:- /Global Options1- /Status1- /Map1Splitter Ratio: 0.5Tree Height: 566- Class: rviz/SelectionName: Selection- Class: rviz/Tool PropertiesExpanded:- /2D Pose Estimate1- /2D Nav Goal1- /Publish Point1Name: Tool PropertiesSplitter Ratio: 0.588679- Class: rviz/ViewsExpanded:- /Current View1Name: ViewsSplitter Ratio: 0.5- Class: rviz/TimeExperimental: falseName: TimeSyncMode: 0SyncSource: LaserScan Visualization Manager:Class: ""Displays:- Alpha: 0.5Cell Size: 1Class: rviz/GridColor: 160; 160; 164Enabled: trueLine Style:Line Width: 0.03Value: LinesName: GridNormal Cell Count: 0Offset:X: 0Y: 0Z: 0Plane: XYPlane Cell Count: 10Reference Frame: <Fixed Frame>Value: true- Class: rviz/TFEnabled: trueFrame Timeout: 15Frames:All Enabled: truebase_footprint:Value: truebase_link:Value: truekinect2_depth_frame:Value: truekinect2_ir_optical_frame:Value: truekinect2_link:Value: truekinect2_rgb_optical_frame:Value: truelaser:Value: truemap:Value: trueodom:Value: trueMarker Scale: 1Name: TFShow Arrows: trueShow Axes: trueShow Names: trueTree:map:odom:base_footprint:base_link:kinect2_depth_frame:{}kinect2_link:kinect2_rgb_optical_frame:kinect2_ir_optical_frame:{}laser:{}Update Interval: 0Value: true- Alpha: 1Autocompute Intensity Bounds: trueAutocompute Value Bounds:Max Value: 1Min Value: 1Value: trueAxis: ZChannel Name: intensityClass: rviz/LaserScanColor: 255; 255; 255Color Transformer: AxisColorDecay Time: 0Enabled: trueInvert Rainbow: falseMax Color: 255; 255; 255Max Intensity: 4096Min Color: 0; 0; 0Min Intensity: 0Name: LaserScanPosition Transformer: XYZQueue Size: 10Selectable: trueSize (Pixels): 3Size (m): 0.01Style: Flat SquaresTopic: /scanUnreliable: falseUse Fixed Frame: trueUse rainbow: trueValue: true- Alpha: 0.7Class: rviz/MapColor Scheme: mapDraw Behind: falseEnabled: trueName: MapTopic: /mapUnreliable: falseValue: trueEnabled: trueGlobal Options:Background Color: 48; 48; 48Fixed Frame: odomFrame Rate: 30Name: rootTools:- Class: rviz/InteractHide Inactive Objects: true- Class: rviz/MoveCamera- Class: rviz/Select- Class: rviz/FocusCamera- Class: rviz/Measure- Class: rviz/SetInitialPoseTopic: /initialpose- Class: rviz/SetGoalTopic: /move_base_simple/goal- Class: rviz/PublishPointSingle click: trueTopic: /clicked_pointValue: trueViews:Current:Class: rviz/OrbitDistance: 70.1093Enable Stereo Rendering:Stereo Eye Separation: 0.06Stereo Focal Distance: 1Swap Stereo Eyes: falseValue: falseFocal Point:X: 3.9777Y: -3.7323Z: -7.60875Name: Current ViewNear Clip Distance: 0.01Pitch: 0.355398Target Frame: <Fixed Frame>Value: Orbit (rviz)Yaw: 0.0404091Saved: ~ Window Geometry:Displays:collapsed: falseHeight: 846Hide Left Dock: falseHide Right Dock: trueQMainWindow State: 000000ff00000000fd00000004000000000000016a000002c4fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006100fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c0061007900730100000028000002c4000000d600fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002c4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a005600690065007700730000000028000002c4000000ac00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004b00000003efc0100000002fb0000000800540069006d00650100000000000004b0000002f600fffffffb0000000800540069006d0065010000000000000450000000000000000000000340000002c400000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000Selection:collapsed: falseTime:collapsed: falseTool Properties:collapsed: falseViews:collapsed: trueWidth: 1200X: 50Y: 45
-
5.最后我们依次启动我们的launch文件便可
(1)roslaunch kinect2_gmapping.launch (2)roslaunch kinect2_gmapping_rviz_view.launch (3)rosrun teleop_twist_keyboard teleop_twist_keyboard.py
-
这样子我们就可以愉快的控制小车移动来建图了,当你建好图后运行一下指令就可以保存地图:
rosrun map_server map_saver -f mymap
-
地图保存在主文件夹,两个文件,mymap.pgm 和 mymap.yaml
这是我建好的图
6.最后看一波TF树
版权声明:本文为博主原创文章,如若转载,请标明作者和原文出处! https://blog.csdn.net/Forrest_Z/article/details/56666922
-
基于ROS平台的移动机器人-8-使用Kinect2导航
ready
终于到写最后一篇了。。。不是经常写博文的老司机果然伤不起!
在这一篇教程就是利用KinectV2来导航啦。go
1.安装一下所需的包
(1)cd ~/catkin_ws/src (2)git clone https://github.com/ros-planning/navigation.git (3)cd ~/catkin_ws (4)catkin_make (5)rospack profile
-
2.在我们之前的建的bringup/下,新建nav_config文件夹,然后新建四个文件
base_local_planner_params.yaml costmap_common_params.yaml global_costmap_params.yaml local_costmap_params.yaml
-
这四个文件主要用于导航配置
(1)
base_local_planner_params.yaml
文件controller_frequency: 2.0 recovery_behavior_enabled: false clearing_rotation_allowed: falseTrajectoryPlannerROS:max_vel_x: 0.3min_vel_x: 0.05max_vel_y: 0.0 # zero for a differential drive robotmin_vel_y: 0.0min_in_place_vel_theta: 0.5escape_vel: -0.1acc_lim_x: 2.5acc_lim_y: 0.0 # zero for a differential drive robotacc_lim_theta: 3.2holonomic_robot: falseyaw_goal_tolerance: 0.1 # about 6 degreesxy_goal_tolerance: 0.15 # 10 cmlatch_xy_goal_tolerance: falsepdist_scale: 0.8gdist_scale: 0.6meter_scoring: trueheading_lookahead: 0.325heading_scoring: falseheading_scoring_timestep: 0.8occdist_scale: 0.1oscillation_reset_dist: 0.05publish_cost_grid_pc: falseprune_plan: truesim_time: 2.5sim_granularity: 0.025angular_sim_granularity: 0.025vx_samples: 8vy_samples: 0 # zero for a differential drive robotvtheta_samples: 20dwa: truesimple_attractor: false
-
(2)
costmap_common_params.yaml
文件obstacle_range: 2.5 raytrace_range: 3.0 robot_radius: 0.30 inflation_radius: 0.15 max_obstacle_height: 0.6 min_obstacle_height: 0.0 observation_sources: scan scan: {data_type: LaserScan, topic: /scan, marking: true, clearing: true, expected_update_rate: 0}
-
(3)
global_costmap_params.yaml
文件global_costmap: global_frame: /map robot_base_frame: /base_link update_frequency: 1.0 publish_frequency: 0 static_map: true rolling_window: false resolution: 0.01 transform_tolerance: 0.5 map_type: costmap
-
(4)
local_costmap_params.yaml
文件local_costmap: global_frame: /odom robot_base_frame: /base_link update_frequency: 1.0 publish_frequency: 1.0 static_map: false rolling_window: true width: 6.0 height: 6.0 resolution: 0.01 transform_tolerance: 0.5 map_type: costmap
-
3.在我们之前的建的bringup/下,新建map文件夹,然后将之前建图生成的两个文件
mymap.pgm 和 mymap.yaml
移到map文件夹里,然后修改 mymap.yaml ,做如下修改:
将image这一行的改为你的mymap.pgm文件所在路径,如image: /home/forrest/catkin_ws/src/bringup/map/mymap.pgm
-
4.在我们之前的建的bringup/launch/下新建
kinect2_nav.launch
文件<launch> <!-- ×××××××××××××××××××××××××××××××××××××××××××× 华丽分割线 ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× --><param name="use_sim_time" value="false" /><!-- ×××××××××××××××××××××××××××××××××××××××××××× 华丽分割线 ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× --><!-- 启动kinect2驱动节点 --> <include file="$(find kinect2_bridge)/launch/kinect2_bridge.launch"><arg name="base_name" value="kinect2"/><arg name="sensor" value=""/><arg name="publish_tf" value="true"/><arg name="base_name_tf" value="kinect2"/><arg name="fps_limit" value="-1.0"/><arg name="calib_path" value="$(find kinect2_bridge)/data/"/><arg name="use_png" value="false"/><arg name="jpeg_quality" value="90"/><arg name="png_level" value="1"/><arg name="depth_method" value="default"/><arg name="depth_device" value="-1"/><arg name="reg_method" value="default"/><arg name="reg_device" value="-1"/><arg name="max_depth" value="12.0"/><arg name="min_depth" value="0.1"/><arg name="queue_size" value="5"/><arg name="bilateral_filter" value="true"/><arg name="edge_aware_filter" value="true"/><arg name="worker_threads" value="4"/></include> <!-- 启动深度图转换激光数据节点 --><node pkg="depthimage_to_laserscan" type="depthimage_to_laserscan" name="depthimage_to_laserscan" output="screen"><!--输入图像--><remap from="image" to="/kinect2/qhd/image_depth_rect"/><!--相关图像的相机信息。通常不需要重新变形,因为camera_info将从与图像相同的命名空间订阅。--><remap from="camera_info" to="/kinect2/qhd/camera_info" /><!--输出激光数据的话题--><remap from="scan" to="/scan" /> <!--激光扫描的帧id。对于来自具有Z向前的“光学”帧的点云,该值应该被设置为具有X向前和Z向上的相应帧。--><param name="output_frame_id" value="/kinect2_depth_frame"/><!--用于生成激光扫描的像素行数。对于每一列,扫描将返回在图像中垂直居中的那些像素的最小值。--><param name="scan_height" value="30"/><!--返回的最小范围(以米为单位)。小于该范围的输出将作为-Inf输出。--><param name="range_min" value="0.45"/><!--返回的最大范围(以米为单位)。大于此范围将输出为+ Inf。--><param name="range_max" value="8.00"/></node><!-- ×××××××××××××××××××××××××××××××××××××××××××× 华丽分割线 ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× --><!-- 启动地图服务器载入地图 --><node name="map_server" pkg="map_server" type="map_server" args="$(find bringup)/map/mymap.yaml"/><!-- ×××××××××××××××××××××××××××××××××××××××××××× 华丽分割线 ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× --><!-- 启动 move_base 节点 --><node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen" clear_params="true"><rosparam file="$(find bringup)/nav_config/costmap_common_params.yaml" command="load" ns="global_costmap" /><rosparam file="$(find bringup)/nav_config/costmap_common_params.yaml" command="load" ns="local_costmap" /><rosparam file="$(find bringup)/nav_config/local_costmap_params.yaml" command="load" /><rosparam file="$(find bringup)/nav_config/global_costmap_params.yaml" command="load" /><rosparam file="$(find bringup)/nav_config/base_local_planner_params.yaml" command="load" /><!-- <rosparam file="$(find odom_tf_package)/config/nav_obstacles_params.yaml" command="load" /> --></node><!-- ×××××××××××××××××××××××××××××××××××××××××××× 华丽分割线 ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× --> <!-- 启动 AMCL 节点 --><node pkg="amcl" type="amcl" name="amcl" clear_params="true"><param name="use_map_topic" value="false"/><!-- Publish scans from best pose at a max of 10 Hz --><param name="odom_model_type" value="diff"/><param name="odom_alpha5" value="0.1"/><param name="gui_publish_rate" value="10.0"/><param name="laser_max_beams" value="60"/><param name="laser_max_range" value="12.0"/><param name="min_particles" value="500"/><param name="max_particles" value="2000"/><param name="kld_err" value="0.05"/><param name="kld_z" value="0.99"/><param name="odom_alpha1" value="0.2"/><param name="odom_alpha2" value="0.2"/><!-- translation std dev, m --><param name="odom_alpha3" value="0.2"/><param name="odom_alpha4" value="0.2"/><param name="laser_z_hit" value="0.5"/><param name="laser_z_short" value="0.05"/><param name="laser_z_max" value="0.05"/><param name="laser_z_rand" value="0.5"/><param name="laser_sigma_hit" value="0.2"/><param name="laser_lambda_short" value="0.1"/><param name="laser_model_type" value="likelihood_field"/><!-- <param name="laser_model_type" value="beam"/> --><param name="laser_likelihood_max_dist" value="2.0"/><param name="update_min_d" value="0.25"/><param name="update_min_a" value="0.2"/><param name="odom_frame_id" value="odom"/><param name="resample_interval" value="1"/><!-- Increase tolerance because the computer can get quite busy --><param name="transform_tolerance" value="1.0"/><param name="recovery_alpha_slow" value="0.0"/><param name="recovery_alpha_fast" value="0.0"/><!-- scan topic --><remap from="scan" to="scan"/></node><!-- ×××××××××××××××××××××××××××××××××××××××××××× 华丽分割线 ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× --><!-- 启动基础控制器节点:发布里程计,控制小车 --><node name="base_controller" pkg="base_controller" type="base_controller"/><!-- ×××××××××××××××××××××××××××××××××××××××××××× 华丽分割线 ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× --><!-- tf 转换 --><!-- static_transform_publisher x y z yaw pitch roll frame_id child_frame_id period_in_ms --> <node pkg="tf" type="static_transform_publisher" name="base_footprint_to_base_link" args="0 0 0.5 0 0 0 base_footprint base_link 50" /><node pkg="tf" type="static_transform_publisher" name="base_link_to_laser" args="0 0 0.5 0 0 0 base_link laser 50" /><node pkg="tf" type="static_transform_publisher" name="base_link_to_kinect2laser" args="0 0 0.5 0 0 0 base_link kinect2_depth_frame 50" /><node pkg="tf" type="static_transform_publisher" name="base_link_to_kinect2_link" args="0 0 0.5 -1.57 0 -1.57 base_link kinect2_link 50" /><!-- ×××××××××××××××××××××××××××××××××××××××××××× 华丽分割线 ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× --> </launch>
-
5.在我们之前的建的bringup/launch/下新建
kinect2_nav_rviz_view.launch
文件<?xml version="1.0"?><launch><!--start rviz view --><node name="rviz" pkg="rviz" type="rviz" args="-d $(find bringup)/rviz/kinect2_nav.rviz" /></launch>
-
6.还有在新建bringup/rviz/下新建
kinect2_nav.rviz
文件Panels:- Class: rviz/DisplaysHelp Height: 78Name: DisplaysProperty Tree Widget:Expanded:- /Global Options1- /Odometry1- /RobotModel1/Links1/base_footprint1- /Marker1/Namespaces1Splitter Ratio: 0.652661Tree Height: 457- Class: rviz/SelectionName: Selection- Class: rviz/Tool PropertiesExpanded:- /2D Pose Estimate1- /2D Nav Goal1Name: Tool PropertiesSplitter Ratio: 0.428571- Class: rviz/ViewsExpanded:- /Current View1Name: ViewsSplitter Ratio: 0.5- Class: rviz/TimeExperimental: falseName: TimeSyncMode: 0SyncSource: "" Visualization Manager:Class: ""Displays:- Alpha: 0.5Cell Size: 0.5Class: rviz/GridColor: 160; 160; 164Enabled: trueLine Style:Line Width: 0.03Value: LinesName: GridNormal Cell Count: 0Offset:X: 0Y: 0Z: 0Plane: XYPlane Cell Count: 80Reference Frame: odomValue: true- Angle Tolerance: 0.1Class: rviz/OdometryColor: 221; 200; 14Enabled: trueKeep: 100Length: 0.6Name: OdometryPosition Tolerance: 0.1Topic: /odomValue: true- Angle Tolerance: 0.1Class: rviz/OdometryColor: 255; 85; 0Enabled: falseKeep: 100Length: 0.6Name: Odometry EKFPosition Tolerance: 0.1Topic: /odom_ekfValue: false- Alpha: 1Class: rviz/RobotModelCollision Enabled: falseEnabled: trueLinks:All Links Enabled: trueExpand Joint Details: falseExpand Link Details: falseExpand Tree: falseLink Tree Style: Links in Alphabetic Orderbase_footprint:Alpha: 1Show Axes: falseShow Trail: falseValue: truebase_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truecamera_depth_frame:Alpha: 1Show Axes: falseShow Trail: falsecamera_depth_optical_frame:Alpha: 1Show Axes: falseShow Trail: falsecamera_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truecamera_rgb_frame:Alpha: 1Show Axes: falseShow Trail: falsecamera_rgb_optical_frame:Alpha: 1Show Axes: falseShow Trail: falsefront_wheel_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truegyro_link:Alpha: 1Show Axes: falseShow Trail: falselaser:Alpha: 1Show Axes: falseShow Trail: falseValue: trueleft_cliff_sensor_link:Alpha: 1Show Axes: falseShow Trail: falseleft_wheel_link:Alpha: 1Show Axes: falseShow Trail: falseValue: trueleftfront_cliff_sensor_link:Alpha: 1Show Axes: falseShow Trail: falseplate_0_link:Alpha: 1Show Axes: falseShow Trail: falseValue: trueplate_1_link:Alpha: 1Show Axes: falseShow Trail: falseValue: trueplate_2_link:Alpha: 1Show Axes: falseShow Trail: falseValue: trueplate_3_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truerear_wheel_link:Alpha: 1Show Axes: falseShow Trail: falseValue: trueright_cliff_sensor_link:Alpha: 1Show Axes: falseShow Trail: falseright_wheel_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truerightfront_cliff_sensor_link:Alpha: 1Show Axes: falseShow Trail: falsespacer_0_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truespacer_1_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truespacer_2_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truespacer_3_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truestandoff_2in_0_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truestandoff_2in_1_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truestandoff_2in_2_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truestandoff_2in_3_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truestandoff_2in_4_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truestandoff_2in_5_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truestandoff_2in_6_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truestandoff_2in_7_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truestandoff_8in_0_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truestandoff_8in_1_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truestandoff_8in_2_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truestandoff_8in_3_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truestandoff_kinect_0_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truestandoff_kinect_1_link:Alpha: 1Show Axes: falseShow Trail: falseValue: truewall_sensor_link:Alpha: 1Show Axes: falseShow Trail: falseName: RobotModelRobot Description: robot_descriptionTF Prefix: ""Update Interval: 0Value: trueVisual Enabled: true- Alpha: 0.2Class: rviz/MapColor Scheme: mapDraw Behind: trueEnabled: trueName: MapTopic: /mapValue: true- Alpha: 1Buffer Length: 1Class: rviz/PathColor: 255; 0; 0Enabled: trueName: Local PlanTopic: /move_base/TrajectoryPlannerROS/local_planValue: true- Alpha: 1Buffer Length: 1Class: rviz/PathColor: 0; 213; 0Enabled: trueName: Global PlanTopic: /move_base/TrajectoryPlannerROS/global_planValue: true- Class: rviz/MarkerEnabled: trueMarker Topic: /waypoint_markersName: MarkerNamespaces:{}Queue Size: 100Value: true- Alpha: 1Autocompute Intensity Bounds: trueAutocompute Value Bounds:Max Value: 0.304Min Value: 0.304Value: trueAxis: ZChannel Name: intensityClass: rviz/LaserScanColor: 255; 255; 255Color Transformer: FlatColorDecay Time: 0Enabled: trueInvert Rainbow: falseMax Color: 255; 255; 255Max Intensity: 4096Min Color: 0; 0; 0Min Intensity: 0Name: LaserScanPosition Transformer: XYZQueue Size: 10Selectable: trueSize (Pixels): 3Size (m): 0.01Style: SpheresTopic: /scanUse Fixed Frame: trueUse rainbow: trueValue: true- Alpha: 1Axes Length: 1Axes Radius: 0.1Class: rviz/PoseColor: 0; 255; 0Enabled: trueHead Length: 0.1Head Radius: 0.15Name: Mouse GoalShaft Length: 0.5Shaft Radius: 0.03Shape: ArrowTopic: /move_base/current_goalValue: true- Alpha: 1Axes Length: 1Axes Radius: 0.1Class: rviz/PoseColor: 0; 255; 0Enabled: trueHead Length: 0.1Head Radius: 0.15Name: Goal PoseShaft Length: 0.5Shaft Radius: 0.03Shape: ArrowTopic: /move_base_simple/goalValue: true- Arrow Length: 0.3Class: rviz/PoseArrayColor: 255; 25; 0Enabled: falseName: Pose ArrayTopic: ""Value: falseEnabled: trueGlobal Options:Background Color: 0; 0; 0Fixed Frame: mapFrame Rate: 30Name: rootTools:- Class: rviz/MoveCamera- Class: rviz/InteractHide Inactive Objects: true- Class: rviz/Select- Class: rviz/SetInitialPoseTopic: /initialpose- Class: rviz/SetGoalTopic: /move_base_simple/goalValue: trueViews:Current:Angle: -1.57Class: rviz/TopDownOrthoName: Current ViewNear Clip Distance: 0.01Scale: 205.257Target Frame: <Fixed Frame>Value: TopDownOrtho (rviz)X: 0.755064Y: 0.634474Saved: ~ Window Geometry:Displays:collapsed: falseHeight: 695Hide Left Dock: falseHide Right Dock: falseQMainWindow State: 000000ff00000000fd00000004000000000000012d00000258fc0200000005fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006400fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000198000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000004100000258000000dd00ffffff000000010000010f00000270fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000002800000270000000b000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004a00000003efc0100000002fb0000000800540069006d00650000000000000004a0000002f600fffffffb0000000800540069006d00650100000000000004500000000000000000000002b80000025800000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000Selection:collapsed: falseTime:collapsed: falseTool Properties:collapsed: falseViews:collapsed: falseWidth: 1003X: 787Y: 348
-
7.最后我们依次启动我们的launch文件便可进行导航
(1)roslaunch kinect2_nav.launch (2)roslaunch kinect2_nav_rviz_view.launch
-
启动成功的话会看到一下画面:
如果rviz显示的机器人位置和实际机器人所处的位置不一样,我们可以根据机器人实际所处的位置在rviz上初始化机器人在地图上的位置
方法为点击rviz界面上方的2D Pose Estimate ,然后点击地图,确定机器人所在位置
最后一步就是给机器人定个目的地让它行驶到那里,
方法为点击rviz界面上方的2D Nav Goal , 然后点击地图上的某个位置,这样子就可以看到机器人开始向目标移动啦!
版权声明:本文为博主原创文章,如若转载,请标明作者和原文出处! https://blog.csdn.net/Forrest_Z/article/details/56670514
-
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- OpenGL--纹理2
目录(?)[] 原始图像数据 像素包装 图像数据在内存中很少以紧密包装的形式存在。在许多硬件平台上,处于性能上的考虑,一幅图像的每一行都应该从一种特定字节对齐地址开始。绝大多数编译器会自动把变量和缓冲区放置在一个针对该架构对齐优化的地址上。 例…...
2024/4/20 18:55:26 - 福州 总院 北京双眼皮王勋
...
2024/4/20 18:55:25 - 前端面经2
1.flex弹性布局 (1)水平居中用哪个属性做的? display:flex; justify-content: center; align-items: center;(2)flex的轴默认是水平还是垂直? flex的轴默认水平 2.transition和animation区别࿱…...
2024/4/21 7:07:48 - angular js 在ie11 下的get请求缓存问题的解决办法
使用angularjs 1.x开发的应用在ie11 下回碰到各种怪异的情况:一般表现在:卡,慢,丑。 还有另外一种情况,就是:get请求被缓存,导致页面数据没有刷新。今天我们就来解决这个问题。 几行代码&#x…...
2024/4/24 15:49:56 - 第一医院双眼皮图片
...
2024/4/21 7:07:47 - 高云之双眼皮怎么样
...
2024/4/21 7:07:45 - [Angular] - 01 Architecture and workflow
阅读体验更佳 :https://github.com/youhengchan/angular-notes/blob/master/angular-01-Architecture-and-%20workflow.md [Angular] - 01 Architecture and workflow by youhengchan Overview The architecture of Angular will be an app contains one more modu…...
2024/4/21 7:07:45 - Angular和用户身份验证入门
本文最初发布在OKTA开发人员博客上 。 感谢您支持使SitePoint成为可能的合作伙伴。 AngularJS多年来一直是JavaScript MVC框架之王。 但是,当Angular团队宣布将不提供其下一版本的向后兼容性时,其社区引起了一些轰动,这为React和Vue.js之类的…...
2024/4/21 7:07:44 - 基础美双眼皮 徐洋
...
2024/5/6 17:17:27 - 双眼皮手术 睫毛翘度不一样
...
2024/4/21 7:07:41 - Angular学习笔记-angular是如何执行的
angular执行图:jquery启动: js dom元素绑定相应的事件,当dom监听到相应的事件,这时就开始执行注册的这个事件.angularjs执行:首先,绑定jquery,判断是否引入jquery,如果没有引入jquery,自己会实现一个jqlit。…...
2024/5/2 17:07:00 - 切双眼皮14天上睫毛外反
...
2024/4/21 7:07:40 - angular常用directive,身份证号码,倒计时按钮,重复值,input后端校验
/** * Created by jing on 14-11-4. */angular.module(app) .directive(jingIdCard, function () { /** * 身份证号码验证 * * param cardNo * {String} 证件号码 * returns info {Object} 身份证信息. * */ var getIdCardInfo …...
2024/5/6 14:10:46 - 基于Angular-animate.js和css实现的轮播图
最近在学习angularJS和foundation进行前端开发, 需要一款轮播图.简单做了一个,能够进行无缝轮播,带有滑动效果,点击上/下一张时从新开始定时器轮播的功能. 首先进行外部文件的引用: <link rel"stylesheet" type"text/css" href"http://cdn.bootcs…...
2024/5/6 15:43:16 - angularjs对象
//判断是否是个数组 angular.isArray([])//true angular.isArray("strings")//false //判断是否是个日期对象 var a angular.isDate(new Date());//true //判断一个值是否被定义 angular.isDefined(undefined);//false angular.isDefined([])//true …...
2024/5/6 16:55:32 - MyBatis 返回动态结果类型插件
MyBatis 返回动态结果类型插件说明虽然写了这么一个插件,但是个人建议尽可能不去这么用,如果这个插件真正能方便你,使用起来也没任何问题。关于插件的一些个人修改建议,在插件的注释中有说明。插件用途:可以在 MyBatis 参数中带上要返回的类型Class,插件就会改变返回值类…...
2024/5/6 7:37:11 - Angular 学习系列 - - Angular数据类型判断
angular.isArray 判断括号内的值是否为数组。 格式:angular.isArray(value); value: 被判断是否为数组的值。 --------------------------------------------------------------- angular.isDate 判断括号内的值是否是一个时间。 格式:angular.isDate(va…...
2024/5/8 8:48:50 - 双眼皮眼睑外翻能好么
...
2024/4/21 7:07:33 - 简单的下拉多选angularjs 实现
因为在工作中需要用到下拉多选的组件,查了一些资料,觉得有些组件挺复杂的,而我只要实现基本的功能,所以结合需求和资料,自己整合了一下,下面是完整的代码实现 (function ( angular ) {use strict;angular.…...
2024/4/20 4:22:09 - angularjs中常见的工具方法
angular自身封装了一些很好用的方法,比如最常用的angular.clone()。总结了一些常用的方法,欢迎补充。 angular.clone() 用于深度复制对象 var cloneObjangular.clone(obj); angular.bind() function show(){alert(this"调用了show") }var…...
2024/4/20 18:55:31
最新文章
- 大语言模型LLM入门篇
大模型席卷全球,彷佛得模型者得天下。对于IT行业来说,以后可能没有各种软件了,只有各种各样的智体(Agent)调用各种各样的API。在这种大势下,笔者也阅读了很多大模型相关的资料,和很多新手一样&a…...
2024/5/8 17:00:42 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/5/7 10:36:02 - A股企业数据要素利用水平数据集(2001-2022年)
参照史青春(2023)的做法,团队对上市公司-数据要素利用水平进行测算。统计人工智能技术、区块链技术、云计算技术、大数据技术、大数据技术应用五项指标在企业年报中的披露次数,求和后衡量数据要素投入水平。 一、数据介绍 数据名…...
2024/5/7 15:39:36 - 《c++》多态案例一.电脑组装
一.代码展示 #include <iostream> using namespace std; class CPU { public://抽象计算函数virtual void calculate() 0;};class CVideoCard { public://抽象显示函数virtual void display() 0;}; class Memory { public://抽象存储函数virtual void storage() 0;};…...
2024/5/5 8:48:19 - Vue3学习笔记+报错记录
文章目录 1.创建Vue3.0工程1.1使用vue-cli创建1.2 使用vite创建工程1.3.分析Vue3工程结构 2.常用Composition2.1 拉开序幕的setup2.2 ref函数_处理基本类型2.3 ref函数_处理对象类型2.4 ref函数使用总结 1.创建Vue3.0工程 1.1使用vue-cli创建 查看vue/cli版本,确保…...
2024/5/8 9:55:54 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/5/8 6:01:22 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/5/7 9:45:25 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到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/7 14:25:14 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
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/7 11:36:39 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和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/7 9:26:26 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
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/6 21:42:42 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含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