Hi, @staff
I’m caught in an error when I try to deliver arguments to my callback function.
I find a method in ROS Answer.But I also encountered a bug when applying this method to my problem.
There is the key line:
map_sub_ = n.subscribe<nav_msgs::OccupancyGrid>("/map", 100, boost::bind(&MapGenerator::mapCallback, this, _1, _2));
void mapCallback(const nav_msgs::OccupancyGridConstPtr& map, const nav_msgs::OdometryConstPtr& odom){}
And there is my all source code, as you see, I just modified a map_saver.cpp
file in map_server package:
#include <cstdio>
#include "ros/ros.h"
#include "ros/console.h"
#include "nav_msgs/GetMap.h"
#include "tf2/LinearMath/Matrix3x3.h"
#include "geometry_msgs/Quaternion.h"
#include "tf2_ros/transform_listener.h"
#include "tf2/LinearMath/Quaternion.h"
#include "nav_msgs/Odometry.h"
#include "nav_msgs/OccupancyGrid.h"
// #include "message_filters/subscriber.h"
// #include "message_filters/synchronizer.h"
// #include "message_filters/sync_policies/approximate_time.h"
using namespace std;
/**
* @brief Map generation node.
*/
class MapGenerator
{
public:
std::string mapname_;
ros::Subscriber map_sub_;
ros::Subscriber imu_sub_;
bool saved_map_;
int threshold_occupied_;
int threshold_free_;
MapGenerator(const std::string& mapname, int threshold_occupied, int threshold_free)
: mapname_(mapname), saved_map_(false), threshold_occupied_(threshold_occupied), threshold_free_(threshold_free)
{
ros::NodeHandle n;
ROS_INFO("Waiting for the map");
imu_sub_ = n.subscribe<nav_msgs::Odometry>("/odom", 100, this);
map_sub_ = n.subscribe<nav_msgs::OccupancyGrid>("/map", 100, boost::bind(&MapGenerator::mapCallback, this, _1, _2));
// message_filters::Subscriber<nav_msgs::OccupancyGrid> map_sub(n, "map", 1);
// message_filters::Subscriber<nav_msgs::Odometry> imu_sub(n, "odom", 1);
// typedef message_filters::sync_policies::ApproximateTime<nav_msgs::OccupancyGrid, nav_msgs::Odometry> MySyncPolicy;
// message_filters::Synchronizer<MySyncPolicy> sync(MySyncPolicy(10), imu_sub, map_sub);
// sync.registerCallback(boost::bind(&MapGenerator::mapCallback, this, _1, _2));
// ros::spin();
}
void mapCallback(const nav_msgs::OccupancyGridConstPtr& map, const nav_msgs::OdometryConstPtr& odom)
{
ROS_INFO("Received a %d X %d map @ %.3f m/pix",
map->info.width,
map->info.height,
map->info.resolution);
std::string mapdatafile = mapname_ + ".pgm";
ROS_INFO("Writing map occupancy data to %s", mapdatafile.c_str());
FILE* out = fopen(mapdatafile.c_str(), "w");
if (!out)
{
ROS_ERROR("Couldn't save map file to %s", mapdatafile.c_str());
return;
}
fprintf(out, "P5\n# CREATOR: map_saver.cpp %.3f m/pix\n%d %d\n255\n",
map->info.resolution, map->info.width, map->info.height);
for(unsigned int y = 0; y < map->info.height; y++) {
for(unsigned int x = 0; x < map->info.width; x++) {
unsigned int i = x + (map->info.height - y - 1) * map->info.width;
if (map->data[i] >= 0 && map->data[i] <= threshold_free_) { // [0,free)
fputc(254, out);
} else if (map->data[i] >= threshold_occupied_) { // (occ,255]
fputc(000, out);
} else { //occ [0.25,0.65]
fputc(205, out);
}
}
}
fclose(out);
std::string mapmetadatafile = mapname_ + ".yaml";
ROS_INFO("Writing map occupancy data to %s", mapmetadatafile.c_str());
FILE* yaml = fopen(mapmetadatafile.c_str(), "w");
//get origin pose
geometry_msgs::Quaternion orientation = map->info.origin.orientation;
tf2::Matrix3x3 mat(tf2::Quaternion(
orientation.x,
orientation.y,
orientation.z,
orientation.w
));
double yaw, pitch, roll;
mat.getEulerYPR(yaw, pitch, roll);
//get end pose
tf2_ros::Buffer tfBuffer;
tf2_ros::TransformListener tfListener(tfBuffer);
geometry_msgs::Quaternion rot;
ros::Time now = ros::Time::now();
try{
// tfBuffer.canTransform("/map", "/odom", now, ros::Duration(1.0));
rot = tfBuffer.lookupTransform("/map", "/odom", now).transform.rotation;
// ROS_INFO(rot);
}catch(tf2::TransformException &ex){
ROS_ERROR("lookupTransform Error: %s", ex.what());
}
// the incoming geometry_msgs::Quaternion is transformed to a tf2::Quaterion
tf2::Matrix3x3 mat_end(tf2::Quaternion(
rot.x,
rot.y,
rot.z,
rot.w
));
// the tf::Quaternion has a method to acess roll pitch and yaw
double roll_end, pitch_end, yaw_end;
mat_end.getEulerYPR(yaw_end, pitch_end, roll_end);
fprintf(yaml, "image: %s\nresolution: %f\norigin: [%f, %f, %f]\nend: [%f, %f, %f]\nnegate: 0\noccupied_thresh: 0.65\nfree_thresh: 0.196\n\n",
mapdatafile.c_str(), map->info.resolution, map->info.origin.position.x, map->info.origin.position.y, yaw, odom->pose.pose.position.x, odom->pose.pose.position.y, yaw_end);
// fprintf(yaml, "image: %s\nresolution: %f\norigin: [%f, %f, %f]\nnegate: 0\noccupied_thresh: 0.65\nfree_thresh: 0.196\n\n",
// mapdatafile.c_str(), map->info.resolution, map->info.origin.position.x, map->info.origin.position.y, yaw);
fclose(yaml);
ROS_INFO("Done\n");
saved_map_ = true;
}
};
#define USAGE "Usage: \n" \
" map_saver -h\n"\
" map_saver [--occ <threshold_occupied>] [--free <threshold_free>] [-f <mapname>] [ROS remapping args]"
int main(int argc, char** argv)
{
ros::init(argc, argv, "map_saver");
std::string mapname = "map";
int threshold_occupied = 65;
int threshold_free = 25;
for(int i=1; i<argc; i++)
{
if(!strcmp(argv[i], "-h"))
{
puts(USAGE);
return 0;
}
else if(!strcmp(argv[i], "-f"))
{
if(++i < argc)
mapname = argv[i];
else
{
puts(USAGE);
return 1;
}
}
else if (!strcmp(argv[i], "--occ"))
{
if (++i < argc)
{
threshold_occupied = std::atoi(argv[i]);
if (threshold_occupied < 1 || threshold_occupied > 100)
{
ROS_ERROR("threshold_occupied must be between 1 and 100");
return 1;
}
}
else
{
puts(USAGE);
return 1;
}
}
else if (!strcmp(argv[i], "--free"))
{
if (++i < argc)
{
threshold_free = std::atoi(argv[i]);
if (threshold_free < 0 || threshold_free > 100)
{
ROS_ERROR("threshold_free must be between 0 and 100");
return 1;
}
}
else
{
puts(USAGE);
return 1;
}
}
else
{
puts(USAGE);
return 1;
}
}
if (threshold_occupied <= threshold_free)
{
ROS_ERROR("threshold_free must be smaller than threshold_occupied");
return 1;
}
MapGenerator mg(mapname, threshold_occupied, threshold_free);
while(!mg.saved_map_ && ros::ok())
ros::spinOnce();
return 0;
}
Finally, there is the error info:
I guess this error is caused by my mistake of using boost::bind() when delivering arguments. If you have a better method, please let me know.
Thank you so much!