消息分析器-----HANDLE_MSG

本文详细介绍了Windows消息分析器的工作原理及其逐步优化的过程,从基本的WndProc函数入手,逐步展示了如何利用消息分析器处理WM_CREATE、WM_PAINT等消息,并深入探讨了对话框消息处理中的特殊技巧。

windows消息分析器的实现很好理解,windows操作系统使用消息处理机制,那么,我们所设计的程序如何才能分辨和处理系统中的各种消息呢?这就是消息分析器的作用.

       简单来说,消息分析器就是一段代码,在我的讲述中,将分7重来循序渐进的介绍它.从最初的第1重到最成熟的第7重,它的样子会有很大的变化.但,实现的功能都是一样的,所不同的,仅仅是变得更加简练罢了.

      程序开始时候,是WinMain函数,然后会生成初始的窗口,同时会调用WndProc函数.这是一个自定义的函数,名字也会有变化,但其功能是一样的,就是运行消息分析器.WndProc函数如下:

LRESULT CALLBACK WndProc (HWND hwnd, UINT msg,WPARAM wParam, LPARAM lParam)
{

//......

return DefWindowProc(hwnd, msg, wParam, lParam);

}

     这其中,hwnd是窗口的句柄,msg是系统发送来的消息的名字.wParam和lParam则是随消息一起发送来的消息参数.

     WndProc函数使用了消息分析器,下面把消息分析器的内容解释一下:

      第一重,当不同的消息出现时,在其中写入相应的程序语句即可。
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg,WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
// ...
return 0;

case WM_PAINT:
// ...
return 0;

case WM_DESTROY:
//...
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}

     第二重,运用三个消息分析器进行处理。
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
return HANDLE_WM_CREATE(hwnd, wParam, lParam, Cls_OnCreate);

case WM_PAINT:
return HANDLE_WM_PAINT(hwnd, wParam, lParam, Cls_OnPaint);

case WM_DESTROY:
return HANDLE_WM_DESTROY(hwnd, wParam, lParam, Cls_OnDestroy);
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
       这里的HANDLE_WM_CREATE,HANDLE_WM_PAINT,HANDLE_WM_DESTROY就是消息分析器。
      与消息不同之处就是在前面增加了“HANDLE_”字符,windows的消息分析器就是这样的模样。它的本质就是宏定义。其中的四个参数有三个都是从本函数的入口参数中直接得到的,即为hwnd, wParam, lParam。只有第四的参数是表明调用的函数。
      消息分析器是在winowsx.h文件中定义的。由此,可以看出第四个参数是调用的函数,其定义如下:

#define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn) ((fn)((hwnd), (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L)

#define HANDLE_WM_PAINT(hwnd, wParam, lParam, fn) ((fn)(hwnd), 0L)

#define HANDLE_WM_DESTROYCLIPBOARD(hwnd, wParam, lParam, fn) ((fn)(hwnd), 0L)

      0L是表示int类型的变量,其数值为0。
       int类型时,可在后面加l或者L(小写和大写形式)
      ussigned 无符号数时,可在后面加u或者U(小写和大写形式)
      float类型时,可在后面加f或者F(小写和大写形式)
       例如:
     128u 1024UL 1L 8Lu 3.14159F 0.1f

      LRESULT是一个系统的数据类型,其定义如下:
typedef LONG_PTR LRESULT;

     LONG_PTR也是一个系统的数据类型,其定义如下:
#if defined(_WIN64)
typedef __int64 LONG_PTR;
#else
typedef long LONG_PTR;
#endif
      由此可见,LRESULT的实质就是64位的long类型的变量

