Been beating my head against the wall for a while now, and am almost embarrassed to ask the community since it will most likely result in me getting schooled for a pointer or scoping .
I am using ROS to manipulate a robot that has two arms; each arm has a gripper. I have an arm class and a gripper class; the gripper is a member of the arm class. Relevant code posted below.
To sum up my code: the gripper class has members such as id
which need to be initialized by the callback
function. If these members are accessed before the callback is called, they will get bad data. Therefore, the class has an initialized_
variable and associated initialized()
function, which simply checks to see if the callback has been called yet (initialized is set to false when constructed, then set to true in the callback). The design pattern for the arm class is similar; its initialize()
function checks to see if the gripper is initialized. In the main function, in my ros loop, I check to make sure the arms are both initialized; if not, ros spins (aka calls the callbacks) until the callbacks initialize the grippers, allowing the program to continue.
To sum up my problem: the gripper's callback function is definitely being called, since "gripper initialized" is being printed. However, the properties it sets are not being retained, since "success!" is not being printed. Furthermore, an id of -1 is printed, a value set by the constructor rather than by the callback (an id of -1 is impossible).
Smells like a scoping or pointer issue, but I can't seem to find the problem. Since callback functions modify the "this" object, it is modifying the gripper itself, and that modification should remain after the function exits.
If anyone can offer help, it would be very greatly appreciated. Thanks in advance.
class Gripper
{
private:
int id;
bool initialized_;
ros::Subscriber subscriber;
void callback(const baxter_core_msgs::EndEffectorState::ConstPtr& msg);
void init();
public:
Gripper();
Gripper(ros::NodeHandle handle);
bool initialized() { return this->initialized_; }
int get_id() { return this->id; }
};
// DEFAULT CONSTRUCTOR
Gripper::Gripper()
{
this->init();
...
}
// CONSTRUCTOR
Gripper::Gripper(ros::NodeHandle handle)
{
this->init();
this->subscriber = handle.subscribe(sub_topic, 10, &Gripper::callback, this);
...
}
// CALLBACK FUNCTION
// initializes gripper fields
void Gripper::callback(const baxter_core_msgs::EndEffectorState::ConstPtr& msg)
{
this->initialized_ = true;
this->id = msg->id;
...
if (this->initialized_) ROS_INFO("gripper initialized");
}
// INIT FUNCTION
// common code in constructors
// sets all bools to false, ints to -1
void Gripper::init()
{
this->initialized_ = false;
this->id = -1;
...
}
class Arm
{
public:
Gripper gripper;
Arm();
Arm(ros::NodeHandle handle);
bool initialized()
{
if (this->gripper.initialized()) ROS_INFO("success!");
ROS_INFO("gripper id: %d");
return this->gripper.initialized();
};
};
// DEFAULT CONSTRUCTOR
Arm::Arm()
{
this->gripper = gripper();
...
}
// CONSTRUCTOR
Arm::Arm(ros::NodeHandle handle)
{
this->gripper = gripper(handle);
...
}
int main(int argc, char **argv)
{
// initialize the node and create a node handle
ros::init(argc, argv, "master_node");
ros::NodeHandle nh;
ros::Rate loop_rate(10);
// make some variables for later
Arm left_arm(nh, LEFT);
Arm right_arm(nh, RIGHT);
// main program content
while (ros::ok())
{
// if everything is initialized, start doing the stuff
if (left_arm.initialized() && right_arm.initialized())
{
...
}
// spin & sleep
ROS_INFO("spin");
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}