我正在敲打这个错误。我创建了3个文件,其中1个是main.cpp,第2个是.cpp文件,第3个是.hpp代码文件。 由于某种原因,当我尝试从类方法调用它时,订阅者回调函数给我一个错误。代码如下:
文件1:main.cpp
#include "ControlTurtlebot.hpp"
int main(int argc, char **argv){
//initialize the ROS node
ros::init(argc, argv, "free_space_navigation_node");
ros::NodeHandle n;
ControlTurtlebot obj;
//subscribe to the odometry topic to get the position of the robot
obj.pose_subscriber = n.subscribe("/odom", 10, &ControlTurtlebot::poseCallback, &obj);
//register the velocity publisher
obj.pub =n.advertise<geometry_msgs::Twist>("mobile_base/commands/velocity", 1000);
ros::spinOnce();
ros::Rate loop(1);
loop.sleep();loop.sleep();loop.sleep();//loop.sleep();loop.sleep();
ros::spinOnce();
while (ros::ok()){
ros::spinOnce();loop.sleep();
printf("robot initial pose: (%.2f, %.2f, %.2f)\n", obj.turtlebot_odom_pose.pose.pose.position.x, obj.turtlebot_odom_pose.pose.pose.position.y, obj.radian2degree(tf::getYaw(obj.turtlebot_odom_pose.pose.pose.orientation)));
double velocity = 0.3;
obj.moveShape(1.0, 3, 120, velocity);
//exercise: try to remove the ros::SpinOnce() and observe and comment the result
ros::spinOnce();loop.sleep();ros::spinOnce();
printf("robot final pose: (%.2f, %.2f, %.2f)\n", obj.turtlebot_odom_pose.pose.pose.position.x, obj.turtlebot_odom_pose.pose.pose.position.y, obj.radian2degree(tf::getYaw(obj.turtlebot_odom_pose.pose.pose.orientation)));
return 0;
}
return 0;
}
另一个文件是:
文件2:ControlTurtlebot.hpp
#pragma once
#ifndef INCLUDE_CONTROLTURTLEBOT_HPP_
#define INCLUDE_CONTROLTURTLEBOT_HPP_
#include "ros/ros.h"
#include "geometry_msgs/Twist.h"
#include "sensor_msgs/LaserScan.h"
#include "nav_msgs/Odometry.h"
#include "tf/tf.h"
#include <tf/transform_listener.h>
#include <fstream>
class ControlTurtlebot {
public:
#define ANGULAR_VELOCITY_MINIMUM_THRESHOLD 0.4
#define pi 22/7
//declare publishers
ros::Publisher pub;
//declare subscribers
ros::Subscriber pose_subscriber;
//global variable to update the position of the robot
nav_msgs::Odometry turtlebot_odom_pose;
ros::NodeHandle n;
//callback function for the /odom topic to update the pose
void poseCallback(const nav_msgs::Odometry::ConstPtr& pose_message);
//the function that makes the robot moves forward and backward
void move_linear(double speed, double distance, bool isForward);
//the function that makes the robot rotates left and right
double rotate(double ang_vel, double angle_radian, bool isClockwise);
double degree2radian(double degreeAngle);
double radian2degree(double radianAngle);
void moveShape(double sideLength, double totalSides, double angle, double velocity);
};
#endif
` 最后一个文件是:
文件3:ControlTurtlebot.cpp
#include "ControlTurtlebot.hpp"
void ControlTurtlebot::poseCallback(const nav_msgs::Odometry::ConstPtr& pose_message){
turtlebot_odom_pose.pose.pose.position.x=pose_message->pose.pose.position.x;
turtlebot_odom_pose.pose.pose.position.y=pose_message->pose.pose.position.y;
turtlebot_odom_pose.pose.pose.position.z=pose_message->pose.pose.position.z;
turtlebot_odom_pose.pose.pose.orientation.w=pose_message->pose.pose.orientation.w;
turtlebot_odom_pose.pose.pose.orientation.x=pose_message->pose.pose.orientation.x;
turtlebot_odom_pose.pose.pose.orientation.y=pose_message->pose.pose.orientation.y;
turtlebot_odom_pose.pose.pose.orientation.z=pose_message->pose.pose.orientation.z;
}
void ControlTurtlebot::moveShape(double sideLength, double totalSides, double angle, double velocity){
for (int i=0;i<totalSides;i++){
move_linear(velocity, sideLength, true);
rotate (velocity, degree2radian(angle), true);
}
}
void ControlTurtlebot::move_linear(double speed, double distance, bool isForward){
//delcare a Twist message to send velocity commands
geometry_msgs::Twist VelocityMessage;
//initial pose of the turtlebot before start moving
nav_msgs::Odometry initial_turtlebot_odom_pose;
//set the linear velocity to a positive value if isFoward is true
if (isForward)
VelocityMessage.linear.x =abs(speed);
//all velocities of other axes must be zero.
VelocityMessage.linear.y = VelocityMessage.linear.z =VelocityMessage.angular.x =VelocityMessage.angular.y =VelocityMessage.angular.z =0;
double distance_moved = 0.0;
ros::Rate loop_rate(10); // we publish the velocity at 10 Hz (10 times a second)
//we update the initial_turtlebot_odom_pose using the turtlebot_odom_pose global variable updated in the callback function poseCallback
initial_turtlebot_odom_pose = turtlebot_odom_pose;
do{
pub.publish(VelocityMessage);
ros::spinOnce();
loop_rate.sleep();
distance_moved = sqrt(pow((turtlebot_odom_pose.pose.pose.position.x-initial_turtlebot_odom_pose.pose.pose.position.x), 2) +
pow((turtlebot_odom_pose.pose.pose.position.y-initial_turtlebot_odom_pose.pose.pose.position.y), 2));
}while((distance_moved<distance)&&(ros::ok()));
//finally, stop the robot when the distance is moved
VelocityMessage.linear.x =0;
pub.publish(VelocityMessage);
}
double ControlTurtlebot::rotate(double angular_velocity, double radians, bool clockwise)
{
//delcare a Twist message to send velocity commands
geometry_msgs::Twist VelocityMessage;
//declare tf transform listener: this transform listener will be used to listen and capture the transformation between
// the odom frame (that represent the reference frame) and the base_footprint frame the represent moving frame
tf::TransformListener TFListener;
//declare tf transform
//init_transform: is the transformation before starting the motion
tf::StampedTransform init_transform;
//current_transformation: is the transformation while the robot is moving
tf::StampedTransform current_transform;
//initial coordinates (for method 3)
nav_msgs::Odometry initial_turtlebot_odom_pose;
double angle_turned =0.0;
//validate angular velocity; ANGULAR_VELOCITY_MINIMUM_THRESHOLD is the minimum allowed
angular_velocity=((angular_velocity>ANGULAR_VELOCITY_MINIMUM_THRESHOLD)?angular_velocity:ANGULAR_VELOCITY_MINIMUM_THRESHOLD);
while(radians < 0) radians += 2*pi;
while(radians > 2*pi) radians -= 2*pi;
//wait for the listener to get the first message
TFListener.waitForTransform("base_footprint", "odom", ros::Time(0), ros::Duration(1.0));
//record the starting transform from the odometry to the base frame
TFListener.lookupTransform("base_footprint", "odom", ros::Time(0), init_transform);
//the command will be to turn at 0.75 rad/s
VelocityMessage.linear.x = VelocityMessage.linear.y = 0.0;
VelocityMessage.angular.z = angular_velocity;
if (clockwise) VelocityMessage.angular.z = -VelocityMessage.angular.z;
//the axis we want to be rotating by
tf::Vector3 desired_turn_axis(0,0,1);
if (!clockwise) desired_turn_axis = -desired_turn_axis;
ros::Rate rate(10.0);
bool done = false;
while (!done )
{
//send the drive command
pub.publish(VelocityMessage);
rate.sleep();
//get the current transform
try
{
TFListener.waitForTransform("base_footprint", "odom", ros::Time(0), ros::Duration(1.0));
TFListener.lookupTransform("base_footprint", "odom", ros::Time(0), current_transform);
}
catch (tf::TransformException ex)
{
ROS_ERROR("%s",ex.what());
break;
}
tf::Transform relative_transform = init_transform.inverse() * current_transform;
tf::Vector3 actual_turn_axis = relative_transform.getRotation().getAxis();
angle_turned = relative_transform.getRotation().getAngle();
if (fabs(angle_turned) < 1.0e-2) continue;
if (actual_turn_axis.dot(desired_turn_axis ) < 0 )
angle_turned = 2 * pi - angle_turned;
if (!clockwise)
VelocityMessage.angular.z = (angular_velocity-ANGULAR_VELOCITY_MINIMUM_THRESHOLD) * (fabs(radian2degree(radians-angle_turned)/radian2degree(radians)))+ANGULAR_VELOCITY_MINIMUM_THRESHOLD;
else
if (clockwise)
VelocityMessage.angular.z = (-angular_velocity+ANGULAR_VELOCITY_MINIMUM_THRESHOLD) * (fabs(radian2degree(radians-angle_turned)/radian2degree(radians)))-ANGULAR_VELOCITY_MINIMUM_THRESHOLD;
if (angle_turned > radians) {
done = true;
VelocityMessage.linear.x = VelocityMessage.linear.y = VelocityMessage.angular.z = 0;
pub.publish(VelocityMessage);
}
}
if (done) return angle_turned;
return angle_turned;
}
/* makes conversion from radian to degree */
double ControlTurtlebot::radian2degree(double radianAngle){
return (radianAngle*57.2957795);
}
/* makes conversion from degree to radian */
double ControlTurtlebot::degree2radian(double degreeAngle){
return (degreeAngle/57.2957795);
}
我在main.cpp文件中使用上述订阅者回调的错误是:
CMakeFiles / free_space_navigation_node.dir / src / main.cpp.o:在功能中
main': main.cpp:(.text+0x400): undefined reference to
ControlTurtlebot :: poseCallback(升压:: shared_ptr的常量&GT;常量&安培;)&#39; main.cpp :(。text + 0x5f0):未定义引用
ControlTurtlebot::radian2degree(double)' main.cpp:(.text+0x674): undefined reference to
ControlTurtlebot :: moveShape(double,double, 双,双)&#39; main.cpp :(。text + 0x6b1):未定义的引用 `ControlTurtlebot :: radian2degree(双)&#39; collect2:错误:ld返回 1退出状态 toy_robot / CMakeFiles / free_space_navigation_node.dir / build.make:118: 目标食谱 &#39; /家/ VIKI / catkin_ws / devel的/ lib目录/ toy_robot / free_space_navigation_node&#39; 失败了[2]: * [/家庭/ VIKI / catkin_ws / devel的/ lib目录/ toy_robot / free_space_navigation_node] 错误1 CMakeFiles / Makefile2:2938:目标的配方 &#39; toy_robot / CMakeFiles / free_space_navigation_node.dir /所有&#39;失败 make [1]:* [toy_robot / CMakeFiles / free_space_navigation_node.dir / all] 错误2 Makefile:138:目标配方&#39;全部&#39;失败了:*** [全部] 错误2
如果我改变了main.cpp中的订阅回调行:
obj.pose_subscriber = n.subscribe("/odom", 10, &ControlTurtlebot::poseCallback, &obj);
到
obj.pose_subscriber = n.subscribe("/odom", 10, ControlTurtlebot::poseCallback);
所以我收到如下错误:
错误:无效使用非静态成员函数'void ControlTurtlebot :: poseCallback(const ConstPtr&amp;)' obj.pose_subscriber = n.subscribe(&#34; / odom&#34;,10,ControlTurtlebot :: poseCallbac ^ toy_robot / CMakeFiles / free_space_navigation_node.dir / build.make:62: 目标食谱 &#39; toy_robot / CMakeFiles / free_space_navigation_node.dir / SRC / main.cpp.o&#39; 失败了[2]: * [toy_robot / CMakeFiles / free_space_navigation_node.dir / SRC / main.cpp.o] 错误1 CMakeFiles / Makefile2:2938:目标的配方 &#39; toy_robot / CMakeFiles / free_space_navigation_node.dir /所有&#39;失败 make [1]:* [toy_robot / CMakeFiles / free_space_navigation_node.dir / all] 错误2 Makefile:138:目标配方&#39;全部&#39;失败了:*** [全部] 错误2
我不明白这是什么问题。我也尝试将callfunction定义从void更改为static void callback(),但它再次恢复为第一个错误,类似于我使用上述订阅者方法时。
任何帮助都会非常感激!
谢谢!