那么(LRESULT)-1L的实质并不是减法,而是((LRESULT)(-1L)),即强制类型转换

      第三重,把消息分析器的宏定义代换回去,就成了下面的样子
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
return Cls_OnCreate(hwnd, (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L;
// 如果处理了消息,则Cls_OnCreate应返回TRUE,导致WndProc返回0,否则Cls_OnCreate返回FALSE,导致WndProc返回-1;

case WM_PAINT:
return Cls_OnPaint(hwnd), 0L;
// 逗号表达式;Cls_OnPaint是void类型,这里返回0;

case WM_DESTROY:
return Cls_OnDestroy(hwnd), 0L; // 同Cls_OnPaint
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
      在逗号表达式,C++会计算每个表达式,但完整的逗号表达式的结果是最右边表达式的值。所以,会return 0。
     然后,就可以手动的编写各个处理函数了:Cls_OnCreate,Cls_OnPaint,WM_DESTROY。

     第四重,
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
HANDLE_MSG(hwnd, WM_CREATE, Cls_OnCreate);
HANDLE_MSG(hwnd, WM_PAINT, Cls_OnPaint);
HANDLE_MSG(hwnd, WM_DESTROY, Cls_OnDestroy);
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}

        HANDLE_MSG也是一个宏,它在windowsx.h中定义,如下:
#define HANDLE_MSG(hwnd, message, fn) case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))

       这个宏要做的就是根据不同的message(##用来连接前后的字符串),把自己“变成”相应的HANDLE_XXXXMESSAGE形式的宏,再通过相应的宏来执行消息处理代码。说白了,就是把message的消息做为替换,##就是一个替换的标志。如果没有##,就成了HANDLE_message了,这样,宏是不会被代换的。如果有,则会代换,如hwnd和fn。

       比如实际代码中写入:
HANDLE_MSG(hwnd, WM_CREATE, Cls_OnCreate)
       则经过转换就变成:
case (WM_CREATE): return HANDLE_WM_CREATE((hwnd), (wParam), (lParam), (Cls_OnCreate))
       这与第二重一模一样。

       以上四重,是消息分析器的基本使用,但,这不完整,消息分析器主要应用在对话框消息处理中。这里,窗口子类化是我们经常使用的手段,这也可以通过消息分析器实现,

      第五重,
LRESULT CALLBACK Dlg_Proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
HANDLE_MSG(hwnd, WM_INITDIALO , Cls_OnInitDialog); // 不能直接使用HANDLE_MSG宏
HANDLE_MSG(hwnd, WM_COMMAND, Cls_OnCommand); // 不能直接使用HANDLE_MSG宏
}
return false;
}
      由于是窗口子类化,所以,最后,返回的是false,以表明,如果没有约定响应的消息,则返回父亲窗口false,如果有,则返回ture,这是与前四重不同的地方。
一般情况下,对话框过程函数应该在处理了消息的情况下返回TRUE,如果没有处理,则返回FALSE。
       如果对话框过程返回了FALSE,那么对话框管理器为这条消息准备默认的对话操作。

       但是,这其中有错误,因为有的消息,需要单独处理。单独处理的消息列表见SetDlgMsgResult宏。

      第六重,这点小问题,这就需要用到SetDlgMsgResult(hwnd, msg, result)宏。

LRESULT CALLBACK Dlg_Proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_INITDIALO:
return (SetDlgMsgResult(hwnd, Msg, HANDLE_WM_INITDIALO((hwnd), (wParam), (lParam), (fn)));

case WM_COMMAND:
return (SetDlgMsgResult(hwnd, Msg, HANDLE_WM_COMMAND((hwnd), (wParam), (lParam), (fn)));
}
return false;
}
       这里,就用直接用到了第二重的消息分析器,而抛弃了其他。

       这个宏定义如下:
#define SetDlgMsgResult(hwnd, msg, result)
(
(
(msg) == WM_CTLCOLORMSGBOX ||
(msg) == WM_CTLCOLOREDIT ||
(msg) == WM_CTLCOLORLISTBOX ||
(msg) == WM_CTLCOLORBTN ||
(msg) == WM_CTLCOLORDLG ||
(msg) == WM_CTLCOLORSCROLLBAR ||
(msg) == WM_CTLCOLORSTATIC ||
(msg) == WM_COMPAREITEM ||
(msg) == WM_VKEYTOITEM ||
(msg) == WM_CHARTOITEM ||
(msg) == WM_QUERYDRAGICON ||
(msg) == WM_INITDIALOG
) ?
(BOOL)(result) :
(SetWindowLongPtr((hwnd), DWLP_MSGRESULT, (LPARAM)(LRESULT)(result)), TRUE)
)

       为了表述清楚,所以用了此格式,这是一个条件表达式,首先对消息类型进行考察。如果对话框过程处理的消息恰巧为返回特定值中的一个,则如实返回result;
