智能实训-wheeltec小车-抓取(源代码)

语言 :C

源代码:

#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <sensor_msgs/JointState.h>
#include <geometry_msgs/Twist.h>
#include <nav_msgs/Odometry.h>#include </usr/include/opencv2/highgui/highgui_c.h> //树莓派(Raspberry)、工控机(IPC)、虚拟机
//#include </usr/include/opencv4/opencv2/highgui/highgui_c.h> //jetson Nano/NX/TX2
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>#include <dynamic_reconfigure/server.h>
#include <stepper_arm/arm_color_block_paramsConfig.h>#include <pthread.h>
#include <arm_2_control.h>using namespace std;
using namespace cv;//ROS图片话题
string rgb_image_topic;
//opencv图片对象
Mat image, HSV_image, final_image;
//ROS里程计话题
string odom_topic;/****可以使用rqt动态调参的变量****/
//抓取色块标志位
int Pick_start=false;
double car_search_distance_max=3;
//机械臂初始位置
double grab_start_jointA = 1.570796;
double grab_start_position_x = 0.062;
double grab_start_position_y =-0.008;
//机械臂结束位置
double grab_end_jointA = -1.570796;
double grab_end_position_x = 0.062;
double grab_end_position_y = 0.062;//机械爪初始张开程度
double hand_open_size=-0.7; 
//机械爪抓取色块夹紧程度
double hand_close_size=0.5; 
//色块识别阈值
int color=0;//0:dynamic, 1:green, 2:blue, 3:yellow. 4:red
int dynamic_hsv[6]={0,  0,   0,   0,   0,   0  }; //[h_min, s_min, v_min, h_max, s_max, v_max]
int green_hsv  [6]={60, 35,  0,   80,  180, 255}; //[h_min, s_min, v_min, h_max, s_max, v_max]
int blue_hsv   [6]={80, 90,  100, 130, 200, 255}; //[h_min, s_min, v_min, h_max, s_max, v_max]
int yellow_hsv [6]={15, 110, 30,  50,  255, 255}; //[h_min, s_min, v_min, h_max, s_max, v_max]
int red_hsv    [6]={0,  100, 53,  18,  223, 255}; //[h_min, s_min, v_min, h_max, s_max, v_max]
//膨胀腐蚀大小
int dilate_erode_size=7;
//期望识别到的目标的面积的大小,代表距离。因为RGB相机没有深度信息,只能在已知目标大小的情况下,通过判断面积大小计算近似距离(近大远小)
double target_areaSize=22000; 
//期望色块位于画面中心向上偏移多少像素点
double target_y_bias=0; 
//寻找色块时小车的转速
double car_search_turn=0.1;
double car_search_foward=0.1;
//抓取色块时机械臂的运动限幅参数,前进后退、上升下降、左转右转
float Move_step_max=0.4, Turn_step_max=0.2;
float Move_step_min=0.0005, Turn_step_min=0.0005;
//抓取色块时机械臂运动靠近色块的PID参数
double turn_KP=0.05,   turn_KD=0;
double down_KP=0.01,   down_KD=0;
double foward_KP=0.01, foward_KD=0;
//寻找色块时小车的运动参数,
double Car_foward_KP;
/****可以使用rqt动态调参的变量****///机械臂小车寻找抓取色块的相关变量
double area;
double distance_bias, x_bias, y_bias;
double last_distance_bias, last_x_bias, last_y_bias;
double distance_step=0, x_step=0, y_step=0;
double foward_step, down_step;
double Car_foward_velocity, Car_turn_velocity;
bool foward_forb=false;
//机械臂小车寻找抓取色块过程中的各个状态变量
bool Car_stop=false, car_turn_locked=false, Arm_stop=true;
bool hand_on_color=false, arm_turn_locked=false, arm_locked=false, hand_closed=false;
int Car_turn_times=0;
//小车里程计,用于寻找色块功能
double odom_foward, odom_lateral, odom_turn;
//机械臂时间状态变量
ros::Time arm_position_move_time, arm_locked_time, hand_closed_time;//rqt动态调参函数
void dynamic_reconfigure_callback(stepper_arm::arm_color_block_paramsConfig &config, uint32_t level);
//获取摄像头图像后的处理函数,主要功能实现在这里
void rgb_image_Callback(const sensor_msgs::ImageConstPtr& msg);
//获得小车里程计
void odom_Callback(const nav_msgs::Odometry& msg);
//opencv进度条调阈值回调函数,放弃使用,改由rqt调动态阈值
void on_trackbar(int, void*) {}/**************************************************************************
Function: The main function
Input   : none
Output  : 无
函数功能: 主函数
入口参数: 无
返回  值: 无
**************************************************************************/
int main(int argc, char **argv)
{ros::init(argc,argv,"arm_2_auto_pick_colorBlock"); //初始化节点ros::AsyncSpinner spinner(1); spinner.start();ros::NodeHandle NodeHandle; //创建节点句柄//关节B默认角度(相对X轴,逆时针为正)NodeHandle.param<double>("Angle_B_bias",    Angle_B_bias,    1.571);//关节C默认角度(相对关节B,逆时针为正)NodeHandle.param<double>("Angle_C_bias",    Angle_C_bias,    0.384);//机械臂底座到地面的距离NodeHandle.param<double>("arm_base_height", arm_base_height, 0);//图片话题名NodeHandle.param<string>("rgb_image_topic", rgb_image_topic, "/usb_cam/image_raw");//里程计话题名NodeHandle.param<string>("odom_topic",      odom_topic,      "/odom");//摄像头图片话题订阅者,用于识别抓取色块ros::Subscriber rgb_image_Sub; rgb_image_Sub   = NodeHandle.subscribe(rgb_image_topic, 20, &rgb_image_Callback);//机械臂关节姿态信息发布者,用于控制机械臂ros::Publisher Arm_2_JointStates_Pub;Arm_2_JointStates_Pub = NodeHandle.advertise<sensor_msgs::JointState>("Arm_2_JointStates", 10);//速度命令话题发布者,用于控制小车运动寻找色块ros::Publisher cmd_vel_Pub;cmd_vel_Pub = NodeHandle.advertise<geometry_msgs::Twist>("cmd_vel_ori", 10);//里程计话题订阅者,用于识别抓取色块ros::Subscriber odom_Sub; odom_Sub   = NodeHandle.subscribe(odom_topic, 20, &odom_Callback);//动态调参初始化,用于控制抓取色块、改变目标色块颜色dynamic_reconfigure::Server<stepper_arm::arm_color_block_paramsConfig> server;dynamic_reconfigure::Server<stepper_arm::arm_color_block_paramsConfig>::CallbackType f;f = boost::bind(&dynamic_reconfigure_callback, _1, _2);server.setCallback(f);Joint_A=grab_start_jointA;ArmC_End_Position_X=grab_start_position_x;ArmC_End_Position_Y=grab_start_position_y;Joint_Hand_left1  =  hand_open_size, Joint_Hand_left2  =  hand_open_size, Joint_Hand_right1 = -hand_open_size, Joint_Hand_right2 = -hand_open_size;arm_2_inverse_solution(ArmC_End_Position_X, ArmC_End_Position_Y, Joint_B, Joint_C);ros::Rate loopRate(70);//频率70Hzwhile(ros::ok()){//发布机械臂关节姿态信息,用于控制机械臂sensor_msgs::JointState Arm_2_JointStates;Arm_2_JointStates.position.push_back(Joint_A);//减去Angle_B_bias是因为moveit的关节初始位置为0Arm_2_JointStates.position.push_back(Joint_B-Angle_B_bias);//减去Angle_C_bias是因为moveit的关节初始位置为0Arm_2_JointStates.position.push_back(Joint_C-Angle_C_bias);Arm_2_JointStates.position.push_back(Joint_End);Arm_2_JointStates.position.push_back(Joint_Hand_left1);Arm_2_JointStates.position.push_back(Joint_Hand_left2);Arm_2_JointStates.position.push_back(Joint_Hand_right1);Arm_2_JointStates.position.push_back(Joint_Hand_right2);Arm_2_JointStates.position.push_back(Joint_Grasper);Arm_2_JointStates_Pub.publish(Arm_2_JointStates);   //发布速度命令话题,用于控制小车运动寻找色块geometry_msgs::Twist cmd_vel;cmd_vel.linear.x =Car_foward_velocity;cmd_vel.linear.y =0;cmd_vel.linear.z =0;cmd_vel.angular.x=0;cmd_vel.angular.y=0;cmd_vel.angular.z=Car_turn_velocity;cmd_vel_Pub.publish(cmd_vel); ros::spinOnce();loopRate.sleep();} return 0;
}/**************************************************************************
Function: rqt dynamically calls the parameter callback function
Input   : none
Output  : none
函数功能: rqt动态调参回调函数
入口参数: 动态调参对象,
返回  值: 无
**************************************************************************/
void dynamic_reconfigure_callback(stepper_arm::arm_color_block_paramsConfig &config, uint32_t level)
{Pick_start=config.Pick_start;car_search_distance_max=config.car_search_distance_max;grab_start_jointA=config.grab_start_jointA;grab_start_position_x=config.grab_start_position_x;grab_start_position_y=config.grab_start_position_y;grab_end_jointA=config.grab_end_jointA;grab_end_position_x=config.grab_end_position_x;grab_end_position_y=config.grab_end_position_y;hand_open_size=config.hand_open_size;hand_close_size=config.hand_close_size;color=config.color;//使用ROS的rqt工具进行动态调阈值dynamic_hsv[0]=config.HSV_H_MIN;dynamic_hsv[1]=config.HSV_S_MIN;dynamic_hsv[2]=config.HSV_V_MIN;dynamic_hsv[3]=config.HSV_H_MAX;dynamic_hsv[4]=config.HSV_S_MAX;dynamic_hsv[5]=config.HSV_V_MAX;dilate_erode_size=config.dilate_erode_size;/*cout<<"color= "<<color<<endl;cout<<"levle:"<<level<<endl;*/car_search_foward=config.car_search_foward;target_areaSize=config.target_areaSize;target_y_bias=config.target_y_bias;Move_step_max=config.Move_step_max;Turn_step_max=config.Turn_step_max;Move_step_min=config.Move_step_min;Turn_step_min=config.Turn_step_min;turn_KP=config.turn_KP;turn_KD=config.turn_KD;down_KP=config.down_KP;down_KD=config.down_KD;foward_KP=config.foward_KP;foward_KD=config.foward_KD;Car_foward_KP=config.Car_foward_KP;
}/**************************************************************************
Function: RGB image topic subscription callback function
Input   : none
Output  : none
函数功能: RGB图像话题订阅回调函数
入口参数: 无
返回  值: 无
**************************************************************************/
void rgb_image_Callback(const sensor_msgs::ImageConstPtr& msg)
{  /*零、ROS图片话题转换为OpenCV图片格式*************************/try {cv_bridge::CvImagePtr cv_ptr;  //ROS图像格式//将ROS话题数据转换为ROS图像格式cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);//将ROS图像格式转换为opencv图像格式cv_ptr->image.copyTo(image);//压缩图片,提高图片处理速度,同时减轻远程运行程序时的网络带宽压力CvSize size;size.width = image.cols/2;size.height = image.rows/2;resize(image,image,size,0,0, CV_INTER_AREA);}catch (cv_bridge::Exception& e){ROS_ERROR("cv_bridge exception: %s", e.what());return;}/*零、ROS图片话题转换为OpenCV图片格式*************************//*一、图像处理:识别色块部分**********************************/cvtColor(image, HSV_image, CV_BGR2HSV);//RGB图像转换为HSV图像/*0.在原图上标记出目标位置*/double target_x=image.cols/2, target_y=target_y_bias; //控制机械臂使色块位于画面内的目标位置circle(image, Point(target_x, target_y), 10, Scalar(0, 0, 255), 1); //画色块轮廓外接圆    line(image, Point(target_x-10,target_y),Point(target_x+10,target_y), Scalar(0, 0, 255),1,8,0);//在目标位置画十字line(image, Point(target_x,target_y-10),Point(target_x,target_y+10), Scalar(0, 0, 255),1,8,0);//在目标位置画十字/*1.根据颜色阈值进行图片二值化*/if(color==0) //根据HSV颜色空间下的自定义颜色阈值(即动态调阈值),进行图像二值化,仅保留指定自定义颜色{inRange(HSV_image, Scalar(dynamic_hsv[0], dynamic_hsv[1], dynamic_hsv[2]), Scalar(dynamic_hsv[3], dynamic_hsv[4], dynamic_hsv[5]), final_image); }else{if(color==1) //根据HSV颜色空间下的预置绿色阈值,进行图像二值化,仅保留绿色{inRange(HSV_image, Scalar(green_hsv[0], green_hsv[1], green_hsv[2]), Scalar(green_hsv[3], green_hsv[4], green_hsv[5]), final_image); }if(color==2) //根据HSV颜色空间下的预置蓝色阈值,进行图像二值化,仅保留蓝色{inRange(HSV_image, Scalar(blue_hsv[0], blue_hsv[1], blue_hsv[2]), Scalar(blue_hsv[3], blue_hsv[4], blue_hsv[5]), final_image); }if(color==3) //根据HSV颜色空间下的预置黄色阈值,进行图像二值化,仅保留黄色{inRange(HSV_image, Scalar(yellow_hsv[0], yellow_hsv[1], yellow_hsv[2]), Scalar(yellow_hsv[3], yellow_hsv[4], yellow_hsv[5]), final_image); }      if(color==4) //根据HSV颜色空间下的预置红色阈值,进行图像二值化,仅保留红色{inRange(HSV_image, Scalar(red_hsv[0], red_hsv[1], red_hsv[2]), Scalar(red_hsv[3], red_hsv[4], red_hsv[5]), final_image); }}/*2.膨胀腐蚀清除图像杂质*/Mat element = getStructuringElement(MORPH_RECT, Size(dilate_erode_size, dilate_erode_size)); dilate(final_image, final_image, element);erode(final_image, final_image, element);erode(final_image, final_image, element);dilate(final_image, final_image, element);//3.获得当前图像存在的所有轮廓(经过前面的处理,只有指定颜色的目标(色块)才有轮廓)vector<vector<Point>> contours;vector<Vec4i> hierarchy; try{findContours(final_image,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());}catch (cv::Exception& e){const char* err_msg = e.what();cout << "exception caught: " << err_msg << endl;}/*一、图像处理:识别色块部分**********************************//*********如果视野内存在色块,则停止色块寻找,开始执行色块抓取*//*********如果视野内存在色块,则停止色块寻找,开始执行色块抓取*//*********如果视野内存在色块,则停止色块寻找,开始执行色块抓取*//*二、图像处理:提取色块位置信息与可视化部分*******************/static int object_found=0;if(contours.size()>0) //如果轮廓对象不为空,则开始进行处理{if(object_found==0)cout<<GREEN<<"Object found."<<RESET<<endl<<endl; //只在第一次发现目标色块时打印object_found=1;int largest_contours_order=0; //所有轮廓中面积最大轮廓的序号/*1.提取色块位置信息*///获得面积最大轮廓的序号double largest_area=0;for(int i=0;i<contours.size();i++)  {  if(cv::contourArea(contours[i])>largest_area){largest_area=cv::contourArea(contours[i]);largest_contours_order=i;}      }//获得面积最大轮廓的面积大小area= cv::contourArea(contours[largest_contours_order]);//cout<<"area: "<<area<<endl; //面积最大轮廓的外接圆半径float radius=0; //面积最大轮廓的中心位置(横轴为x,纵轴为y,右上角为原点)Point2f center;//求面积最大轮廓外接圆,获得轮廓中心位置minEnclosingCircle(contours[largest_contours_order], center, radius);  //求获得当前色块与目标位置、距离的偏差x_bias=image.cols/2-center.x; //横轴偏差,色块中心在图像中心的左边为正,单位为分辨率y_bias=image.rows/2-center.y-target_y; //纵轴偏差,色块中心在目标位置的上边为正,单位为分辨率distance_bias=target_areaSize-area; //目标面积-色块面积=距离偏差,色块过远为正,单位为分辨率*分辨率/*cout<<"distance_bias: "<<distance_bias<<endl; cout<<"x_bias: "<<x_bias<<endl; cout<<"y_bias: "<<y_bias<<endl;*/ /*2.色块位置信息可视化*//*2.1.1在原图上标记出识别到的指定颜色目标*/circle(image, Point(center.x, center.y), radius, Scalar(0, 0, 255), 5); //画色块轮廓外接圆    line(image, Point(center.x-10,center.y),Point(center.x+10,center.y), Scalar(0, 0, 255),1,8,0);//在色块中心画十字line(image, Point(center.x,center.y-10),Point(center.x,center.y+10), Scalar(0, 0, 255),1,8,0);//在色块中心画十字/*2.2.在原图上显示当前色块与目标位置(摄像头中心)、距离的偏差*///定义用于显示的文字变量string area_txt="area: ";string bias_area_txt="bias_area: ";string bias_x_txt="bias_x: ";string bias_y_txt="bias_y: ";//初始化用于显示文字的字体格式CvFont font;double hScale=0.5, vScale=0.5;int    lineWidth=1.5;cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX,hScale,vScale,0,lineWidth,8);//限制要显示的文字在图像上的位置在图像大小内int txt_position_x, txt_position_y;txt_position_x=10;txt_position_y=50;if(txt_position_x<5)txt_position_x=5;if(txt_position_x>image.cols-50)txt_position_x=image.cols-50;if(txt_position_y<50)txt_position_y=50;if(txt_position_y>image.rows-60)txt_position_y=image.rows-60;//显示文字需要先转换图像格式IplImage tmp = IplImage(image);CvArr* image_=(CvArr*)&tmp;//显示当前色块面积area_txt = area_txt + to_string((int)area);cvPutText(image_, area_txt.data(), cvPoint(txt_position_x, txt_position_y-30), &font, cvScalar(0,0,0,1));//显示目标色块面积与当前色块面积的偏差bias_area_txt = bias_area_txt + to_string((int)distance_bias);cvPutText(image_, bias_area_txt.data(), cvPoint(txt_position_x, txt_position_y-10), &font, cvScalar(0,0,0,1));//显示图像中心与当前色块中心的横轴偏差bias_x_txt = bias_x_txt + to_string((int)x_bias);cvPutText(image_, bias_x_txt.data(), cvPoint(txt_position_x, txt_position_y+10), &font, cvScalar(0,0,0,1));//显示图像中心与当前色块中心的纵轴偏差bias_y_txt = bias_y_txt + to_string((int)y_bias);cvPutText(image_, bias_y_txt.data(), cvPoint(txt_position_x, txt_position_y+30), &font, cvScalar(0,0,0,1));//转换图像格式image = cv::cvarrToMat(image_);/*二、图像处理:提取色块位置信息与可视化部分*******************//*三、如果发现了色块,首先控制小车移动,使小车移动到与色块合适的距离,然后再计算机械臂的运动数值,用于抓取色块;如果当前视野内没有发现色块,则控制小车运动寻找色块*//*1.首先控制小车移动,使小车移动到与色块合适的距离*/if(Car_stop==false && Pick_start==true){/*1.1.如果横轴偏差比较大,控制小车旋转,使偏差减小到0*/if(x_bias>70 || x_bias<-70){Car_foward_velocity=x_bias/400*Car_foward_KP;}else{Car_foward_velocity=0;Car_stop=true, Arm_stop=false;cout<<GREEN<<"Car location complete."<<RESET<<endl<<endl;}}/*2.计算机械臂的运动数值,用于抓取色块*/if(Car_stop==true && Arm_stop==false && arm_locked==false){/*2.1.如果距离偏差(色块与机械臂的距离)大于1000,则对y轴偏差做处理,求机械臂上下方向运动值*/if((distance_bias>1000)&& arm_locked==false){//如果偏差较大,说明机械爪还没有靠近目标,继续运动进行调整y_step = (y_bias*down_KP + (y_bias-last_y_bias)*down_KD)*0.0005;  }/*2.2.如果距离偏差(色块与机械臂的距离)小于1000,则锁定机械臂的前后上下方向的位移。下一步机械爪将夹紧*/else if(arm_locked==false){y_step = 0;arm_locked=true;arm_locked_time=ros::Time::now();cout<<GREEN<<"Arm_hand can close now."<<RESET<<endl<<endl;}//if(area<target_areaSize*0.8 && y_step<0.00 && ArmC_End_Position_X<0.145 &&arm_in_min_height==1) y_step=distance_step*1; //机械爪离目标远时,禁止机械臂后退/*2.3.如果横轴偏差大小大于5,则对偏差做处理,求机械臂左右旋转的运动值*/if((x_bias>5 || x_bias<-5  )&& arm_turn_locked==false){x_step = (x_bias*turn_KP + (x_bias-last_distance_bias)*turn_KD)*0.01;      }else {x_step = 0;//当机械臂靠近色块后,转向偏差的认为已经稳定,后续禁止转向运动if(distance_bias<5000 && distance_bias>-5000) arm_turn_locked=true;}/*2.4.限制机械臂前后左右上下方向运动值的最大值和最小值*///前后上下移动的最大值(单位:m),转向移动的最大值(单位:rad)          if(x_step> Turn_step_max)       x_step= Turn_step_max;if(x_step<-Turn_step_max)       x_step=-Turn_step_max;if(y_step> Move_step_max)       y_step= Move_step_max;if(y_step<-Move_step_max)       y_step=-Move_step_max;if(distance_step> Move_step_max)distance_step= Move_step_max;if(distance_step<-Turn_step_max)distance_step=-Turn_step_max;//前后上下移动的最小值(单位:m),转向移动的最小值(单位:rad)if(x_step< Turn_step_min && x_step> 0)x_step= Turn_step_min;if(x_step>-Turn_step_min && x_step< 0)x_step=-Turn_step_min;             if(y_step< Move_step_min && y_step> 0)y_step= Move_step_min;if(y_step>-Move_step_min && y_step< 0)y_step=-Move_step_min;if(distance_step< Move_step_min && distance_step> 0)distance_step= Move_step_min;   //机械臂不允许向上移动,提高机械臂向色块靠近的稳定性if(distance_step<0)distance_step=0;/*cout<<"distance_step: "<<distance_step<<endl; cout<<"x_step: "<<x_step<<endl; cout<<"y_step: "<<y_step<<endl; *///用于KD控制last_distance_bias=distance_bias;last_x_bias=x_bias;last_y_bias=y_bias;}      }/*******如果轮廓对象为空,则说明当前视野内没有目标颜色,执行寻找色块功能*******/else //对应判断if(contours.size()>0) {/*1.机械臂前后左右上下方向运动值置0,即停止色块抓取*/distance_step=0;x_step=0;y_step=0;Joint_Hand_left1  =  hand_open_size, Joint_Hand_left2  =  hand_open_size, Joint_Hand_right1 = -hand_open_size, Joint_Hand_right2 = -hand_open_size;object_found=0;cout<<RED<<"no object found."<<RESET<<endl;   /*2.寻找色块*/  if(Pick_start==true && Arm_stop==true && foward_forb==false)//判断是否下达了抓取色块命令{          Car_foward_velocity=car_search_foward;}else {Car_foward_velocity=0;Car_turn_velocity=0;}    }/*三、如果发现了色块,首先控制小车移动,使小车移动到与色块合适的距离,然后再计算机械臂的运动数值,用于抓取色块;如果当前视野内没有发现色块,则控制小车运动寻找色块*//*四、根据机械臂前后左右上下方向运动值决定机械臂应该执行什么动作*//*1.1.机械臂前后上下方向运动值不为0,则控制机械臂靠近色块*/if(Arm_stop==false && arm_locked==false){//cout<<"distance_step!=0 && y_step!=0"<<endl;int error_foward, error_down;     error_foward=Position_move(foward, 0.01*foward_KP);/*cout<<"error_foward: "<<error_foward<<endl;cout<<"error_foward&(1<<5): "<<(error_foward&(1<<5))<<endl;cout<<"error_foward&(1<<3): "<<(error_foward&(1<<3))<<endl<<endl;*/error_down=Position_move(down, -y_step);/*cout<<"error_down: "<<error_down<<endl;cout<<"error_down&(1<<5): "<<(error_down&(1<<5))<<endl; cout<<"error_down&(1<<3): "<<(error_down&(1<<3))<<endl<<endl; */}/*1.2.机械臂左右方向运动值不为0,则控制机械臂旋转*/if(x_step!=0){//cout<<"x_step!=0"<<endl;Joint_A = Joint_A + x_step;}/*2.1.如果机械爪锁定标志位置1,代表已经抓取到色块,控制机械臂返回初始位置*/if(hand_closed==true){//机械爪之前色块后 if(( ros::Time::now() - hand_closed_time).toSec()<2.0){//0-2秒:机械臂回到默认位置ArmC_End_Position_X=grab_start_position_x;ArmC_End_Position_Y=grab_start_position_y;arm_2_inverse_solution(ArmC_End_Position_X, ArmC_End_Position_Y, Joint_B, Joint_C);}else if(( ros::Time::now() - hand_closed_time).toSec()<5.0){//2-5秒:机械臂底座旋转到终点Joint_A=grab_end_jointA;}else if(( ros::Time::now() - hand_closed_time).toSec()<6.0){//5-6秒:机械臂前进到目标点X坐标ArmC_End_Position_X=grab_end_position_x;ArmC_End_Position_Y=grab_start_position_y;arm_2_inverse_solution(ArmC_End_Position_X, ArmC_End_Position_Y, Joint_B, Joint_C);}else if(( ros::Time::now() - hand_closed_time).toSec()<7.0){//6-7秒:机械臂下降到目标点Y坐标(地面)ArmC_End_Position_X=grab_end_position_x;ArmC_End_Position_Y=grab_end_position_y;arm_2_inverse_solution(ArmC_End_Position_X, ArmC_End_Position_Y, Joint_B, Joint_C);}else if(( ros::Time::now() - hand_closed_time).toSec()<8.0){//7-8秒:机械爪张开,放置色块Joint_Hand_left1  =  hand_open_size, Joint_Hand_left2  =  hand_open_size, Joint_Hand_right1 = -hand_open_size, Joint_Hand_right2 = -hand_open_size;}else if(( ros::Time::now() - hand_closed_time).toSec()<9.0){//8-9秒:机械臂上升回去ArmC_End_Position_X=grab_end_position_x;ArmC_End_Position_Y=grab_start_position_y;arm_2_inverse_solution(ArmC_End_Position_X, ArmC_End_Position_Y, Joint_B, Joint_C);}else if(( ros::Time::now() - hand_closed_time).toSec()<12.0){//9-12秒:机械臂直接回归起点Joint_A=grab_start_jointA;ArmC_End_Position_X=grab_start_position_x;ArmC_End_Position_Y=grab_start_position_y;Joint_Hand_left1  =  hand_open_size, Joint_Hand_left2  =  hand_open_size, Joint_Hand_right1 = -hand_open_size, Joint_Hand_right2 = -hand_open_size;arm_2_inverse_solution(ArmC_End_Position_X, ArmC_End_Position_Y, Joint_B, Joint_C);}else if(( ros::Time::now() - hand_closed_time).toSec()>12.0){//回归后,清空相关标志位,为下一次抓取做准备Car_stop=false, Arm_stop=true, Car_turn_times=0;car_turn_locked=false, arm_turn_locked=false, arm_locked=false, hand_closed=false;Car_foward_velocity=0, Car_turn_velocity=0;foward_forb=false;}}/*2.2.如果机械臂锁定标志位置1,代表已经靠近色块,控制机械臂夹紧抓取色块*/if(arm_locked==true && hand_closed==false){/*cout<<"_start_time: "<<arm_locked_time.toSec()<<endl;cout<<"ros::Time::now(): "<<ros::Time::now().toSec()<<endl;*/Joint_Hand_left1  =  hand_close_size;Joint_Hand_left2  =  hand_close_size;Joint_Hand_right1 = -hand_close_size;Joint_Hand_right2 = -hand_close_size;//cout<<"( ros::Time::now() - _start_time).toSec(): "<<( ros::Time::now() - arm_locked_time).toSec()<<endl;//夹紧后等待1秒钟,再置1机械爪锁定标志位if(( ros::Time::now() - arm_locked_time).toSec()>1 && hand_closed==false)//delay 1s{hand_closed=true; hand_closed_time=ros::Time::now();}}/*五、如果抓取色块标志位置0,机械臂状态全部复位*/if(Pick_start==false){Car_stop=false, Arm_stop=true, Car_turn_times=0;car_turn_locked=false, arm_turn_locked=false, arm_locked=false, hand_closed=false;Car_foward_velocity=0, Car_turn_velocity=0;foward_forb=false;Joint_A=grab_start_jointA;ArmC_End_Position_X=grab_start_position_x;ArmC_End_Position_Y=grab_start_position_y;Joint_Hand_left1  =  hand_open_size, Joint_Hand_left2  =  hand_open_size, Joint_Hand_right1 = -hand_open_size, Joint_Hand_right2 = -hand_open_size;arm_2_inverse_solution(ArmC_End_Position_X, ArmC_End_Position_Y, Joint_B, Joint_C);}/*cout<<endl<<GREEN<<"arm_turn_locked: "<<arm_turn_locked<<endl;cout<<GREEN<<"arm_locked: "<<arm_locked<<endl;cout<<GREEN<<"hand_closed: "<<hand_closed<<endl;cout<<GREEN<<"Car_stop: "<<Car_stop<<endl;cout<<GREEN<<"Arm_stop: "<<Arm_stop<<RESET<<endl<<endl;*///显示原始图片,添加色块位置标注CvSize size;size.width = image.cols/2; //再次压缩图片,减轻远程运行程序时的网络带宽压力size.height = image.rows/2;resize(image,image,size,0,0, CV_INTER_AREA);imshow("rgb_image", image);//显示二值化图片,jetsonNano/NX目前无法显示单通道图像,暂时关闭//imshow("final_rgb_image", final_image);waitKey(1);
}/**************************************************************************
Function: Odometer topic subscribe callback function
Input   : none
Output  : none
函数功能: 里程计话题订阅回调函数
入口参数: 无
返回  值: 无
**************************************************************************/
void odom_Callback(const nav_msgs::Odometry& msg)
{static double last_odom_turn, last_odom_foward;odom_foward  = msg.pose.pose.position.x-last_odom_foward; //Position //位置odom_lateral = msg.pose.pose.position.y;odom_turn    = msg.pose.pose.position.z-last_odom_turn;if(Pick_start==false){last_odom_turn = msg.pose.pose.position.z;last_odom_foward = msg.pose.pose.position.x;}   if(hand_closed==true)last_odom_foward = msg.pose.pose.position.x;if(car_search_distance_max>0 && odom_foward>car_search_distance_max)//前进3m还没有发现色块,则停止运动foward_forb=true;if(car_search_distance_max<0 && odom_foward<car_search_distance_max)//前进3m还没有发现色块,则停止运动foward_forb=true;/*cout<<RED<<"odom_Callback"<<endl;cout<<RED<<"odom_foward:  "<<odom_foward<<endl;cout<<RED<<"odom_lateral: "<<odom_lateral<<endl;cout<<RED<<"odom_turn:    "<<odom_turn<<RESET<<endl;*/
}

小车抓取物块时的截图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/7707.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试题:String类型长度有限制吗?最大多少?

简介 Java中String是有长度限制的。String还有长度限制?是的有,而且在JVM编译中还有规范,String长度限制的场景(将某固定文件转码成Base64的形式用字符串存储,在运行时需要的时候在转回来,当时文件比较大),那这个规范限制到底是怎么样的,我们分析下。 …

crossover怎么打开软件 mac怎么下载steam crossover下载的软件怎么运行

CrossOver是一款Mac和Linux平台上的类虚拟机软件&#xff0c;通过CrossOver可以运行Windows的可执行文件。如果你是Mac用户且需要使用CrossOver&#xff0c;但是不知道CrossOver怎么打开软件&#xff0c;如果你想在Mac电脑上玩Windows游戏&#xff0c;但不知道怎么下载Steam&am…

2-5 任务:打印九九表

本次实战的目标是通过编写程序实现打印九九乘法表、字符矩形、字符平行四边形和字符菱形等图形&#xff0c;以及解决百钱买百鸡问题和输出素数等实际问题。在实战过程中&#xff0c;我们将学习并掌握以下知识点。 双重循环的使用&#xff1a;通过双重循环实现九九乘法表的打印&…

代码版本管理:提升团队协作效率的利器

在软件开发过程中&#xff0c;代码版本管理是一个至关重要的环节。它不仅能够有效管理代码的变更历史&#xff0c;还能提高团队协作效率、保证代码质量、降低风险。本文将介绍两种常用的代码版本管理工具&#xff1a;Git 和 Subversion&#xff08;SVN&#xff09;&#xff0c;…

怎么把图片尺寸在线修改?5种方法调整方式介绍

在日常生活和工作中&#xff0c;我们经常遇到需要调整图片尺寸的情况&#xff0c;无论是为了适应自媒体文章内容中的图片、还是上传社交媒体平台要求&#xff0c;调整图片尺寸是一项非常有用的技能。在本教程中&#xff0c;我们将介绍几个方便快捷的图片处理工具&#xff0c;帮…

如何让CANoe或Wireshark自动解析应用层协议

当我们使用CANoe软件或Wireshark工具抓取以太网总线上的报文时,网卡首先会把以太网总线上的模拟信号解析成以太网帧数据。数据链路层根据二层头部中的Type字段值确定上层的协议。 如果以太网使用的是TCP/IP协议栈,那么Type值要么是0x0800(IPv4),要么是0x0806(ARP),要么是0x…

【牛客】【模板】前缀和

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 前缀和模板题。 前缀和中数组下标为1~n。 前缀和&#xff1a;pre[i]pre[i-1]a[i]; 某段区间 [l,r]的和&#xff1a;pre[r]-pre[l-1] 3.…

数据结构---动态数组

一、数据结构基本理论 数据结构是相互之间存在一种或多种特定关系的数据元素的集合。强调数据元素之间的关系 算法五个特性&#xff1a; 输入、输出、有穷、确定、可行 数据结构分类&#xff1a; 逻辑结构&#xff1a;集合、线性结构、树形结构、图形结构 物理…

安装nginx-1.25.5与ngx_http_headers_more_filter_module模块

#下载nginx的代码 curl -O http://nginx.org/download/nginx-1.25.5.tar.gz #下载headers-more-nginx-module代码 git clone https://github.com/openresty/headers-more-nginx-module#解压 tar -xzf nginx-1.25.5.tar.gzcd nginx-1.25.5#--add-dynamic-module 下载下来的目录 …

接入大量设备后,视频汇聚系统EasyCVR安防监控视频融合平台是如何实现负载均衡的?

一、负载均衡 随着技术的不断进步和监控需求的日益增长&#xff0c;企业视频监控系统的规模也在不断扩大&#xff0c;接入大量监控设备已成为一项常态化的挑战。为确保企业能够有效应对这一挑战&#xff0c;视频汇聚系统EasyCVR视频融合平台凭借其卓越的高并发处理能力&#x…

“Postman 中文版使用教程:如何切换到中文界面?”

Postman 的很好用的接口测试软件。但是&#xff0c;Postman 默认是英文版的&#xff0c;也不支持在软件内切换为中文版。很多同学的英语并不是很好&#xff0c;看到一堆的英文很是头痛。 今天我们来介绍下&#xff1a;切换到 Postman 中文版的方法。想要学习更多的关于 Postma…

【教学类-50-14】20240505“数一数”图片样式12:数一数(12个“人物”图案)

作品展示 背景需求&#xff1a; 前文做了“”材料”图片的数一数学具&#xff0c;效果不错&#xff0c; https://blog.csdn.net/reasonsummer/article/details/138466325https://blog.csdn.net/reasonsummer/article/details/138466325 为了让图案内容更丰富&#xff0c;我又…

皮秒激光切割机可以切割材料及主要应用行业

皮秒激光切割机可以切割多种材料&#xff0c;主要应用行业包括但不限于&#xff1a; 1. PCB板行业&#xff1a;主要用于PCB激光分板&#xff0c;如FR4、补强钢片、FPC、软硬结合板、玻纤板等材料的紫外激光切割。 2. 薄膜材料切割&#xff1a;皮秒紫外激光切割机可以直接切割薄…

启英泰伦“离线自然说”技术,让智能语音芯片更善解人意

“以科技创新推动产业创新&#xff0c;特别是以颠覆性技术和前沿技术催生新产业、新模式、新动能&#xff0c;发展新质生产力”。2023年12月&#xff0c;中央经济工作会议强调了发展新质生产力的路径。“科技创新是发展新质生产力的核心要素&#xff0c;这也是我们一直潜心在做…

解决Pyppeteer下载chromium慢或者失败的问题[INFO] Starting Chromium download.

文章目录 1.进入网址2.选择上面对应自己系统的文件夹进去3. 然后找到自己的python环境中的site-packages中pyppeteer中的chromium_downloader.py文件并打开 在首次使用Pyppeteer时需要下载chromium 1.进入网址 https://registry.npmmirror.com/binary.html?pathchromium-bro…

07_Flutter使用NestedScrollView+TabBarView滚动位置共享问题修复

07_Flutter使用NestedScrollViewTabBarView滚动位置共享问题修复 一.案发现场 可以看到&#xff0c;上图中三个列表的滑动位置共享了&#xff0c;滑动其中一个列表&#xff0c;会影响到另外两个&#xff0c;这显然不符合要求&#xff0c;先来看下布局&#xff0c;再说明产生这个…

【MM32F3270 Micropython】pwm输出

文章目录 前言一、PWM脉宽调制技术介绍二、machine.PWM 类2.1 machine.PWM 类的构造对象2.2 PWM 对象初始化2.3 关闭PWM设备2.4 设置pwm的周期2.5 设置占空比 三、pwm示例代码总结 前言 MicroPython是一种精简的Python 3编程语言实现&#xff0c;旨在在微控制器和嵌入式系统上…

算法分析 KMP算法中next值的计算、0/1背包问题

5.6.1 KMP算法中next值的计算 设模式的长度为m。用蛮力法求解 KMP算法中的 next值时&#xff0c;next[0]可直接给出&#xff0c;计算next[j](1<j<m-1)则需要在 T[0] …T[j-1]中分别取长度为j-1、..、2、1的真前缀和真后缀并比较是否相等&#xff0c;最坏情况下的时间代价…

解析Linux键盘组合键产生信号的完整过程:从硬件中断到信号发送

前言 每一个了解Linux的都知道这样一个知识&#xff0c;CtrlC组合键能够终止一个进程。 个人了解进程相关知识之后知道&#xff0c;一个进程被终止只会有有三种情况&#xff1a; 代码运行完毕&#xff0c;结果正确代码运行完毕&#xff0c;结果不正确代码运行异常&#xff…

鸿蒙OpenHarmony【基于Hi3516DV300开发板(时钟应用开发)】

概述 本文将介绍如何快速搭建基于OpenHarmony标准系统&#xff08;Hi3516DV300开发板&#xff09;的应用开发环境&#xff0c;并基于一个时钟APP示例逐步展示应用的创建、开发、调试和安装等流程。示例代码可以通过本链接获取。 时钟App是一款显示实时时间的应用&#xff0c;…