Отсутствуют сообщения обратного вызова абонента ROS
Резюме: у меня есть узел, публикующий сообщения с частотой ~300 Гц, но обратный вызов, подписывающийся на тему в другом узле, вызывается только с частотой ~25 Гц. SpinOnce в узле подписчика вызывается с частотой ~700 Гц, поэтому я не знаю, почему он пропускает сообщения.
Узел издателя:
#include <ros/ros.h>
#include <ros/console.h>
#include <nav_msgs/Odometry.h>
...
int main(int argc, char** argv)
{
ros::init(argc, argv, "sim_node");
ros::NodeHandle nh;
...
// Publishers
tf::TransformBroadcaster tfbr;
ros::Publisher odomPub = nh.advertise<nav_msgs::Odometry>("pose",10);
...
ros::Rate r(300); // loop rate
while(ros::ok())
{
...
// Publish pose and velocity
...
odomPub.publish(msg);
ros::spinOnce();
r.sleep();
}
ros::waitForShutdown();
return 0;
}
Абонентский узел:
#include <ros/ros.h>
#include <ros/console.h>
#include <nav_msgs/Odometry.h>
...
std::mutex mtx1, mtx2;
class DataHandler
{
private:
ros::NodeHandle nh;
ros::Publisher odomPub;
double lastTime;
int lastSeq;
public:
Eigen::Vector3d x, xDot, w;
Eigen::Vector3d xDes, xDesDot, xDesDotDot, b1Des, b1DesDot;
Eigen::Matrix3d R;
DataHandler()
{
// Initialize data
xDes = Eigen::Vector3d(1,0,1);
xDesDot = Eigen::Vector3d::Zero();
xDesDotDot = Eigen::Vector3d::Zero();
b1Des = Eigen::Vector3d(1,0,0);
b1DesDot = Eigen::Vector3d::Zero();
x = Eigen::Vector3d::Zero();
xDot = Eigen::Vector3d::Zero();
R = Eigen::Matrix3d::Identity();
odomPub = nh.advertise<nav_msgs::Odometry>("controller_pose",10);
trajPub = nh.advertise<asap_control::DesiredTrajectory>("controller_desTraj",10);
lastTime = ros::Time::now().toSec();
lastSeq = 0;
}
// Get current pose and velocity
void odomCB(const nav_msgs::OdometryConstPtr& odomMsg)
{
mtx1.lock();
// Get data
double time1 = ros::Time::now().toSec();
x << odomMsg->pose.pose.position.x, odomMsg->pose.pose.position.y, ...;
xDot << odomMsg->twist.twist.linear.x, odomMsg->twist.twist.linear.y, ...;
R = Eigen::Quaterniond(odomMsg->pose.pose.orientation.w, odomMsg->pose.pose.orientation.x,...;
w << odomMsg->twist.twist.angular.x, odomMsg->twist.twist.angular.y, ...;
double time2 = ros::Time::now().toSec();
// Time to extract data, < 1ms
double delTproc = time2 - time1;
std::cout << "\n\n";
std::cout << "proc elapsed time: " << delTproc << "\n";
std::cout << "proc frequency: " << 1.0/delTproc << "\n";
odomPub.publish(odomMsg); // rostopic hz says this is publishing at ~25Hz
// Time between callback calls, ~25Hz
double timeNow = ros::Time::now().toSec();
double delT = timeNow - lastTime;
lastTime = timeNow;
std::cout << "elapsed time: " << delT << "\n";
std::cout << "frequency: " << 1.0/delT << "\n";
// Message sequence IDs, shows 12 msgs skipped every call
int seqNow = odomMsg->header.seq;
int delSeq = seqNow - lastSeq;
lastSeq = seqNow;
std::cout << "delta seq: " << delSeq << "\n";
mtx1.unlock();
}
};
...
int main(int argc, char** argv)
{
ros::init(argc, argv, "asap_control");
ros::NodeHandle nh;
...
// Publishers
ros::Publisher outputPub = nh.advertise<geometry_msgs::WrenchStamped>("wrench_command",10);
ros::Publisher debugPub = nh.advertise<asap_control::ControllerSignals>("controller_debug",10);
tf::TransformBroadcaster tfbr;
// Subscribers
DataHandler callbacks;
ros::Subscriber poseSub = nh.subscribe("pose",10,&DataHandler::odomCB,&callbacks);
// Asynchronous threads for callback handling
//ros::AsyncSpinner spinner(2);
//spinner.start();
double lastTime = ros::Time::now().toSec();
// Main loop
ros::Rate r(700); // loop rate
while(ros::ok())
{
// Data (extracted for cleanliness further down, and thread safety)
mtx1.lock();
Eigen::Vector3d x = callbacks.x;
Eigen::Vector3d xDot = callbacks.xDot;
Eigen::Matrix3d R = callbacks.R;
Eigen::Vector3d w = callbacks.w;
mtx1.unlock();
...
// Publish
...
outputPub.publish(msg);
// Publish debug signals
asap_control::ControllerSignals debugMsg;
debugMsg.x[0] = x(0);
...
debugPub.publish(debugMsg);
//double timeNow = ros::Time::now().toSec();
//double delT = timeNow - lastTime;
//lastTime = timeNow;
//std::cout << "\n\n";
//std::cout << "elapsed time: " << delT << "\n";
//std::cout << "frequency: " << 1.0/delT << "\n";
ros::spinOnce();
r.sleep();
}
ros::waitForShutdown();
return 0;
}
Дополнительная информация:
- Издатель публикует на частоте ~300 Гц (подтверждено
rostopic hz
из темы "поза") - Основной цикл в узле абонента работает на частоте ~700 Гц (подтверждено
rostopic hz
темы "wrench_command", публикуемой в цикле, а также времени цикла черезros::Time::now()
), и поэтому,spinOnce
вызывается с той же скоростью. - Обратный вызов для темы позы вызывается с частотой ~25 Гц (подтверждено
rostopic hz
темы "controller_pose", публикуемой в обратном вызове, а также циклической синхронизации черезros::Time::now()
) - Я получаю такое же поведение, даже если я использую
AsyncSpinner
вместоspinOnce
хотя могу подтвердить только используяrostopic hz
, Сроки производит ошибочный вывод, как и ожидалось - Увеличение абонентской очереди queue_length, например, до 10, увеличивает частоту обратного вызова до ~250 Гц, однако я хочу оставить для queue_length значение 1, чтобы получать только самые последние данные.
- Системный монитор в Ubuntu показывает менее чем 50% загрузки процессора, поэтому я не думаю, что это проблема узких мест процессора.
1 ответ
Я решил аналогичную проблему, передавая данные одометрии некоторое время назад, когда данные одометрии передавались на частоте 100 Гц, но принимались только на частоте 25 Гц. Оказалось, что базовый сокет TCP буферизует данные, объединяя 4 сообщения в один пакет TCP, чтобы сэкономить на транспортных расходах. Я считаю, что вам нужно установить значение tcpNoDelay в true в TransportHints ():
node.subscribe (...., ROS::TransportHints() tcpNoDelay(истина));
Обратите внимание, что это происходит на стороне подписки.
http://wiki.ros.org/roscpp/Overview/Publishers%20and%20Subscribers