不要被前面的BOOL蒙蔽,BOOL在头文件中的定义实际上是一个int型,一旦需要返回非TRUE或FALSE的其他值,照样可以;
这样,我们的Cls_OnInitDialog就能够正确的返回它的BOOL值了,而Cls_OnCommand在处理之后,也可以由后面的逗号表达式正确的返回一个TRUE表示消息已处理。

      第七重,我们还可以把case也包含进来,就成了如下的样子。

LRESULT CALLBACK Dlg_Proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Cls_OnInitDialog);
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Cls_OnCommand);
}
return false;
}

chHANDLE_DLGMSG是牛人定义的一个宏,它把case也包含进来了。
#define chHANDLE_DLGMSG(hwnd, message, fn) case (message): return (SetDlgMsgResult(hwnd, uMsg, HANDLE_##message((hwnd), (wParam), (lParam), (fn))))

       这样,程序中的语句
switch (uMsg)
{
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
chHANDLE_DLGMSG(hwnd, WM_SIZE, Dlg_OnSize);
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
}

        就被翻译成:
switch (uMsg)
{
case (WM_INITDIALOG):
return (SetDlgMsgResult(hwnd, uMsg, HANDLE_WM_INITDIALOG((hwnd), (wParam), (lParam), (Dlg_OnInitDialog))));

case (WM_SIZE)
return (SetDlgMsgResult(hwnd, uMsg, HANDLE_WM_SIZE((hwnd), (wParam), (lParam), (Dlg_OnSize))));

case (WM_COMMAND)
return (SetDlgMsgResult(hwnd, uMsg, HANDLE_WM_COMMAND((hwnd), (wParam), (lParam), (Dlg_OnCommand))));
}

        至此,消息分析器,就介绍完毕。

