// // Created by zx on 22-12-2. // #include "navigation.h" #include "loaded_mpc.h" #include "../define/TimerRecord.h" Navigation::~Navigation() { exit_=true; if(terminator_) delete terminator_; if(monitor_) delete monitor_; if(thread_!= nullptr) { if(thread_->joinable()) thread_->join(); delete thread_; } if(pubthread_!= nullptr) { if(pubthread_->joinable()) pubthread_->join(); delete pubthread_; } } /* * 高斯函数压缩,x=3 */ double limit(double x,double min,double max){ double r=x>=0?1.0:-1.0; double delta=max/3.0; return (max-(max-min)*exp(-x*x/(delta*delta)))*r; } bool Navigation::Init(const Navigation_parameter& parameter) { parameter_=parameter; AgvEmqx_parameter agv_p=parameter.agv_emqx(); if(monitor_== nullptr) { monitor_ = new Monitor_emqx(agv_p.nodeid(), agv_p.pubtopic(), agv_p.subtopic()); monitor_->set_statu_arrived_callback(Navigation::RobotStatuCallback, this); if(monitor_->Connect(agv_p.ip(),agv_p.port())==false) { printf(" agv emqx connected failed\n"); return false; } } Emqx_parameter terminal_p=parameter.terminal_emqx(); if(terminator_== nullptr) { terminator_ = new Terminator_emqx(terminal_p.nodeid()); if(terminator_->Connect(terminal_p.ip(),terminal_p.port())==false) { printf(" terminator emqx connected failed\n"); return false; } terminator_->AddCallback(terminal_p.subnavcmdtopic(),Navigation::NavCmdCallback,this); terminator_->AddCallback(terminal_p.subbrotherstatutopic(),Navigation::BrotherAgvStatuCallback,this); } inited_=true; if(pubthread_!= nullptr) { exit_=true; if(pubthread_->joinable()) pubthread_->join(); delete pubthread_; } exit_=false; pubthread_=new std::thread(&Navigation::publish_statu,this); return true; } void Navigation::publish_statu() { while (exit_ == false) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); //发布nav状态 NavMessage::NavStatu statu; statu.set_statu(eReady); //默认ready NavMessage::Action *current_action = nullptr; if (running_) { statu.set_statu(eRunning); statu.set_key(global_navCmd_.key()); std::queue actios = unfinished_cations_; while (actios.empty() == false) { //保存当前动作 NavMessage::Action *act = statu.add_unfinished_actions(); current_action = new NavMessage::Action(*act); act->CopyFrom(actios.front()); actios.pop(); } } //发布MPC信息 if (current_action != nullptr) { delete current_action; //发布mpc 预选点 if (selected_traj_.timeout() == false) { for (int i = 0; i < selected_traj_.Get().size(); ++i) { Pose2d pt = selected_traj_.Get()[i]; NavMessage::Pose2d *pose = statu.mutable_selected_traj()->add_poses(); pose->set_x(pt.x()); pose->set_y(pt.y()); pose->set_theta(pt.theta()); } } //发布 mpc 预测点 if (predict_traj_.timeout() == false) { for (int i = 0; i < predict_traj_.Get().size(); ++i) { Pose2d pt = predict_traj_.Get()[i]; NavMessage::Pose2d *pose = statu.mutable_predict_traj()->add_poses(); pose->set_x(pt.x()); pose->set_y(pt.y()); pose->set_theta(pt.theta()); } } } MqttMsg msg; msg.fromProtoMessage(statu); if(terminator_) terminator_->Publish(parameter_.terminal_emqx().pubnavstatutopic(),msg); //发布位姿 -------------------------------- if (timedPose_.timeout() == false&& timedV_.timeout() == false && timedA_.timeout() == false) { NavMessage::AGVStatu agvStatu; Pose2d pose = timedPose_.Get(); agvStatu.set_x(pose.x()); agvStatu.set_y(pose.y()); agvStatu.set_theta(pose.theta()); agvStatu.set_v(timedV_.Get()); agvStatu.set_vth(timedA_.Get()); if(terminator_) { MqttMsg msg; msg.fromProtoMessage(agvStatu); terminator_->Publish(parameter_.terminal_emqx().pubstatutopic(), msg); } } } } void Navigation::ResetStatu(double v,double a) { timedV_.reset(v,0.5); timedA_.reset(a,0.5); } void Navigation::ResetPose(const Pose2d& pose) { timedPose_.reset(pose,0.5); } bool Navigation::Start(const NavMessage::NavCmd& cmd) { if(unfinished_cations_.empty()==false) //正在运行中,上一次指令未完成 { if(pause_) { pause_=false; return true; } printf(" navigation is running pls cancel before\n"); return false; } if(thread_!= nullptr) { if(thread_->joinable()) thread_->join(); delete thread_; } //add 先检查当前点与起点的距离 global_navCmd_=cmd; for(int i=0;istop(); pause_=true; } Navigation::Navigation() { thread_= nullptr; monitor_= nullptr; terminator_= nullptr; } void Navigation::BrotherAgvStatuCallback(const MqttMsg& msg,void* context) { Navigation* navigator=(Navigation*)context; NavMessage::AGVStatu brother_statu; if(msg.toProtoMessage(brother_statu)==false) { printf(" msg transform to AGVStatu failed ..!!\n"); return; } //std::cout<timedBrotherPose_.reset(pose,1); navigator->timedBrotherV_.reset(brother_statu.v(),1); navigator->timedBrotherA_.reset(brother_statu.vth(),1); } void Navigation::NavCmdCallback(const MqttMsg& msg,void* context) { Navigation* navigator=(Navigation*)context; NavMessage::NavCmd cmd; if(msg.toProtoMessage(cmd)==false) { printf(" msg transform to NavCmd failed ..!!\n"); return; } if(cmd.action()==3) { navigator->Cancel(); return ; } if(cmd.action()==2) { navigator->pause_=false; return ; } if(cmd.action()==1) { navigator->Pause(); return ; } navigator->Start(cmd); } void Navigation::RobotStatuCallback(double x,double y,double theta,double v,double vth,void* context) { Navigation* navigator=(Navigation*)context; navigator->ResetPose(Pose2d(x,y,theta)); navigator->ResetStatu(v,vth); } bool Navigation::exec_adjust_action(const Pose2d& target,const Pose2d& target_diff) { if(inited_==false) { printf(" navigation has not inited\n"); return false; } Pose2d thresh=Pose2d::abs(target_diff); int action=0; //1 原地旋转,2横移,3前进 while(cancel_==false) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); if (pause_ == true) { //发送暂停消息 continue; } if (timedPose_.timeout() || timedV_.timeout() || timedA_.timeout()) { printf(" navigation Error:Pose/v/a is timeout \n"); break; } //判断是否到达目标点 if (IsArrived(timedPose_.Get(), timedV_.Get(), timedA_.Get(), target, target_diff)) { monitor_->stop(); printf("adjust completed\n"); return true; } //计算目标点在当前pose下的pose Pose2d diff = Pose2d::TargetByPose(target, timedPose_.Get()); //停止状态 if (action == 0) { //优先进入旋转 if (Pose2d::abs(diff).theta() > thresh.theta()) { action = 1; //原地旋转 } else if (Pose2d::abs(diff).x() > thresh.x()) { //前进 action = 3; }else if (Pose2d::abs(diff).y() > thresh.y()) { //横移 action = 2; } } else { if (action == 1) { if (Pose2d::abs(diff).theta() > thresh.theta()) { double theta = limit(diff.theta(),5*M_PI/180.0,40*M_PI/180.0); monitor_->set_speed(Monitor_emqx::eRotate, 0, theta); printf(" Ratate :%f\n",theta); continue; } } if (action == 2) { if (Pose2d::abs(diff).y() > thresh.y()) { monitor_->set_speed(Monitor_emqx::eHorizontal, limit(diff.y(),0.05,0.2), 0); printf(" Horizontal :%f\n",limit(diff.y(),0.05,0.2)); continue; } } if (action == 3) { if (Pose2d::abs(diff).x() > thresh.x()) { monitor_->set_speed(Monitor_emqx::eMPC, limit(diff.x(),0.05,0.5), 0); printf(" Vrtical :%f\n",limit(diff.x(),0.05,0.5)); continue; } } monitor_->stop(); printf(" monitor type :%d completed!!! reset action type!!!\n", action); action = 0; } } return false; } bool Navigation::mpc_once(const Trajectory& traj,std::vector& out) { if(timedPose_.timeout()==true && timedV_.timeout()==false && timedA_.timeout()==false) { printf(" MPC once Error:Pose/V/A is timeout \n"); return false; } if(traj.size()==0) { printf("traj size ==0\n"); return false; } Pose2d pose=timedPose_.Get(); double velocity=timedV_.Get(); //从plc获取状态 double angular=timedA_.Get(); LoadedMPC MPC(2.7); Eigen::VectorXd statu=Eigen::VectorXd::Zero(5);//agv状态 statu[0]=pose.x(); statu[1]=pose.y(); statu[2]=pose.theta(); statu[3]=velocity; statu[4]=angular; Trajectory optimize_trajectory; Trajectory selected_trajectory; bool ret= MPC.solve(traj,traj[traj.size()-1],statu,out,selected_trajectory,optimize_trajectory); predict_traj_.reset(optimize_trajectory,1); selected_traj_.reset(selected_trajectory,1); return ret; } bool Navigation::IsArrived(const Pose2d& cur,double velocity,double angular, const Pose2d& target,const Pose2d& diff) { Pose2d distance=Pose2d::TargetByPose(target,cur); if(Pose2d::abs(distance)stop(); printf(" exec along completed !!!\n"); return true; } //一次变速 std::vector out; bool ret; TimerRecord::Execute([&,this](){ ret=mpc_once(traj,out); },"mpc_once"); if(ret==false) { monitor_->stop(); return false; } monitor_->set_speed(Monitor_emqx::eMPC,out[0],out[1]); } return false; } void Navigation::navigatting() { if(inited_==false) { printf(" navigation has not inited\n"); return ; } pause_=false; cancel_=false; running_=true; printf(" navigation beg...\n"); while(unfinished_cations_.empty()==false && cancel_==false) { NavMessage::Action act=unfinished_cations_.front(); Pose2d target(act.target().x(),act.target().y(),act.target().theta()); Pose2d target_diff(act.target_diff().x(),act.target_diff().y(),act.target_diff().theta()); if(act.type()==1) { printf(" adjust to (%.3f %.3f %.3f) diff:(%.3f,%.3f,%.3f)\n", act.target().x(),act.target().y(),act.target().theta(), act.target_diff().x(),act.target_diff().y(),act.target_diff().theta()); if(exec_adjust_action(target,target_diff)==false) { printf("execute adjust action failed\n"); break; } } else if(act.type()==2) { printf(" MPC to (%.3f %.3f %.3f) diff:(%.3f,%.3f,%.3f)\n", act.target().x(),act.target().y(),act.target().theta(), act.target_diff().x(),act.target_diff().y(),act.target_diff().theta()); if(execute_along_action(target,target_diff)==false) { printf("execute along action failed\n"); break; } } else { printf(" unknow action type:%d\n",act.type()); break; } unfinished_cations_.pop(); } monitor_->stop(); if(cancel_==true) { printf(" navigation canceled\n"); while(unfinished_cations_.empty()==false) unfinished_cations_.pop(); }else { if (unfinished_cations_.empty()) printf("navigation completed!!!\n"); else{ printf(" navigation Failed\n"); while(unfinished_cations_.empty()==false) unfinished_cations_.pop(); } } running_=false; }