use pointer to odometry message
I've been stuck on a problem for quite a while now. I'm trying to use multiple files (main function file, file containing different movement control functions, file for controlling the camera, etc... and header files) in order to make control my turtlebot. When I only use publishers and don't bother subscribing to any nodes, everything seems to work fine, including moving the turtlebot solely with publish commands, however when I try and use a subscriber to change what the motion will be depending on speed everything seems to fail.
My CMake list is fine and everything compiles correctly, but when I run it I get the following error:
/usr/include/boost/smartptr/sharedptr.hpp:648: typename boost::detail::spmemberaccess
::type boost::sharedptr ::operator->() const [with T = const nav msgs::Odometry_std::allocator<void; typename boost::detail::spmemberaccess
::type = const navmsgs::Odometrystd::allocator<void *]: Assertion `px != 0' failed. Aborted (core dumped)
What I've figured out is that my odometry pointer (odom_ptr) seems to not be initializing, but I'm not sure why or how to fix it. Any help would be greatly appreciated.
For this I'm using the following piece of code:
MainFile.cpp
#include <iostream>
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <nav_msgs/Odometry.h>
#include <std_msgs/Empty.h>
#include "TurtleFunction.cpp"
#include "TurtleFunction.h"
#include <sstream>
#include <string>
#include <cmath>
#include <math.h>
using namespace std;
/* Define Global Variables
--------------------------*/
// ROS Publishers and Subscribers
ros::Publisher cmd_pub, reset_pub;
ros::Subscriber OdomSub;
// Pointers and Messages
geometry_msgs::Twist cmd_msg;
nav_msgs::Odometry::ConstPtr odom_ptr;
std_msgs::Empty reset_msg ;
int main(int argc, char** argv){
// Initialize ROS
ros::init(argc, argv, "test3");
ros::NodeHandle nh;
ros::spinOnce();
// Define Global Variables for use
cmd_pub = nh.advertise<geometry_msgs::Twist>("/cmd_vel_mux/input/teleop", 10);
reset_pub = nh.advertise<std_msgs::Empty>("/mobile_base/commands/reset_odometry", 1);
OdomSub = nh.subscribe<nav_msgs::Odometry>("/odom",50,processodom);
ros::spinOnce();
resetOdom(); // Reset the Odometry of the Turtlebot
ros::spinOnce();
// Define Initial Velocity Variables for TurtleBot
double v = 0.1;
double theta = 0.01;
int i = 0;
while(1){
// Movement(v,theta);
UnicycleModel();
cout << "this is working" << i << endl;
i++;
}
cout << "This worked" << endl;
return 0;
}
Then I have the following function file:
TurtleFunction.cpp
#include <iostream>
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <nav_msgs/Odometry.h>
#include <std_msgs/Empty.h>
#include "TurtleFunction.h"
#include <sstream>
#include <string>
#include <cmath>
#include <math.h>
using namespace std;
void Movement(double v,double theta){
// geometry_msgs::Twist cmd_msg;
cmd_msg.linear.x = v;
cout << "v = " << cmd_msg.linear.x << endl;
cmd_msg.angular.z = theta;
cout << "theta = " << cmd_msg.angular.z << endl;
cmd_pub.publish(cmd_msg); //send
ros::spinOnce();
}
void UnicycleModel(){
float pi = 3.14159265359 ;
float pose_judah_x = odom_ptr->pose.pose.position.x ;
float pose_judah_y = odom_ptr->pose.pose.position.y ;
float orientationW = odom_ptr->pose.pose.orientation.w ;
float orientationX = odom_ptr->pose.pose.orientation.x ;
float orientationY = odom_ptr->pose.pose.orientation.y ;
float orientationZ = odom_ptr->pose.pose.orientation.z ;
float psi_rad = atan2(2*orientationW*orientationZ,1-2*orientationZ*orientationZ) ;
float psi_deg = psi_rad*180/pi ;
if (psi_deg<0){
psi_deg = psi_deg +360 ;
}
float p_x = 1 ;
float p_y = 0 ;
float dx = p_x - pose_judah_x ;
float dy = p_y - pose_judah_y ;
float err_pos = sqrt (dx * dx + dy * dy) ; //send
float heading_angle_des = atan2( dy , dx );
float heading_angle_error = heading_angle_des - psi_rad ; // e_theta = theta_des - theta
float heading_angle_error_mod = fmod(heading_angle_error,2*pi);
float heading_angle_error_mod_atan2 = atan2(sin(heading_angle_error_mod),cos(heading_angle_error_mod));
cout << "X_JUDAH===" << pose_judah_x << endl ;
cout << "Y_JUDAH===" << pose_judah_y << endl ;
cout << "PSI_DEGREES_JUDAH===" << psi_deg << endl ;
cout << " P_X " << p_x << endl;
cout << " P_Y *** " << p_y << endl;
double k_p = 0.5;
double k_theta = 0.05;
double v = k_p * err_pos;
double theta = k_theta * heading_angle_error_mod_atan2;
Movement(v,theta);
}
void processodom(const nav_msgs::Odometry::ConstPtr& odom){
odom_ptr = odom;
}
void resetOdom (){
reset_pub.publish(reset_msg);
}
Finally I have the header file to join it together and use the global variables
TurtleFunction.h
#ifndef TURTLEFUNCTION_H_
#define TURTLEFUNCTION_H_
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <nav_msgs/Odometry.h>
#include <std_msgs/Empty.h>
/* Global Variables
-------------------*/
// ROS NodeHandle
extern ros::NodeHandle nh;
// ROS Publishers and Subscribers
extern ros::Publisher cmd_pub, reset_pub;
extern ros::Subscriber OdomSub;
// Pointers and Messages
extern geometry_msgs::Twist cmd_msg;
extern nav_msgs::Odometry::ConstPtr odom_ptr;
extern std_msgs::Empty reset_msg ;
#endif /* TURTLEFUNCTION_H_ */
Asked by conect on 2018-07-01 07:45:34 UTC
Comments
It is likely that no messages have been processed for the
/odom
subscriber and the very first time you runUnicycleModel()
your code tries to dereference theodom_ptr
and crashes.Also: I would recommend you rewrite your
while
loop to checkros::ok()
and introduce aros::Rate
.Asked by gvdhoorn on 2018-07-01 10:56:52 UTC
And a question: is there any reason you don't want to run the code in
UnicycleModel()
inside theprocessodom(..)
callback? You have all the context there (ie: msg, time, etc), don't need any additional variables, and you avoid undersampling, aliasing and potentially losing events.Asked by gvdhoorn on 2018-07-01 10:58:46 UTC
Yeah, the reasoning not to run UnicyleModel in the proccessodom is because it is only one of 3 different movement functions I may use. Since I am trying to make my code as modular as possible, I have multiple different movement functions in that function file so that I can simply swap a line of code
Asked by conect on 2018-07-01 17:09:51 UTC
If I put the unicycle model code in the processodom I'd have to rewrite it each time which defeat the purpose.
How could I make sure that the subscriber gets a message first? I tried spinOnce already and nothing
And yeah, going to make the change on the while, it's just a placeholder. Thanks
Asked by conect on 2018-07-01 17:10:19 UTC
so I tried moving
UnicyleModel()
intoproccessodom()
just to see if that would help at all any see if I could work from there to debug. I also addedros::spin()
so that it would continue running. when I ranrqt_graph
it found just the node"test3"
and nothing else, no publishers or subscribersAsked by conect on 2018-07-02 04:53:38 UTC