你从学长手里拿到这个代码,看不懂,详细一行一行代码的解释一下,功能似乎就是用来记录遥控器遥控的小车得到的路径的坐标和航向角信息:#include "path_record.hpp" #include <vector> #include <ros/ros.h> #include <tf/tf.h> #include <fstream> #include <ros/package.h> #include <ros/node_handle.h> #include <tf/transform_broadcaster.h> #include <nav_msgs/Path.h> #include <nav_msgs/Odometry.h> #include <std_msgs/Float64MultiArray.h> #include <geometry_msgs/Pose.h> #include <geometry_msgs/PoseArray.h> #include <geometry_msgs/PoseWithCovarianceStamped.h> #include <sys/time.h> #include <time.h> #include <cmath> #include <iostream> #include<sstream> #include<string> #include <unistd.h> using namespace std; int i = 2; path_record::path_record(/* args */) { } path_record::~path_record() { } void path_record::record_path(const nav_msgs::Odometry::ConstPtr odometry_msg){ char p; p='c'; if (this->count == 0) { double raw, pitch, theta; tf::Quaternion q; tf::quaternionMsgToTF(odometry_msg->pose.pose.orientation, q); tf::Matrix3x3(q).getRPY(raw, pitch, theta); std::string roadMap_path = "/home/yt/agv/data/odom.txt";//地图录制位置 FILE *fp_s; fp_s = fopen("/home/yt/agv/data/odom.txt","a"); fprintf(fp_s, "%c %lf %lf %lf", p,odometry_msg->pose.pose.position.x, odometry_msg->pose.pose.position.y,odometry_msg->pose.pose.position.z); // Angle fprintf(fp_s, "\r\n"); fclose(fp_s); start_x = odometry_msg->pose.pose.position.x; start_y = odometry_msg->pose.pose.position.y; this->count++; }else{ sample_distance = sample_distance+sqrt(pow((odometry_msg->pose.pose.position.x - start_x), 2) + pow((odometry_msg->pose.pose.position.y- start_y), 2) ); start_x = odometry_msg->pose.pose.position.x; start_y = odometry_msg->pose.pose.position.y; cout<<odometry_msg->pose.pose.position.x<<endl; cout<<"odometry_msg->pose.pose.position.y"<<odometry_msg->pose.pose.position.y<<endl; if ( sample_distance >= S0) { double raw, pitch, theta; tf::Quaternion q; tf::quaternionMsgToTF(odometry_msg->pose.pose.orientation, q); tf::Matrix3x3(q).getRPY(raw, pitch, theta); FILE *fp_s; fp_s = fopen("/home/yt/agv/data/odom.txt","a"); fprintf(fp_s, "%c %lf %lf %lf",p, odometry_msg->pose.pose.position.x, odometry_msg->pose.pose.position.y, odometry_msg->pose.pose.position.z); // Angle fprintf(fp_s, "\r\n"); fclose(fp_s); sample_distance = 0; this->count++; } } } void path_record::record_path_GPS(const geometry_msgs::PoseStamped::ConstPtr odometry_msg){ cout<<"qqqqqqqqqqqqqq"<<endl; char p; p='c'; if (this->count == 0) { double raw, pitch, theta; tf::Quaternion q; tf::quaternionMsgToTF(odometry_msg->pose.orientation, q); // 将ROS四元数转换为TF四元数 tf::Matrix3x3(q).getRPY(raw, pitch, theta); // 从四元数获取欧拉角(RPY) std::string roadMap_path = "/home/yt/agv/data/GPS.txt";//地图录制位置 FILE *fp_s; fp_s = fopen("/home/yt/agv/data/GPS.txt","a"); // 写入位置数据(x,y,z) fprintf(fp_s, "%c %lf %lf %lf", p,-odometry_msg->pose.position.x, odometry_msg->pose.position.y,theta); // Angle fprintf(fp_s, "\r\n"); fclose(fp_s); // 保存起始位置 start_x = odometry_msg->pose.position.x; start_y = odometry_msg->pose.position.y; this->count++; }else{ sample_distance = sample_distance+sqrt(pow((-odometry_msg->pose.position.x - start_x), 2) + pow((odometry_msg->pose.position.y- start_y), 2) ); start_x = odometry_msg->pose.position.x; start_y = odometry_msg->pose.position.y; ROS_INFO_STREAM (" /////////////////////// sample_distance == "<< sample_distance ); ROS_INFO_STREAM (" /////////////////////// start_x == "<< start_x ); ROS_INFO_STREAM (" /////////////////////// odometry_msg->pose.pose.position.x == "<< odometry_msg->pose.position.x ); if ( sample_distance >= S0) { double raw, pitch, theta; tf::Quaternion q; tf::quaternionMsgToTF(odometry_msg->pose.orientation, q); tf::Matrix3x3(q).getRPY(raw, pitch, theta); FILE *fp_s; fp_s = fopen("/home/yt/agv/data/GPS.txt","a"); fprintf(fp_s, "%c %lf %lf %lf",p, odometry_msg->pose.position.x, odometry_msg->pose.position.y,theta); // Angle fprintf(fp_s, "\r\n"); fclose(fp_s); sample_distance = 0; this->count++; } } } void path_record::record_path2(const nav_msgs::Odometry::ConstPtr odometry_msg){ cout<<"/////start_path_record////////"<<endl; // ros::Rate loop_rate(10); char p; p='c'; double raw, pitch, theta; tf::Quaternion q; tf::quaternionMsgToTF(odometry_msg->pose.pose.orientation, q); tf::Matrix3x3(q).getRPY(raw, pitch, theta); FILE *fp_s; fp_s = fopen("/home/lwh/Lpp_files/data/odom3_road_path.txt","a"); fprintf(fp_s, "%c %lf %lf %lf", p, odometry_msg->pose.pose.position.x, odometry_msg->pose.pose.position.y,theta); // Angle fprintf(fp_s, "\r\n"); fclose(fp_s); // loop_rate.sleep(); } void path_record::odometryGetCallBack_slam(const nav_msgs::Odometry::ConstPtr odometry_msg){ char p; p='c'; if (this->count == 0) { double raw, pitch, theta; tf::Quaternion q; tf::quaternionMsgToTF(odometry_msg->pose.pose.orientation, q); tf::Matrix3x3(q).getRPY(raw, pitch, theta); std::string roadMap_path = "/home/agv/agv/data/slam.txt";//地图录制位置 FILE *fp_s; fp_s = fopen("/home/agv/agv/data/slam.txt","a"); fprintf(fp_s, "%c %lf %lf %lf", p,odometry_msg->pose.pose.position.x,-odometry_msg->pose.pose.position.y,theta); // Angle fprintf(fp_s, "\r\n"); fclose(fp_s); start_x = odometry_msg->pose.pose.position.x; start_y=-odometry_msg->pose.pose.position.y; this->count++; }else{ float dis_by=sqrt(pow(( odometry_msg->pose.pose.position.x - start_x), 2) + pow((odometry_msg->pose.pose.position.y- start_y), 2) ); if(abs(dis_by) > 0.5) {dis_by=0;} sample_distance = sample_distance+dis_by; // sample_distance = sample_distance+sqrt(pow((odometry_msg->pose.pose.position.x - start_x), 2) + pow((-odometry_msg->pose.pose.position.y- start_y), 2) ); cout<<"start_x"<<start_x<<endl; cout<<"start_y"<<start_y<<endl; cout<<"odometry_msg->pose.pose.position.x"<<odometry_msg->pose.pose.position.x<<endl; cout<<"odometry_msg->pose.pose.position.y"<<odometry_msg->pose.pose.position.y<<endl; start_x =odometry_msg->pose.pose.position.x; start_y =-odometry_msg->pose.pose.position.y; if ( sample_distance >= S0) { cout<<"qqqqqqqqqqqqqq"<<endl; double raw, pitch, theta; tf::Quaternion q; tf::quaternionMsgToTF(odometry_msg->pose.pose.orientation, q); tf::Matrix3x3(q).getRPY(raw, pitch, theta); FILE *fp_s; fp_s = fopen("/home/agv/agv/data/slam.txt","a"); fprintf(fp_s, "%c %lf %lf %lf",p, odometry_msg->pose.pose.position.x, -odometry_msg->pose.pose.position.y,theta); // Angle fprintf(fp_s, "\r\n"); fclose(fp_s); sample_distance = 0; this->count++; } } } void path_record::odometryGetCallBack_slam2(const nav_msgs::Odometry::ConstPtr odometry_msg){ char p; p='c'; ros::Rate rate(0.5); rate.sleep(); if (this->count == 0) { double raw, pitch, theta; tf::Quaternion q; tf::quaternionMsgToTF( odometry_msg->pose.pose.orientation, q); tf::Matrix3x3(q).getRPY(raw, pitch, theta); std::string roadMap_path = "/home/agv/agv/data/slam1.txt";//地图录制位置 FILE *fp_s; fp_s = fopen("/home/agv/agv/data/slam1.txt","a"); fprintf(fp_s, "%c %lf %lf %lf", p, odometry_msg->pose.pose.position.x, odometry_msg->pose.pose.position.y,theta); // Angle fprintf(fp_s, "\r\n"); fclose(fp_s); start_x = odometry_msg->pose.pose.position.x; start_y= odometry_msg->pose.pose.position.y; this->count++; }else{ float dis_by=sqrt(pow(( odometry_msg->pose.pose.position.x - start_x), 2) + pow(( odometry_msg->pose.pose.position.y- start_y), 2) ); if(abs(dis_by) < 0.1) {dis_by=0;} sample_distance = sample_distance+dis_by; cout<<"start_x"<<start_x<<endl; cout<<"start_y"<<start_y<<endl; cout<<"odometry_msg->pose.pose.position.x"<< odometry_msg->pose.pose.position.x<<endl; cout<<"odometry_msg->pose.pose.position.y"<< odometry_msg->pose.pose.position.y<<endl; cout<<"www"<<sample_distance<<endl; start_x = odometry_msg->pose.pose.position.x; start_y = odometry_msg->pose.pose.position.y; if ( sample_distance >= S0) { cout<<"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"<<endl; double raw, pitch, theta; tf::Quaternion q; tf::quaternionMsgToTF( odometry_msg->pose.pose.orientation, q); tf::Matrix3x3(q).getRPY(raw, pitch, theta); FILE *fp_s; fp_s = fopen("/home/agv/agv/data/slam1.txt","a"); fprintf(fp_s, "%c %lf %lf %lf",p, odometry_msg->pose.pose.position.x, odometry_msg->pose.pose.position.y,theta); // Angle fprintf(fp_s, "\r\n"); fclose(fp_s); sample_distance = 0; this->count++; } } } void path_record::odometryGetCallBack_slam3(const nav_msgs::Odometry::ConstPtr odometry_msg){ ros::Rate rate(5); rate.sleep(); char p; p='c'; if (this->count == 0) { double raw, pitch, theta; tf::Quaternion q; tf::quaternionMsgToTF(odometry_msg->pose.pose.orientation, q); tf::Matrix3x3(q).getRPY(raw, pitch, theta); std::string roadMap_path = "/home/yt/agv/data/0000001.txt";//地图录制位置 std::string roadMap_path_2 = "/home/yt/agv/data/shiyan3_10.txt"; FILE *fp_s; FILE *fp_s_2; fp_s = fopen("/home/yt/agv/data/0000001.txt","a"); fprintf(fp_s, "%c %lf %lf %lf", p,odometry_msg->pose.pose.position.x,odometry_msg->pose.pose.position.y,theta); // Angle fprintf(fp_s, "\r\n"); fclose(fp_s); fp_s_2 = fopen("/home/yt/agv/data/shiyan3_10.txt","a"); fprintf(fp_s_2, " %lf %lf %lf", odometry_msg->pose.pose.position.x,odometry_msg->pose.pose.position.y,theta); // Angle fprintf(fp_s_2, "\r\n"); fclose(fp_s_2); start_x = odometry_msg->pose.pose.position.x; start_y = odometry_msg->pose.pose.position.y; this->count++; }else{ float dis_by=sqrt(pow((odometry_msg->pose.pose.position.x - start_x), 2) + pow((odometry_msg->pose.pose.position.y- start_y), 2) ); if(dis_by<0.007){ dis_by=0; } sample_distance = sample_distance+dis_by; start_x =odometry_msg->pose.pose.position.x; start_y =odometry_msg->pose.pose.position.y; if ( sample_distance >= S0) { cout<<"qqqqqqqqqqqqqq"<<endl; double raw, pitch, theta; tf::Quaternion q; tf::quaternionMsgToTF(odometry_msg->pose.pose.orientation, q); tf::Matrix3x3(q).getRPY(raw, pitch, theta); FILE *fp_s; FILE *fp_s_2; fp_s = fopen("/home/yt/agv/data/0000001.txt","a"); fprintf(fp_s, "%c %lf %lf %lf",p, odometry_msg->pose.pose.position.x,odometry_msg->pose.pose.position.y,theta); // Angle fprintf(fp_s, "\r\n"); fclose(fp_s); fp_s_2 = fopen("/home/yt/agv/data/shiyan3_10.txt","a"); fprintf(fp_s_2, "%d %lf %lf %lf", i ,odometry_msg->pose.pose.position.x,odometry_msg->pose.pose.position.y,theta); // Angle fprintf(fp_s_2, "\r\n"); fclose(fp_s_2); i = i + 1; sample_distance = 0; this->count++; } } ///////////////////////////////////////////// } void path_record::nodeStart(int argc, char **argv){ ros::init(argc, argv, "path_record"); ros::NodeHandle nc; count = 0; // 订阅相关节点 // ros::Subscriber sub_odom = nc.subscribe("/odom", 1, &path_record::record_path, this);//录制轨迹话题小车里程计 // ros::Subscriber sub_odom = nc.subscribe("/rear_post", 1, &path_record::record_path_GPS, this);//录制轨迹话题GPS ros::Subscriber sub_odom = nc.subscribe("/localization", 1, &path_record::odometryGetCallBack_slam3, this); // 控制节点gps //ros::Subscriber sub_odom_2 = nc.subscribe("/localization", 1, &path_record::odometryGetCallBack_slam3_2, this); // 控制节点gps ros::spin(); } int main(int argc, char *argv[]) { path_record node; node.nodeStart(argc, argv); return(0); }
06-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值