00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <ros/ros.h>
00034 #include <sensor_msgs/JointState.h>
00035 #include <geometry_msgs/Transform.h>
00036 #include <nav_msgs/Odometry.h>
00037 #include <sensor_msgs/Imu.h>
00038 #include <iostream>
00039
00040 #include <std_srvs/Empty.h>
00041 #include <naoqi_msgs/SetTransform.h>
00042
00043 #include <tf/transform_broadcaster.h>
00044 #include <tf/transform_datatypes.h>
00045
00046
00047 #include <alproxies/almemoryproxy.h>
00048 #include <alproxies/almotionproxy.h>
00049 #include <alvision/alvisiondefinitions.h>
00050 #include <alerror/alerror.h>
00051 #include <alvalue/alvalue.h>
00052 #include <alcommon/altoolsmain.h>
00053 #include <alproxies/alvideodeviceproxy.h>
00054 #include <alcommon/albroker.h>
00055 #include <alcommon/albrokermanager.h>
00056 #include <alcommon/alproxy.h>
00057 #include <alproxies/alproxies.h>
00058 #include <alproxies/almotionproxy.h>
00059 #include <alproxies/almemoryproxy.h>
00060 #include <alcommon/almodule.h>
00061 #include <alcommon/albroker.h>
00062 #include <alcommon/albrokermanager.h>
00063
00064 #include <naoqi_driver/naoqi_node.h>
00065
00066
00067 #include <boost/program_options.hpp>
00068
00069 using namespace std;
00070
00071 class NaoqiJointStates : public NaoqiNode
00072 {
00073 public:
00074
00075 NaoqiJointStates(int argc, char ** argv);
00076 ~NaoqiJointStates();
00077
00078 bool connectProxy();
00079 void run();
00080
00081 bool pauseOdomCallback(std_srvs::Empty::Request& req, std_srvs::Empty::Response& res);
00082 bool resumeOdomCallback(std_srvs::Empty::Request& req, std_srvs::Empty::Response& res);
00083 bool odomOffsetCallback(naoqi_msgs::SetTransform::Request& req, naoqi_msgs::SetTransform::Response& res);
00084 bool setOdomPoseCallback(naoqi_msgs::SetTransform::Request& req, naoqi_msgs::SetTransform::Response& res);
00085
00086
00087 protected:
00088
00089 double m_rate;
00090
00091
00092 boost::shared_ptr<AL::ALMotionProxy> m_motionProxy;
00093 boost::shared_ptr<AL::ALMemoryProxy> m_memoryProxy;
00094 AL::ALValue m_dataNamesList;
00095
00096
00097 ros::NodeHandle m_nh;
00098 ros::NodeHandle m_privateNh;
00099
00100
00101 ros::ServiceServer m_pauseOdomSrv;
00102 ros::ServiceServer m_resumeOdomSrv;
00103 ros::ServiceServer m_odomOffsetSrv;
00104 ros::ServiceServer m_setOdomPoseSrv;
00105
00106 std::string m_odomFrameId;
00107 std::string m_baseFrameId;
00108
00109 nav_msgs::Odometry m_odom;
00110 sensor_msgs::Imu m_torsoIMU;
00111 sensor_msgs::JointState m_jointState;
00112
00113 ros::Publisher m_odomPub;
00114 tf::TransformBroadcaster m_transformBroadcaster;
00115 ros::Publisher m_torsoIMUPub;
00116 ros::Publisher m_jointStatePub;
00117
00118
00119 geometry_msgs::TransformStamped m_odomTransformMsg;
00120 tf::Pose m_odomPose;
00121 tf::Transform m_odomOffset;
00122
00123 bool m_useIMUAngles;
00124
00125 bool m_paused;
00126 double m_lastOdomTime;
00127
00128 tf::Pose m_targetPose;
00129 bool m_mustUpdateOffset;
00130 bool m_initializeFromIMU;
00131 bool m_initializeFromOdometry;
00132 bool m_isInitialized;
00133 };
00134
00135 bool NaoqiJointStates::connectProxy()
00136 {
00137 if (!m_broker)
00138 {
00139 ROS_ERROR("Broker is not ready. Have you called connectNaoQi()?");
00140 return false;
00141 }
00142 try
00143 {
00144
00145 m_motionProxy = boost::shared_ptr<AL::ALMotionProxy>(new AL::ALMotionProxy(m_broker));
00146 }
00147 catch (const AL::ALError& e)
00148 {
00149 ROS_ERROR("Could not create ALMotionProxy.");
00150 return false;
00151 }
00152 try
00153 {
00154
00155 m_memoryProxy = boost::shared_ptr<AL::ALMemoryProxy>(new AL::ALMemoryProxy(m_broker));
00156 }
00157 catch (const AL::ALError& e)
00158 {
00159 ROS_ERROR("Could not create ALMemoryProxy.");
00160 return false;
00161 }
00162 ROS_INFO("Proxies to ALMotion and ALMemory ready.");
00163 return true;
00164 }
00165
00166 NaoqiJointStates::NaoqiJointStates(int argc, char ** argv)
00167 : NaoqiNode(argc, argv),
00168 m_rate(25.0), m_privateNh("~"),
00169 m_odomFrameId("odom"),
00170 m_baseFrameId("base_link"),
00171 m_useIMUAngles(false),
00172 m_paused(false),
00173 m_lastOdomTime(0.0),
00174 m_mustUpdateOffset(false), m_initializeFromIMU(false),
00175 m_initializeFromOdometry(false), m_isInitialized(false)
00176 {
00177 parse_command_line(argc,argv);
00178 if ( ! connectNaoQi() || ! connectProxy() )
00179 {
00180 ROS_ERROR("Gosh! Throwsing exception");
00181 throw std::exception();
00182 }
00183 m_dataNamesList = AL::ALValue::array("DCM/Time",
00184 "Device/SubDeviceList/InertialSensor/AngleX/Sensor/Value","Device/SubDeviceList/InertialSensor/AngleY/Sensor/Value",
00185 "Device/SubDeviceList/InertialSensor/AngleZ/Sensor/Value",
00186 "Device/SubDeviceList/InertialSensor/GyroscopeX/Sensor/Value", "Device/SubDeviceList/InertialSensor/GyroscopeY/Sensor/Value",
00187 "Device/SubDeviceList/InertialSensor/GyroscopeZ/Sensor/Value",
00188 "Device/SubDeviceList/InertialSensor/AccelerometerX/Sensor/Value", "Device/SubDeviceList/InertialSensor/AccelerometerY/Sensor/Value",
00189 "Device/SubDeviceList/InertialSensor/AccelerometerZ/Sensor/Value");
00190
00191
00192
00193 m_privateNh.param("sensor_rate", m_rate,m_rate);
00194
00195
00196 m_privateNh.param("base_frame_id", m_baseFrameId, m_baseFrameId);
00197 m_privateNh.param("odom_frame_id", m_odomFrameId, m_odomFrameId);
00198 m_privateNh.param("use_imu_angles", m_useIMUAngles, m_useIMUAngles);
00199
00200 m_pauseOdomSrv = m_nh.advertiseService("pause_odometry", &NaoqiJointStates::pauseOdomCallback, this);
00201 m_resumeOdomSrv = m_nh.advertiseService("resume_odometry", &NaoqiJointStates::resumeOdomCallback, this);
00202 m_odomOffsetSrv = m_nh.advertiseService("odometry_offset", &NaoqiJointStates::odomOffsetCallback, this);
00203 m_setOdomPoseSrv = m_nh.advertiseService("set_odometry_pose", &NaoqiJointStates::setOdomPoseCallback, this);
00204
00205
00206 m_odom.header.frame_id = m_odomFrameId;
00207 m_torsoIMU.header.frame_id = m_baseFrameId;
00208 m_jointState.name = m_motionProxy->getJointNames("Body");
00209
00210
00211 if (m_jointState.name.size() == 22)
00212 {
00213
00214 m_jointState.name.insert(m_jointState.name.begin()+6,"LWristYaw");
00215 m_jointState.name.insert(m_jointState.name.begin()+7,"LHand");
00216 m_jointState.name.push_back("RWristYaw");
00217 m_jointState.name.push_back("RHand");
00218 }
00219
00220 std::stringstream ss;
00221 std::copy(m_jointState.name.begin(), m_jointState.name.end()-1, std::ostream_iterator<std::string>(ss,","));
00222 std::copy(m_jointState.name.end()-1, m_jointState.name.end(), std::ostream_iterator<std::string>(ss));
00223 ROS_INFO("Nao joints found: %s",ss.str().c_str());
00224
00225 if (m_useIMUAngles)
00226 ROS_INFO("Using IMU for odometry roll & pitch");
00227
00228
00229
00230 m_odomTransformMsg.header.frame_id = m_odomFrameId;
00231 m_odomTransformMsg.child_frame_id = m_baseFrameId;
00232
00233 m_odomOffset = tf::Transform(tf::createIdentityQuaternion());
00234 m_odomPose = tf::Transform(tf::createIdentityQuaternion());
00235
00236 m_odomPub = m_nh.advertise<nav_msgs::Odometry>("odom",5);
00237 m_torsoIMUPub = m_nh.advertise<sensor_msgs::Imu>("imu",5);
00238 m_jointStatePub = m_nh.advertise<sensor_msgs::JointState>("joint_states",5);
00239
00240 ROS_INFO("naoqi_joint_states initialized");
00241
00242 }
00243
00244 NaoqiJointStates::~NaoqiJointStates()
00245 {
00246 }
00247
00248 void NaoqiJointStates::run()
00249 {
00250 ros::Rate r(m_rate);
00251 ros::Time stamp1;
00252 ros::Time stamp2;
00253 ros::Time stamp;
00254
00255 std::vector<float> odomData;
00256 float odomX, odomY, odomZ, odomWX, odomWY, odomWZ;
00257
00258 std::vector<float> memData;
00259
00260 std::vector<float> positionData;
00261
00262 ROS_INFO("Staring main loop. ros::ok() is %d nh.ok() is %d",ros::ok(),m_nh.ok());
00263 while(ros::ok() )
00264 {
00265 r.sleep();
00266 ros::spinOnce();
00267 stamp1 = ros::Time::now();
00268 try
00269 {
00270 memData = m_memoryProxy->getListData(m_dataNamesList);
00271
00272 odomData = m_motionProxy->getPosition("Torso", 1, true);
00273 positionData = m_motionProxy->getAngles("Body", true);
00274 }
00275 catch (const AL::ALError & e)
00276 {
00277 ROS_ERROR( "Error accessing ALMemory, exiting...");
00278 ROS_ERROR( "%s", e.what() );
00279
00280 }
00281 stamp2 = ros::Time::now();
00282
00283
00284 stamp = stamp1 + ros::Duration((stamp2-stamp1).toSec()/2.0);
00285
00286
00287
00288
00289 if (memData.size() != m_dataNamesList.getSize())
00290 {
00291 ROS_ERROR("memData length %zu does not match expected length %u",memData.size(),m_dataNamesList.getSize() );
00292 continue;
00293 }
00294
00295 m_torsoIMU.header.stamp = stamp;
00296
00297 float angleX = memData[1];
00298 float angleY = memData[2];
00299 float angleZ = memData[3];
00300 float gyroX = memData[4];
00301 float gyroY = memData[5];
00302 float gyroZ = memData[6];
00303 float accX = memData[7];
00304 float accY = memData[8];
00305 float accZ = memData[9];
00306
00307 m_torsoIMU.orientation = tf::createQuaternionMsgFromRollPitchYaw(
00308 angleX,
00309 angleY,
00310 angleZ);
00311
00312 m_torsoIMU.angular_velocity.x = gyroX;
00313 m_torsoIMU.angular_velocity.y = gyroY;
00314 m_torsoIMU.angular_velocity.z = gyroZ;
00315
00316 m_torsoIMU.linear_acceleration.x = accX;
00317 m_torsoIMU.linear_acceleration.y = accY;
00318 m_torsoIMU.linear_acceleration.z = accZ;
00319
00320
00321
00322 m_torsoIMU.orientation_covariance[0] = -1;
00323 m_torsoIMU.angular_velocity_covariance[0] = -1;
00324 m_torsoIMU.linear_acceleration_covariance[0] = -1;
00325
00326 m_torsoIMUPub.publish(m_torsoIMU);
00327
00328
00329
00330
00331
00332 m_jointState.header.stamp = stamp;
00333 m_jointState.header.frame_id = m_baseFrameId;
00334 m_jointState.position.resize(positionData.size());
00335 for(unsigned i = 0; i<positionData.size(); ++i)
00336 {
00337 m_jointState.position[i] = positionData[i];
00338 }
00339
00340
00341 if (m_jointState.position.size() == 22)
00342 {
00343 m_jointState.position.insert(m_jointState.position.begin()+6,0.0);
00344 m_jointState.position.insert(m_jointState.position.begin()+7,0.0);
00345 m_jointState.position.push_back(0.0);
00346 m_jointState.position.push_back(0.0);
00347 }
00348
00349 m_jointStatePub.publish(m_jointState);
00350
00351
00352
00353
00354
00355 if (!m_paused) {
00356
00357
00358 tf::Pose transformedPose;
00359
00360
00361 if (odomData.size()!=6)
00362 {
00363 ROS_ERROR( "Error getting odom data. length is %zu",odomData.size() );
00364 continue;
00365 }
00366
00367 double dt = (stamp.toSec() - m_lastOdomTime);
00368
00369 odomX = odomData[0];
00370 odomY = odomData[1];
00371 odomZ = odomData[2];
00372 odomWX = odomData[3];
00373 odomWY = odomData[4];
00374 odomWZ = odomData[5];
00375
00376 tf::Quaternion q;
00377
00378 if (m_useIMUAngles)
00379 q.setRPY(angleX, angleY, odomWZ);
00380 else
00381 q.setRPY(odomWX, odomWY, odomWZ);
00382
00383 m_odomPose.setOrigin(tf::Vector3(odomX, odomY, odomZ));
00384 m_odomPose.setRotation(q);
00385
00386 if(m_mustUpdateOffset) {
00387 if(!m_isInitialized) {
00388 if(m_initializeFromIMU) {
00389
00390 m_targetPose.setOrigin(m_odomPose.getOrigin());
00391 m_targetPose.setRotation(tf::createQuaternionFromRPY(angleX, angleY, odomWZ));
00392 } else if(m_initializeFromOdometry) {
00393 m_targetPose.setOrigin(m_odomPose.getOrigin());
00394 m_targetPose.setRotation(tf::createQuaternionFromRPY(odomWX, odomWY, odomWZ));
00395 }
00396 m_isInitialized = true;
00397 } else {
00398
00399 const double target_yaw = tf::getYaw(m_targetPose.getRotation());
00400 if(m_initializeFromIMU) {
00401 m_targetPose.setRotation(tf::createQuaternionFromRPY(angleX, angleY, target_yaw));
00402 } else if(m_initializeFromOdometry){
00403 m_targetPose.setRotation(tf::createQuaternionFromRPY(odomWX, odomWY, target_yaw));
00404 }
00405 }
00406 m_odomOffset = m_targetPose * m_odomPose.inverse();
00407 transformedPose = m_targetPose;
00408 m_mustUpdateOffset = false;
00409 } else {
00410 transformedPose = m_odomOffset * m_odomPose;
00411 }
00412
00413
00414
00415
00416 m_odomTransformMsg.header.stamp = stamp;
00417 tf::transformTFToMsg(transformedPose, m_odomTransformMsg.transform);
00418 m_transformBroadcaster.sendTransform(m_odomTransformMsg);
00419
00420
00421
00422
00423
00424 m_odom.header.stamp = stamp;
00425
00426 m_odom.twist.twist.linear.x = (odomX - m_odom.pose.pose.position.x) / dt;
00427 m_odom.twist.twist.linear.y = (odomY - m_odom.pose.pose.position.y) / dt;
00428 m_odom.twist.twist.linear.z = (odomZ - m_odom.pose.pose.position.z) / dt;
00429
00430
00431
00432
00433
00434 m_odom.pose.pose.orientation = m_odomTransformMsg.transform.rotation;
00435 m_odom.pose.pose.position.x = m_odomTransformMsg.transform.translation.x;
00436 m_odom.pose.pose.position.y = m_odomTransformMsg.transform.translation.y;
00437 m_odom.pose.pose.position.z = m_odomTransformMsg.transform.translation.z;
00438
00439
00440 m_odomPub.publish(m_odom);
00441
00442
00443 m_lastOdomTime = stamp.toSec();
00444
00445 }
00446 }
00447 ROS_INFO("naoqi_sensors stopped.");
00448
00449 }
00450
00451 bool NaoqiJointStates::pauseOdomCallback(std_srvs::Empty::Request& req, std_srvs::Empty::Response& res){
00452 if (m_paused){
00453 ROS_WARN("Odometry pause requested, but is already paused");
00454 return false;
00455 } else{
00456 ROS_INFO("Odometry paused");
00457 m_paused = true;
00458 m_targetPose = m_odomOffset * m_odomPose;
00459 m_mustUpdateOffset = true;
00460 return true;
00461 }
00462 }
00463
00464 bool NaoqiJointStates::resumeOdomCallback(std_srvs::Empty::Request& req, std_srvs::Empty::Response& res){
00465 if (m_paused){
00466 ROS_INFO("Odometry resumed");
00467 m_paused = false;
00468 return true;
00469 } else{
00470 ROS_WARN("Odometry resume requested, but is not paused");
00471 return false;
00472 }
00473 }
00474
00475 bool NaoqiJointStates::odomOffsetCallback(naoqi_msgs::SetTransform::Request& req,
00476 naoqi_msgs::SetTransform::Response& res){
00477 ROS_INFO("New odometry offset received");
00478 tf::Transform newOffset;
00479 tf::transformMsgToTF(req.offset, newOffset);
00480
00481
00482 if(!m_mustUpdateOffset) {
00483 m_mustUpdateOffset = true;
00484 m_targetPose = m_odomOffset * m_odomPose * newOffset;
00485 } else {
00486 m_targetPose = m_targetPose * newOffset;
00487 }
00488
00489 return true;
00490 }
00491
00492 bool NaoqiJointStates::setOdomPoseCallback(naoqi_msgs::SetTransform::Request& req,
00493 naoqi_msgs::SetTransform::Response& res){
00494 ROS_INFO("New target for current odometry pose received");
00495 tf::Transform targetPose;
00496 tf::transformMsgToTF(req.offset, targetPose);
00497
00498 m_odomOffset = targetPose * m_odomPose.inverse();
00499
00500 return true;
00501 }
00502
00503 int main(int argc, char ** argv)
00504 {
00505 ros::init(argc, argv, "naoqi_joint_states");
00506 NaoqiJointStates * sensors;
00507 try{
00508 sensors = new NaoqiJointStates(argc,argv);
00509
00510 }
00511 catch (const std::exception & e)
00512
00513 {
00514
00515
00516 ROS_ERROR("Creating NaoqiJointStates object failed with error ");
00517 return -1;
00518 }
00519
00520 sensors->run();
00521
00522 delete sensors;
00523
00524 ROS_INFO("naoqi_joint_states stopped");
00525 return 0;
00526 }