diff --git a/MobileRobot/AugReaMarker/CamMark/camtomar/src/VisionControl.cpp b/MobileRobot/AugReaMarker/CamMark/camtomar/src/VisionControl.cpp index 16766be45a3a3bbd1065d78e077e836024566aec..c68a8d85351cfc8085ed174c7572ad23f04d4d99 100644 --- a/MobileRobot/AugReaMarker/CamMark/camtomar/src/VisionControl.cpp +++ b/MobileRobot/AugReaMarker/CamMark/camtomar/src/VisionControl.cpp @@ -48,7 +48,7 @@ using namespace std; float PID4Docking::TheMarkerSize = .1; // Default marker size -int PID4Docking::Thresh1_min = 40; +int PID4Docking::Thresh1_min = 25; int PID4Docking::Thresh2_min = 10; int PID4Docking::Thresh1_max = 300; @@ -92,14 +92,14 @@ double PID4Docking::control_signalX, PID4Docking::control_signalY, PID4Docking:: //const double PID4Docking::RefPose[4] = {-.0957, 0.00638817 /* Y_ref*/ , 0.308857 /* X_ref*/ , 0.17 /* theta_ref*/}; // ---- Ref. Values for Logitech Camera ---- // -const double PID4Docking::RefPose[4] = {-.0957, -0.003 /* Y_ref*/ , 0.6752 /* X_ref*/ , -0.034 /* theta_ref*/}; +const double PID4Docking::RefPose[4] = {-.0957, 0.01923 /* Y_ref*/ , 0.201 /* X_ref*/ , -0.029 /* theta_ref*/}; // ---------------- PID gains---------------- // -double PID4Docking::Kp_y = .5; //.4 +double PID4Docking::Kp_y = .38; //.4 double PID4Docking::Ki_y = 0 ;// 0 -double PID4Docking::Kd_y = 0.2; //.15 +double PID4Docking::Kd_y = 0.02; //.1 -double PID4Docking::Kp_theta = .16;// .08 +double PID4Docking::Kp_theta = .18;// .08 double PID4Docking::Ki_theta = 0; //* Ki_y; // .15 * Ki_y double PID4Docking::Kd_theta = 0; //* Kd_y; // .0008 // ---------------- PID gains---------------- // @@ -121,10 +121,10 @@ double PID4Docking::speed_reducer_theta = 1; // ------ offsets X, Y, theta for Docking --------- double PID4Docking::x_dock_thresh = .001; -double PID4Docking::y_dock_thresh = .003; //.002 -double PID4Docking::theta_dock_thresh = (CV_PI/180) * 1; // .5 deg. +double PID4Docking::y_dock_thresh = .002; //.002 +double PID4Docking::theta_dock_thresh = (CV_PI/180) * .5; // .5 deg. -double PID4Docking::safety_margin_X = .18; // safety margin X axis in docking process : 18 cm +double PID4Docking::safety_margin_X = .16; // safety margin X axis in docking process : 18 cm // ------ offsets X, Y, theta for Undocking --------- double PID4Docking::x_thresh_undock = .02; @@ -417,6 +417,8 @@ if (key == ' ') void PID4Docking::camCB(const geometry_msgs::PoseStamped::ConstPtr& CamFB) // subscriber { camPose[0] = CamFB->pose.position.x; // not important!!! + + camPose[1] = CamFB->pose.position.y; // y pose camPose[2] = CamFB->pose.position.z; // x_rob @@ -441,15 +443,18 @@ camPose[5] = CamFB->pose.orientation.z; // Robot yaw if (theta_with_offset > 0) { - x_robINmar_coor = camPose[2] + (-x_robCen2cam * cos(theta_with_offset) + y_robCen2cam * sin(theta_with_offset)); - y_robINmar_coor = camPose[1] + (x_robCen2cam * sin(theta_with_offset) + y_robCen2cam * cos(theta_with_offset)); + //x_robINmar_coor = -camPose[2] * cos(theta_with_offset) + camPose[1] * sin(theta_with_offset); + x_robINmar_coor = camPose[2] * cos(theta_with_offset) - camPose[1] * sin(theta_with_offset); + y_robINmar_coor = -camPose[2] * sin(theta_with_offset) + camPose[1] * cos(theta_with_offset); + } else if (theta_with_offset < 0) { - x_robINmar_coor = camPose[2] + (-x_robCen2cam * cos(theta_with_offset) - y_robCen2cam * sin(theta_with_offset)); - y_robINmar_coor = camPose[1] + (-x_robCen2cam * sin(theta_with_offset) + y_robCen2cam * cos(theta_with_offset)); + //x_robINmar_coor = -camPose[2] * cos(theta_with_offset) - camPose[1] * sin(theta_with_offset); + x_robINmar_coor = camPose[2] * cos(theta_with_offset) - camPose[1] * sin(theta_with_offset); + y_robINmar_coor = -camPose[2] * sin(theta_with_offset) + camPose[1] * cos(theta_with_offset); } else { - ROS_INFO_STREAM(" Mew condition should be added! \n"); + ROS_INFO_STREAM(" Mew condition should be added for theta! \n"); } ROS_INFO_STREAM("theta = " << theta_with_offset << "rad. =~ " << theta_with_offset*(180.0/CV_PI) << " deg. \n"); @@ -457,6 +462,8 @@ camPose[5] = CamFB->pose.orientation.z; // Robot yaw ROS_INFO_STREAM(" X_mar = " << x_robINmar_coor << " vs. X_ref = " << RefPose[2] << " \n"); ROS_INFO_STREAM(" Y_mar = " << y_robINmar_coor << " vs. Y_ref = " << RefPose[1] << " \n"); + ROS_INFO_STREAM(" y_t = " << camPose[1] << " , x_t = " << camPose[2] << "\n"); + ROS_INFO_STREAM("------------------------------------------------------ \n "); if(Go2RandomPose == false) @@ -607,7 +614,7 @@ ROS_INFO_STREAM("pY = " << p_termY << ", iY = " << i_termY << " dY = " << d_term control_signalYAW = 0; } - /* --- + /* --- ROS_INFO_STREAM("Control signalX = " << control_signalX <<"\n"); ROS_INFO_STREAM("Control signalY = " << control_signalY << "\n"); ROS_INFO_STREAM("Control signalYAW = "<< control_signalYAW <<"\n"); @@ -628,7 +635,7 @@ void PID4Docking::dock(double VelX, double VelY, double omegaZ) commandPub.publish(msg); - ROS_INFO_STREAM(" Current speed of robot: \n" << msg << ".\n"); + ROS_INFO_STREAM(" Current speed of robot: \n" << msg << ""); } void PID4Docking::move2docking(double VelX_est, double VelY_est, double omegaZ_est) diff --git a/MobileRobot/AugReaMarker/CamMark/camtomar/src/VisionControl.cpp~ b/MobileRobot/AugReaMarker/CamMark/camtomar/src/VisionControl.cpp~ index 02c56d8dfa3db7eb14ec5c49ce713a8483679b56..9fc4bba54281690bcdaacebacd76bbe219219511 100644 --- a/MobileRobot/AugReaMarker/CamMark/camtomar/src/VisionControl.cpp~ +++ b/MobileRobot/AugReaMarker/CamMark/camtomar/src/VisionControl.cpp~ @@ -1,8 +1,13 @@ #include <iostream> #include <fstream> #include <sstream> +#include <array> #include <math.h> #include <unistd.h> +#include <cstdlib> +#include <stdio.h> /* printf, scanf, puts, NULL */ +#include <stdlib.h> /* srand, rand */ +#include <time.h> /* time */ #include <aruco/aruco.h> #include <aruco/cvdrawingutils.h> @@ -14,6 +19,9 @@ #include <tf/tf.h> #include <geometry_msgs/Pose.h> +#include <geometry_msgs/PoseStamped.h> +#include <geometry_msgs/Twist.h> + #include <image_transport/image_transport.h> #include <cv_bridge/cv_bridge.h> #include <sensor_msgs/image_encodings.h> @@ -32,158 +40,753 @@ #include "opencv2/highgui/highgui.hpp" #include "opencv2/contrib/contrib.hpp" +#include<VisionControl.h> + using namespace cv; using namespace aruco; using namespace std; -class PID4Docking +float PID4Docking::TheMarkerSize = .1; // Default marker size + +int PID4Docking::Thresh1_min = 10; +int PID4Docking::Thresh2_min = 10; + +int PID4Docking::Thresh1_max = 300; +int PID4Docking::Thresh2_max = 300; + +const string PID4Docking::trackbarWindowName = "Trackbars"; + +int PID4Docking::ThePyrDownLevel = 0; + +bool PID4Docking::update_images = true; + +bool PID4Docking::found = false; +bool PID4Docking::Go2RandomPose = false; + +int PID4Docking::ThresParam1 = 0; +int PID4Docking::ThresParam2 = 0; + +// ---- CONTROLL PARAMETERS ------ // +double PID4Docking::prev_errorX, PID4Docking::curr_errorX, PID4Docking::int_errorX, PID4Docking::diffX; + +double PID4Docking::p_termX = 0; +double PID4Docking::i_termX = 0; +double PID4Docking::d_termX = 0; + +double PID4Docking::prev_errorY, PID4Docking::curr_errorY, PID4Docking::int_errorY, PID4Docking::diffY; + +double PID4Docking::p_termY = 0; +double PID4Docking::i_termY = 0; +double PID4Docking::d_termY = 0; + +double PID4Docking::prev_errorYAW,PID4Docking::curr_errorYAW,PID4Docking::int_errorYAW,PID4Docking::diffYAW; + +double PID4Docking::p_termYAW = 0; +double PID4Docking::i_termYAW = 0; +double PID4Docking::d_termYAW = 0; + +double PID4Docking::control_signalX, PID4Docking::control_signalY, PID4Docking::control_signalYAW; +// ---- CONTROLL PARAMETERS ------ // + +// ---- Ref. Values for Android Camera ---- // +//const double PID4Docking::RefPose[4] = {-.0957, 0.00638817 /* Y_ref*/ , 0.308857 /* X_ref*/ , 0.17 /* theta_ref*/}; + +// ---- Ref. Values for Logitech Camera ---- // +const double PID4Docking::RefPose[4] = {-.0957, -0.004 /* Y_ref*/ , 0.6752 /* X_ref*/ , -0.036 /* theta_ref*/}; + +// ---------------- PID gains---------------- // +double PID4Docking::Kp_y = .51; //.4 +double PID4Docking::Ki_y = 0 ;// 0 +double PID4Docking::Kd_y = 0.1; //.15 + +double PID4Docking::Kp_theta = .11;// .08 +double PID4Docking::Ki_theta = 0; //* Ki_y; // .15 * Ki_y +double PID4Docking::Kd_theta = 0; //* Kd_y; // .0008 +// ---------------- PID gains---------------- // + + +double PID4Docking::TT_S,PID4Docking::TT_E; +// random pose initialized +const double PID4Docking::y_up = .3; +const double PID4Docking::y_dwn = -.1; +const double PID4Docking::theta_dwn = -.7 /*-RefPose[3]*/; +const double PID4Docking::theta_up = .7 /*RefPose[3]*/; + +double PID4Docking::x_new,PID4Docking::y_new,PID4Docking::theta_new; +double PID4Docking::dock_started,PID4Docking::dock_finished,PID4Docking::docking_duration; + +double PID4Docking::speed_reducer_X = 1; +double PID4Docking::speed_reducer_Y = 1; +double PID4Docking::speed_reducer_theta = 1; + +// ------ offsets X, Y, theta for Docking --------- +double PID4Docking::x_dock_thresh = .001; +double PID4Docking::y_dock_thresh = .002; //.002 +double PID4Docking::theta_dock_thresh = (CV_PI/180) * .5; // .5 deg. + +double PID4Docking::safety_margin_X = .17; // safety margin X axis in docking process : 18 cm + +// ------ offsets X, Y, theta for Undocking --------- +double PID4Docking::x_thresh_undock = .02; +double PID4Docking::y_thresh_undock = .015; +double PID4Docking::theta_thresh_undock = (CV_PI/180) * 3; + +double PID4Docking::docking_counter = 1; + +// ---- offsets for Roll, Pitch, Yaw ----// +float PID4Docking::p_off = CV_PI; +float PID4Docking::r_off = CV_PI/2; +float PID4Docking::y_off = CV_PI; + +float PID4Docking::roll,PID4Docking::yaw,PID4Docking::pitch; +double PID4Docking::theta_with_offset; + +double PID4Docking::x_robCen2cam = -.95/2; // x_cam from the center of robot +double PID4Docking::y_robCen2cam = 0; // y_cam from the center of robot + +double PID4Docking::x_robINmar_coor,PID4Docking::y_robINmar_coor; + + +PID4Docking::PID4Docking() +{ + keepMoving = true; + + /* initialize random seed: */ + srand (time(NULL)); + + x_rand_SM = RefPose[2] + .55; // 55 cm spreading domain in the x-axis while moving towards the random pose + + // Publish pose message and buffer up to 100 messages + MarPose_pub = node_vis.advertise<geometry_msgs::PoseStamped>("/marker_pose", 100); + commandPub = node_cont.advertise<geometry_msgs::Twist>("/base_controller/command",100); + + MarPose_Sub = node_vis.subscribe("/marker_pose",100,&PID4Docking::camCB,this); +} + + PID4Docking::~PID4Docking() + { + + } + Mat PID4Docking::getCurrentImage() + { + return img; + } + +void PID4Docking::cvTackBarEvents(int value,void* ptr) { -private: + PID4Docking* ic = (PID4Docking*)(ptr); + ic-> myhandler(value); +} - ros::NodeHandle node_vis; - ros::NodeHandle node_cont; +void PID4Docking::myhandler(int value) +{ + if (Thresh1_min<3) Thresh1_min=3; + + if (Thresh1_min%2!=1) Thresh1_min++; + + if (ThresParam2<1) ThresParam2=1; + + ThresParam1 = Thresh1_min; + ThresParam2 = Thresh2_min; + + MDetector.setThresholdParams(ThresParam1,ThresParam2); - ros::Publisher commandPub; - - ros::Subscriber MarPose_Sub; - ros::Publisher MarPose_pub; + // Recompute + MDetector.detect(TheInputImage,TheMarkers,TheCameraParameters); + // TheInputImageCopy is the output image for TheInputImage + TheInputImage.copyTo(TheInputImageCopy); - Mat img; - - string TheInputVideo; - string TheIntrinsicFile; + for (unsigned int i=0;i<TheMarkers.size();i++) + { + TheMarkers[i].draw(TheInputImageCopy,Scalar(205,0,0),1); + } + + imshow("INPUT IMAGE",TheInputImageCopy); + //imshow("THRESHOLD IMAGE",MDetector.getThresholdedImage()); +} +void PID4Docking::createTrackbars() +{ + namedWindow(trackbarWindowName, 0); + createTrackbar("ThresParam 1", trackbarWindowName, &Thresh1_min, Thresh1_max, cvTackBarEvents, this); + createTrackbar("ThresParam 2", trackbarWindowName, &Thresh2_min, Thresh2_max, cvTackBarEvents, this); + +} +void PID4Docking::imageCb(const sensor_msgs::ImageConstPtr& msg) +{ + cv_bridge::CvImagePtr cv_ptr; + try + { + cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8); + } + catch (cv_bridge::Exception& e) + { + ROS_ERROR("cv_bridge exception: %s", e.what()); + } - MarkerDetector MDetector; - VideoCapture TheVideoCapturer; + img = cv_ptr->image; + +} - vector<Marker> TheMarkers; +bool PID4Docking::readArguments ( int argc,char **argv ) +{ + if (argc<2) { + cerr<< "Invalid number of arguments!\n" <<endl; + cerr<< "Usage: (in.avi|live|copy) [intrinsics.yml] [marker's width/height]" <<endl; + return false; + } + TheInputVideo=argv[1]; + if (argc>=3) + TheIntrinsicFile=argv[2]; + if (argc>=4) + TheMarkerSize=atof(argv[3]); + if (argc==3) + cerr<< "NOTE: You need makersize to see 3d info!" <<endl; + return true; +} - Mat TheInputImage,TheInputImageCopy; - CameraParameters TheCameraParameters; - - tf::TransformBroadcaster broadcaster; +void PID4Docking::ProgStart(int argc,char** argv) +{ + // Show images, press "SPACE" to diable image + // rendering to save CPU time - tf::TransformListener ObjListener; + if (readArguments(argc,argv)==false) + { + cerr<<"check the authenticity of your file again!"<<endl; + node_vis.shutdown(); + } + createTrackbars(); - // --- Camera broadcaster --- - tf::TransformBroadcaster CAMbr; - tf::Transform transformCAM; + // IP address for raw3_lund + const std::string vsa = "http://192.168.0.101:8080/video?x.mjpeg"; + // -- publishing video stream with Android Camera-- - // --- Robot listener --- - tf::TransformListener RobListener; - - static int Thresh1_min,Thresh2_min; - - static int Thresh1_max,Thresh2_max; - - bool keepMoving; - - static int ThresParam1,ThresParam2; + //TheVideoCapturer.open(vsa); + + TheVideoCapturer.open(0); + + // Check video is open + if (!TheVideoCapturer.isOpened()) + { + cerr<<"Could not open video!!"<<endl; + node_vis.shutdown(); + } + dock_started = ros::Time::now().toSec(); + // Read first image to get the dimensions + TheVideoCapturer>>TheInputImage; + + // Read camera parameters if passed + if (TheIntrinsicFile!="") { + TheCameraParameters.readFromXMLFile(TheIntrinsicFile); + TheCameraParameters.resize(TheInputImage.size()); + } + + // Configure other parameters + if (ThePyrDownLevel>0) + { + MDetector.pyrDown(ThePyrDownLevel); + } - static int ThePyrDownLevel; - static float TheMarkerSize; + MDetector.setCornerRefinementMethod(MarkerDetector::LINES); + + char key=0; + int index=0; + + //ros::Rate rate(10); + // Capture until press ESC or until the end of the video + while ((key != 'x') && (key!=27) && TheVideoCapturer.grab() && node_vis.ok() && keepMoving) + { + TT_S = ros::Time::now().toSec(); + + /* --- For the purpose of showing the time --- + Mat frame; + TheVideoCapturer >> frame; // get a new frame from camera + imshow("video stream",frame); + waitKey(30); // 30 ms */ + + +if (TheVideoCapturer.retrieve(TheInputImage)) +{ + +// Detection of markers in the image passed + MDetector.detect(TheInputImage,TheMarkers,TheCameraParameters,TheMarkerSize); + TheInputImage.copyTo(TheInputImageCopy); + geometry_msgs::PoseStamped msg; + + float x_t, y_t, z_t; + + if (TheMarkers.size()>0) + { + found = true; + //ROS_INFO("MARKER FOUND!!! ... \n"); + }else + { + found = false; + keepMoving = false; + ROS_INFO_STREAM("Marker is lost, successful docking trials : " << (docking_counter - 1) << "\n"); + //RandomPose(x_new,y_new,theta_new); + //move2docking(-control_signalX, -control_signalY, control_signalYAW); + } + + if (node_vis.ok() && found) + { + //y_t = -TheMarkers[0].Tvec.at<Vec3f>(0,0)[0]; // changed !!! + y_t = TheMarkers[0].Tvec.at<Vec3f>(0,0)[0]; + x_t = TheMarkers[0].Tvec.at<Vec3f>(0,0)[1]; + z_t = TheMarkers[0].Tvec.at<Vec3f>(0,0)[2]; + + Mat R(3,3,cv::DataType<float>::type); + + // You need to apply cv::Rodrigues() in order to obatain angles wrt to camera coords + Rodrigues(TheMarkers[0].Rvec,R); + + roll = atan2(R.at<float>(1,0), R.at<float>(0,0)); + pitch = atan2(-R.at<float>(2,0),pow((pow(R.at<float>(2,1),2)+pow(R.at<float>(2,2),2)),.5)); + yaw = atan2(R.at<float>(2,1), R.at<float>(2,2)); // useful + + // Adding Camera frame to Robot Frame --- + tf::Quaternion quat_CAM = tf::createQuaternionFromRPY(0, 0, 0); + broadcaster.sendTransform(tf::StampedTransform(tf::Transform(quat_CAM,tf::Vector3(.25, 0, .5)),ros::Time::now(),"/base_link","/camera")); + + + // Adding Marker frame to Camera Frame --- + tf::Quaternion quat_M = tf::createQuaternionFromRPY(roll,pitch,yaw); + broadcaster.sendTransform(tf::StampedTransform(tf::Transform(quat_M,tf::Vector3(x_t, y_t, z_t)),ros::Time::now(),"/camera","/marker")); + + msg.header.frame_id = "/camera"; + + // Publish Position + msg.pose.position.x = x_t; + msg.pose.position.y = y_t; + msg.pose.position.z = z_t; + + // Publish Orientation + msg.pose.orientation.x = roll; + msg.pose.orientation.y = pitch; + msg.pose.orientation.z = yaw; + + MarPose_pub.publish(msg); + + } + + /*// Print other rectangles that contains no valid markers + for (unsigned int i=0;i<MDetector.getCandidates().size();i++) + { + Marker m( MDetector.getCandidates()[i],10); + m.draw(TheInputImageCopy,Scalar(0,255,0),2); + }*/ + + for (unsigned int i=0;i<TheMarkers.size();i++) + { + int currentMarID = TheMarkers[i].id; + TheMarkers[i].draw(TheInputImageCopy,Scalar(0,255,0),2) ; + + CvDrawingUtils::draw3dCube(TheInputImageCopy,TheMarkers[i],TheCameraParameters); + CvDrawingUtils::draw3dAxis(TheInputImageCopy,TheMarkers[i],TheCameraParameters); + + //Marker ID to string + stringstream marker_id_string; + marker_id_string << "marker_ " << currentMarID; + } + + if (update_images) + { + imshow("INPUT IMAGE",TheInputImageCopy); + //imshow("THRESHOLD IMAGE",MDetector.getThresholdedImage()); + } + +}else +{ + printf("retrieve failed\n"); +} + +key=cv::waitKey(30); +// If space is hit, don't render the image. + +if (key == ' ') +{ + update_images = !update_images; +} + + ros::spinOnce(); + + TT_E = ros::Time::now().toSec(); + ROS_INFO_STREAM(" visualization while loop duration = " << (TT_E - TT_S) <<" \n"); + + } +} +void PID4Docking::camCB(const geometry_msgs::PoseStamped::ConstPtr& CamFB) // subscriber +{ +camPose[0] = CamFB->pose.position.x; // not important!!! + + +camPose[1] = CamFB->pose.position.y; // y pose +camPose[2] = CamFB->pose.position.z; // x_rob + +camPose[3] = CamFB->pose.orientation.x; // Robot roll +camPose[4] = CamFB->pose.orientation.y; // Robot pitch +camPose[5] = CamFB->pose.orientation.z; // Robot yaw - static bool update_images,found,Go2RandomPose; + /*ROS_INFO_STREAM("--------- PID gains in trial no. " << docking_counter << " : ---------\n"); + ROS_INFO_STREAM(" Kp_y = " << Kp_y << " , Ki_y = " << Ki_y << " , Kd_y = " << Kd_y << "\n"); + ROS_INFO_STREAM(" Kp_theta = " << Kp_theta << " , Ki_theta = " << Ki_theta << " , Kd_theta = " << Kd_theta << "\n");*/ + + ROS_INFO_STREAM(" --------------------- Pose estimation ------------------ \n"); + + // yaw has an offset of 180 deg. + if (camPose[5] > 0) + { + theta_with_offset = camPose[5] - y_off; + } else + { + theta_with_offset = camPose[5] + y_off; + } + + if (theta_with_offset > 0) + { + //x_robINmar_coor = -camPose[2] * cos(theta_with_offset) + camPose[1] * sin(theta_with_offset); + x_robINmar_coor = camPose[2] * cos(theta_with_offset) - camPose[1] * sin(theta_with_offset); + y_robINmar_coor = -camPose[2] * sin(theta_with_offset) + camPose[1] * cos(theta_with_offset); + + } else if (theta_with_offset < 0) + { + //x_robINmar_coor = -camPose[2] * cos(theta_with_offset) - camPose[1] * sin(theta_with_offset); + x_robINmar_coor = camPose[2] * cos(theta_with_offset) - camPose[1] * sin(theta_with_offset); + y_robINmar_coor = -camPose[2] * sin(theta_with_offset) + camPose[1] * cos(theta_with_offset); + } else + { + ROS_INFO_STREAM(" Mew condition should be added for theta! \n"); + } + + ROS_INFO_STREAM("theta = " << theta_with_offset << "rad. =~ " << theta_with_offset*(180.0/CV_PI) << " deg. \n"); + ROS_INFO_STREAM(" theta_ref = " << RefPose[3] << " rad. =~ " << (180/CV_PI) * RefPose[3] << " deg. \n"); + ROS_INFO_STREAM(" X_mar = " << x_robINmar_coor << " vs. X_ref = " << RefPose[2] << " \n"); + ROS_INFO_STREAM(" Y_mar = " << y_robINmar_coor << " vs. Y_ref = " << RefPose[1] << " \n"); + + ROS_INFO_STREAM(" y_t = " << camPose[1] << " \n"); + ROS_INFO_STREAM(" x_t = " << camPose[2] << " \n"); + + ROS_INFO_STREAM("------------------------------------------------------ \n "); + + if(Go2RandomPose == false) + { + ROS_INFO_STREAM("---------- MOVING TOWARDS DOCKING PLATFORM --------- \n "); + if ( + (abs(RefPose[2] - x_robINmar_coor) <= x_dock_thresh) + ) + { + dock_finished = ros::Time::now().toSec(); + docking_duration = dock_finished - dock_started; + ROS_INFO_STREAM("docking No. " << docking_counter << " is finished in "<< docking_duration <<" sec, moving to new Random Pose\n"); + keepMoving = false; + GenerateRandomVal(); + docking_counter ++; + speed_reducer_X = speed_reducer_Y = speed_reducer_theta = 1; + //Go2RandomPose = true; + + // to make sure that y & theta are within the threshold... + } else if (abs(RefPose[2] - x_robINmar_coor) <= safety_margin_X) + { + if( + (abs(RefPose[1] - y_robINmar_coor) > y_dock_thresh) || + (abs(RefPose[3] - theta_with_offset) > theta_dock_thresh) + ) + { + ROS_INFO_STREAM(" delta_X < " << safety_margin_X << " m., Fixing Y or theta. \n "); + speed_reducer_Y = speed_reducer_theta = 1; + Controller(RefPose[2], RefPose[2], RefPose[1], y_robINmar_coor, RefPose[3], theta_with_offset,.1); + } else if( + (abs(RefPose[1] - y_robINmar_coor) <= y_dock_thresh) && + (abs(RefPose[3] - theta_with_offset) <= theta_dock_thresh) + ) + { + ROS_INFO("y & theta fixed successfully, MOVING STRAIGHT AHEAD ... \n"); + + /*speed_reducer_X = .06; // for x_dot = .1 =>.06*/ + speed_reducer_X = .04; // for x_dot = .15 =>.04 ---- optimal docking time and Y-axis offset ---- + /*speed_reducer_X = .0375; // for x_dot = .16 =>.0375*/ + + Controller(RefPose[2], x_robINmar_coor, RefPose[1], RefPose[1], RefPose[3], RefPose[3],.1); + } + }else + { + speed_reducer_X = 1; + Controller(RefPose[2], x_robINmar_coor, RefPose[1], y_robINmar_coor, RefPose[3], theta_with_offset,.1); + } + } else + { + ROS_INFO("---------- MOVING TOWARDS RANDOM POSE ---------\n"); + Undocking(x_new,y_new,theta_new); + } +} + +void PID4Docking::Controller(double RefX, double MarPoseX, double RefY, double MarPoseY, double RefYAW, double MarPoseYAW, double dt) +{ + ROS_INFO_STREAM("--------------------- Controller started ----------------------\n "); - bool readArguments ( int argc,char **argv ); + // -----------------X--------------------- // + if(abs(RefX - MarPoseX) > x_dock_thresh) + { + /*// e(t) = setpoint - actual value; + curr_errorX = RefX - MarPoseX; - static const string trackbarWindowName; + // Integrated error + int_errorX += curr_errorX * dt; + // differentiation + diffX = ((curr_errorX - prev_errorX) / dt); + // scalling + p_termX = Pos_Px * curr_errorX; + i_termX = Pos_Ix * int_errorX; + d_termX = Pos_Dx * diffX; + // control signal + control_signalX = p_termX + i_termX + d_termX; + prev_errorX = curr_errorX;*/ + + //control_signalX = speed_reducer_X * 0.1; + control_signalX = speed_reducer_X * 0.15; + //control_signalX = speed_reducer_X * 0.16; + } else + { + control_signalX = 0; // 5e-5 + } + // -----------------Y--------------------- // + + if((RefY - MarPoseY) < -y_dock_thresh || (RefY - MarPoseY) > y_dock_thresh) + { + // e(t) = setpoint - actual value; + curr_errorY = RefY - MarPoseY; + + // Integrated error + int_errorY += curr_errorY * dt; + /* + // -- windup gaurd -- + if (int_error < ) + {} + else if () + {}*/ - void Controller(double RefX, double MarPoseX, double refY, double MarPoseY, double refYAW, double MarPoseYAW, double dt); + // differentiation + diffY = ((curr_errorY - prev_errorY) / dt); - void dock(double VelX, double VelY, double omegaZ); + // scalling + p_termY = Kp_y * curr_errorY; + i_termY = Ki_y * int_errorY; + d_termY = Kd_y * diffY; - void move2docking(double VelX_est, double VelY_est, double omegaZ_est); - //double* Q; +ROS_INFO_STREAM("pY = " << p_termY << ", iY = " << i_termY << " dY = " << d_termY<< " \n"); + + control_signalY = p_termY + i_termY + d_termY; + control_signalY = speed_reducer_Y * control_signalY; + prev_errorY = curr_errorY; + + } else if ((RefY - MarPoseY) <= y_dock_thresh && (RefY - MarPoseY) >= -y_dock_thresh) + { + control_signalY = 0; + } + + // -------------------YAW--------------------------// + if(abs(RefYAW - MarPoseYAW) > theta_dock_thresh) + { + //ROS_INFO_STREAM("REF = "<< RefYAW<< ", theta = "<< MarPoseYAW<< ".\n"); + // e(t) = setpoint - actual value; + curr_errorYAW = RefYAW - MarPoseYAW; + // Integrated error + int_errorYAW += curr_errorYAW * dt; -public: + // differentiation + diffYAW = ((curr_errorYAW - prev_errorYAW) / dt); - PID4Docking(); + //ROS_INFO_STREAM(" adjusting orientation! \n"); + // scalling + p_termYAW = Kp_theta * curr_errorYAW; + i_termYAW = Ki_theta * int_errorYAW; + d_termYAW = Kd_theta * diffYAW; + +//ROS_INFO_STREAM("p_theta = " << p_termYAW << ", i_theta = " << i_termYAW << " d_theta = " << d_termYAW << " \n"); + // control signal + control_signalYAW = p_termYAW + i_termYAW + d_termYAW; + + + // save the current error as the previous one + // for the next iteration. + prev_errorYAW = curr_errorYAW; - ~PID4Docking(); - - Mat getCurrentImage(); - - void imageCb(const sensor_msgs::ImageConstPtr& msg); - - void camCB(const geometry_msgs::PoseStamped::ConstPtr& CamFB); - - static void cvTackBarEvents(int value,void* ptr); - - void ProgStart(int argc,char** argv); - - void createTrackbars(); - - void myhandler(int value); - - void GenerateRandomVal(); - void Undocking(double X_rand, double Y_rand, double theta_rand); - - void ContStart(); - - static double Kp_x,Ki_x,Kd_x; - - static double Kp_theta,Ki_theta,Kd_theta; + } else if (abs(RefYAW - MarPoseYAW) <= theta_dock_thresh) + { + control_signalYAW = 0; + } + + /* --- */ + ROS_INFO_STREAM("Control signalX = " << control_signalX <<"\n"); + ROS_INFO_STREAM("Control signalY = " << control_signalY << "\n"); + ROS_INFO_STREAM("Control signalYAW = "<< control_signalYAW <<"\n"); + + ROS_INFO_STREAM(" ---------------------- Controller ended ----------------------- \n"); + //dock(control_signalX, control_signalY, control_signalYAW); +} + +void PID4Docking::dock(double VelX, double VelY, double omegaZ) +{ + ROS_INFO(".... REAL .... !"); + geometry_msgs::Twist msg; + + msg.linear.x = VelX; + msg.linear.y = VelY; + msg.angular.z = omegaZ; + + commandPub.publish(msg); + ROS_INFO_STREAM(" Current speed of robot: \n" << msg << ".\n"); +} - static double safety_margin_X; - double x_rand_SM; +void PID4Docking::move2docking(double VelX_est, double VelY_est, double omegaZ_est) +{ + + ROS_INFO_STREAM(" Zmar = " << camPose[2] << " m. \n"); + ROS_INFO_STREAM(" Zref = " << RefPose[2] << " m. \n"); - // ---- CONTROLL PARAMETERS ------ // - static double prev_errorX; - static double int_errorX; - static double curr_errorX; - static double diffX; - static double p_termX; - static double d_termX; - static double i_termX; - static double control_signalX; + ROS_INFO_STREAM(" Ymar = " << camPose[1] << " m. \n"); + ROS_INFO_STREAM(" Yref = " << RefPose[1] << " m. \n"); - static double prev_errorY; - static double int_errorY; - static double curr_errorY; - static double diffY; - static double p_termY; - static double d_termY; - static double i_termY; - static double control_signalY; + ROS_INFO_STREAM(" rollmar = " << camPose[3] << " rad. \n"); + ROS_INFO_STREAM(" rollref = " << RefPose[3] << " rad. \n"); - static double prev_errorYAW; - static double int_errorYAW; - static double curr_errorYAW; - static double diffYAW; - static double p_termYAW; - static double d_termYAW; - static double i_termYAW; - static double control_signalYAW; - // ---- CONTROLL PARAMETERS ------ // + ROS_INFO(".... ESTIMATION .... !\n"); + geometry_msgs::Twist msg; - static double x_new,y_new,theta_new; // inp (y,theta) - static const double y_up,y_dwn,theta_up,theta_dwn; - static double Kp_y,Ki_y,Kd_y; // actions (Kp,Ki,Kd) + if (VelX_est == 0 && VelY_est == 0 && omegaZ_est == 0) + { + VelX_est = .0001; + VelX_est = .0001; + omegaZ_est = 0; + } + + msg.linear.x = VelX_est; + msg.linear.y = VelY_est; + msg.angular.z = omegaZ_est; - static double docking_counter; - static double dock_started,dock_finished,docking_duration; + commandPub.publish(msg); - static double TT_S,TT_E; - - static double zeroMin,zeroMax; + ROS_INFO_STREAM(" Current ESTIMATED speed of robot: \n" << msg << ".\n"); +} +// ---- Controller part -------- END ------ - static double y_dock_thresh,x_dock_thresh,theta_dock_thresh; - static double x_thresh_undock,y_thresh_undock,theta_thresh_undock; +void PID4Docking::GenerateRandomVal() +{ - static double rand_X_SM,rand_A_esp,rand_Y_esp; - static double speed_reducer_X,speed_reducer_Y,speed_reducer_theta; - static float r_off,p_off,y_off; - static float roll,yaw,pitch; - static double theta_with_offset,x_robCen2cam,y_robCen2cam; + // ---------------- PID gains ------------------ + Kp_y = ((double) rand() / (RAND_MAX)) * (.76 - .4) + .4; //.1 < Kp < .76 + Ki_y = ((double) rand() / (RAND_MAX)) * .006; // 0 < Ki < .006 + Kd_y = ((double) rand() / (RAND_MAX)) * .02; // 0 < Kd < .01 - static double x_robINmar_coor,y_robINmar_coor; + // ------------------ Generating Random Pose ------------------ + //x_new = ((double) rand() / (RAND_MAX)) * (1.1 - x_rand_SM) + x_rand_SM; + x_new = 1.1; + y_new = ((double) rand() / (RAND_MAX)) * (y_up - y_dwn) + y_dwn; // will be used for Q_Learning + theta_new = ((double) rand() / (RAND_MAX)) * (theta_up - theta_dwn) + theta_dwn; // will be used for Q_Learning +} + +void PID4Docking::Undocking(double X_rand, double Y_rand, double theta_rand) +{ + ROS_INFO_STREAM(" Xr = " << X_rand << ", Yr = " << Y_rand << ", Thetar = " << theta_rand << " rad ~ " << theta_rand * (180/CV_PI) << " deg\n"); + ROS_INFO_STREAM(" -------------------------------------------------------------- \n"); +double vel_x,vel_y,omega_z; + +geometry_msgs::Twist msg_new; + // CCW ==>> w > 0 , CW ==>> w < 0 + // Leaving docking station, moving towards x-axis SM + if (X_rand - camPose[2] > x_thresh_undock) + { + ROS_INFO_STREAM(" Adjusting X, moving backward ... \n"); + vel_x = -.04; + } else if (X_rand - camPose[2] < -x_thresh_undock) + { + ROS_INFO_STREAM(" Adjusting X, moving forward ... \n"); + vel_x = .04; + }else if (abs(X_rand - camPose[2]) <= x_thresh_undock) + { + ROS_INFO(" X-axis is fixed, adjusting Y & theta - axes ... \n"); + if ((camPose[1] - Y_rand > y_thresh_undock) && (theta_rand > 0)) + { + if(abs(abs(camPose[3]) - abs(theta_rand)) > theta_thresh_undock) + { + ROS_INFO("moving 2 left side & CW rot. \n"); + vel_y = .03; + omega_z = -.01; + } else + { + ROS_INFO("CW rot. is fixed, only moving 2 left side ...\n"); + vel_y = .03; + } + } else if ((camPose[1] - Y_rand < -y_thresh_undock) && (theta_rand < 0)) + { + if(abs(abs(camPose[3]) - abs(theta_rand)) > theta_thresh_undock) + { + ROS_INFO("moving 2 right side & CCW rot. \n"); + vel_y = -.03; + omega_z = .01; + }else + { + ROS_INFO("CCW rot. is fixed, only moving 2 right side ... \n"); + vel_y = -.03; + } + }else if (abs(camPose[1] - Y_rand) <= y_thresh_undock) + { + ROS_INFO(" Y-axis is fixed, adjusting theta-axis ... ! \n"); + if (abs(abs(camPose[3]) - abs(theta_rand)) <= theta_thresh_undock) + { + ROS_INFO(" Robot is in a new random Pose! \n"); + //keepMoving = false; + Go2RandomPose = false; + } else + { + if(theta_rand > 0) + { + ROS_INFO_STREAM(" theta > 0 => Rob rot. is CW(-) \n"); + omega_z = -.01; + } else + { + ROS_INFO_STREAM(" theta < 0 => Rob rot. is CCW(+) \n"); + omega_z = .01; + } + } + } else if ((camPose[1] - Y_rand > y_thresh_undock) && (theta_rand < 0)) + { + if(abs(abs(camPose[3]) - abs(theta_rand)) > theta_thresh_undock) + { + ROS_INFO("moving 2 left side & CCW rot., chance of losing marker \n"); + vel_y = .03; + omega_z = .01; + } else + { + ROS_INFO("CCW rot. is fixed, only moving 2 left side ... \n"); + vel_y = .03; + } + } else if ((camPose[1] - Y_rand < -y_thresh_undock) && (theta_rand > 0)) + { + if(abs(abs(camPose[3]) - abs(theta_rand)) > theta_thresh_undock) + { + ROS_INFO("moving 2 right side & CW rot., chance of losing marker \n"); + vel_y = -.03; + omega_z = -.01; + } else + { + ROS_INFO("CW rot. is fixed, only moving 2 right side ... \n"); + vel_y = -.03; + } + + } else + { + ROS_INFO(" New condition should be added! \n"); + keepMoving = false; + } + } + msg_new.linear.x = vel_x; + msg_new.linear.y = vel_y; + msg_new.angular.z = omega_z; + +commandPub.publish(msg_new); + +} - double marpose[6]; - double camPose[6]; - static const double RefPose[4]; - -};