【发布时间】:2016-07-13 18:34:57
【问题描述】:
我正在通过 Gazebo 教程将 Gazebo 传感器连接到 ROS 并传递消息。 http://gazebosim.org/tutorials?cat=guided_i&tut=guided_i6
该程序构建一个 Gazebo ModelPlugin 对象,并从该对象中初始化 ROS。然后,它创建一个 ROS 节点、订阅者、队列和一个标准线程来运行 ROS 队列。该程序使用 Gazebo 的传输对象工作,但是当我尝试添加 ROS 传输对象(如前所述)时,该程序不起作用。我的问题源于 roscore 节点(包括 rosmaster)没有初始化。
我的传感器插件代码如下。 ROS 集成从第 70 行开始:
#ifndef _VELODYNE_PLUGIN_HH_
#define _VELODYNE_PLUGIN_HH_
#include <gazebo/gazebo.hh>
#include <gazebo/msgs/msgs.hh>
#include <gazebo/physics/physics.hh>
#include <gazebo/transport/transport.hh>
#include <ros/ros.h>
#include <ros/callback_queue.h>
#include <ros/subscribe_options.h>
#include <thread>
#include <std_msgs/Float32.h>
namespace gazebo
{
/// \brief A plugin to control a Velodyne sensor.
class VelodynePlugin : public ModelPlugin
{
/// \brief Constructor
public: VelodynePlugin() {}
/// \brief The load function is called by Gazebo when the plugin is
/// inserted into simulation
/// \param[in] _model A pointer to the model that this plugin is
/// attached to.
/// \param[in] _sdf A pointer to the plugin's SDF element.
public: virtual void Load(physics::ModelPtr _model, sdf::ElementPtr _sdf) {
gzwarn << "HERE";
if (_model->GetJointCount() == 0) {
std::cerr <<
"Invalid joint count, Velodyne plugin not loaded\n";
}
// Store the model pointer for convenience.
this->model = _model;
// Get the first joint. We are making an assumption about the
// model having one joint that is the rotational joint.
this->joint = _model->GetJoints()[0];
// Setup a P-controller with a gain of 0.1.
this->pid=common::PID(0.1,0,0);
// Apply the P-controller to the joint.
this->model->GetJointController()->SetVelocityPID(
this->joint->GetScopedName(), this->pid);
// Default to zero velocity
double velocity=0;
// Check that the velocity element exists, then read the value
if (_sdf->HasElement("velocity"))
velocity=_sdf->Get<double>("velocity");
this->SetVelocity(velocity);
// Create the node
this->node = transport::NodePtr(new transport::Node());
this->node->Init(this->model->GetWorld()->GetName());
// Create a topic name
std::string topicName = "~/" + this->model->GetName() +
"/vel_cmd";
// Subscribe to the topic, and register a callback.
this->sub = this->node->Subscribe(topicName,
&VelodynePlugin::OnMsg, this);
// Initialize ros, if it has not already been initialized.
if (!ros::isInitialized()) {
std::cout << "initializing ros" << std::endl;
int argc = 0;
char **argv=NULL;
ros::init(argc,argv,"gazebo_client",
ros::init_options::NoSigintHandler);
} else { std::cout << "NOT initializing ros" << std::endl; }
// Create our ROS node. This acts in a similar manner to the
// Gazebo node.
this->rosNode.reset(new ros::NodeHandle("gazebo_client"));
// Create a named topic, and subscribe to it.
ros::SubscribeOptions so =
ros::SubscribeOptions::create<std_msgs::Float32>(
"/"+this->model->GetName()+"/vel_cmd",
1,
boost::bind(&VelodynePlugin::OnRosMsg, this, _1),
ros::VoidPtr(), &this->rosQueue);
this->rosSub = this->rosNode->subscribe(so);
// Spin up the queue helper thread
this->rosQueueThread =
std::thread(std::bind(&VelodynePlugin::QueueThread,this));
}
/// \brief Set the velocity of the Velodyne
/// \param[in] _vel New target velocity
public: void SetVelocity(const double &_vel) {
// Set the joint's target velocity.
this->model->GetJointController()->SetVelocityTarget(
this->joint->GetScopedName(), _vel);
}
/// \brief Handle incoming message
/// \param[in] _msg Repurpose a vector3 message. This function will
/// only use the x component.
private: void OnMsg(ConstVector3dPtr &_msg) {
this->SetVelocity(_msg->x());
}
/// \brief Handle an incoming message from ROS
/// \param[in] _msg A float value that is used to set the velocity
/// of the Velodyne.
public: void OnRosMsg(const std_msgs::Float32ConstPtr &_msg) {
this->SetVelocity(_msg->data);
}
/// \brief ROS helper function that processes messages
private: void QueueThread() {
static const double timeout = .01;
while (this->rosNode->ok()) {
this->rosQueue.callAvailable(ros::WallDuration(timeout));
}
}
/// \brief Pointer to the model;
private: physics::ModelPtr model;
/// \brief Control surfaces joints.
private: physics::JointPtr joint;
/// \brief Velocity PID for the propeller.
private: common::PID pid;
/// \brief A node used for transport
private: transport::NodePtr node;
/// \brief A subscriber to a named topic.
private: transport::SubscriberPtr sub;
/// \brief A node used for ROS transport
private: std::unique_ptr<ros::NodeHandle> rosNode;
/// \brief A ROS subscriber
private: ros::Subscriber rosSub;
/// \brief A ROS callbackqueue that helps process messages
private: ros::CallbackQueue rosQueue;
/// \brief A thread that keeps running the rosQueue
private: std::thread rosQueueThread;
};
// Tell Gazebo about this plugin, so that Gazebo can call Load on this plugin.
GZ_REGISTER_MODEL_PLUGIN(VelodynePlugin)
}
#endif
请告诉我如何才能更具体地回答这个问题。第一个问题肯定是ROS没有初始化。我可以告诉这一点,因为在不同的终端调用rostopic list 输出:
ERROR: Unable to communicate with master
【问题讨论】:
-
“程序不工作”到底是什么意思?您是否收到任何错误消息或订阅者从未收到任何消息?在后一种情况下,您是否通过
rostopic echo /topic_name验证消息确实已发布? -
啊,还有一个问题:你究竟是如何启动凉亭的?它是从终端运行的吗?
-
我从 bash 终端使用 'gazebo ~/.gazebo/worlds/velodyne.world' 启动凉亭,这是我的世界包含我打算与 ros 通信的对象的位置。跨度>
-
“程序不工作”是指rosmaster/roscore 没有初始化/启动。当我尝试运行“rostopic list”时,我收到输出:“错误:无法与主服务器通信”
标签: c++ simulation ros