cortex_stream.cpp
Go to the documentation of this file.
00001 /* 
00002  * A ROS interface for the Cortex Motion Capture System Network Stream
00003  *
00004  * Copyright 2011 by Daniel Maier, University of Freiburg
00005  * based on the robular implementation by Joerg Mueller
00006  * 
00007  * This program is free software: you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation, version 3.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include <ros/ros.h>
00021 #include <cortex_stream/cortex.h>
00022 #include <map>
00023 #include <visualization_msgs/Marker.h>
00024 #include <visualization_msgs/MarkerArray.h>
00025 #include <std_msgs/ColorRGBA.h>
00026 #include <geometry_msgs/Pose.h>
00027 #include <geometry_msgs/Vector3.h>
00028 #include <boost/thread.hpp>
00029 #include <boost/lexical_cast.hpp>
00030 #include <limits>
00031 using namespace std;
00032 
00033 
00034 // Publisher for marker message
00035 ros::Publisher marker_pub;
00036 
00037 // Class containing callbacks, bodies, etc.
00038 class MocapInterface
00039 {
00040    public:
00041       MocapInterface();
00042       void init_colors();
00043       void processOnce();
00044       int cortexRequestPort;
00045       int cortexMulticastPort;
00046       std::string cortexAddress;
00047       void handleCortexFrame(void *frame);
00048    protected:
00049       double conversionFactor; // [meters per MoCap units]
00050       double requestCortexTimeout; // [s]
00051       double frameRate; // [Hz]
00052       struct BodyDefinition {
00053          std::vector<std::string> markerNames;
00054       };
00055       boost::recursive_mutex marker_array_msg_lock_;
00056       visualization_msgs::MarkerArray markerArrayMsg;
00057       std::map<std::string, BodyDefinition> body;
00058       std::string marker_frame_id_;
00059       std::vector<std_msgs::ColorRGBA> colors_;
00060 };
00061 
00062 // Constructor using ROS params 
00063 MocapInterface::MocapInterface()
00064 {
00065    ros::NodeHandle nh;
00066    ros::NodeHandle private_nh("~");
00067    private_nh.param("cortexRequestPort", cortexRequestPort, 1510); 
00068    private_nh.param("cortexMulticastPort", cortexMulticastPort, 1509); 
00069    private_nh.param("cortexAddress", cortexAddress, std::string("132.230.167.153")); 
00070    private_nh.param("markerFrameId", marker_frame_id_, std::string("/map")); 
00071    conversionFactor = 0.001; // meters per MoCap unit
00072    requestCortexTimeout = 0.5; // seconds
00073    init_colors();
00074 }
00075 void MocapInterface::init_colors()
00076 {
00077    double alpha = 0.8;
00078    std_msgs::ColorRGBA color;
00079    color.r = 1.0;
00080    color.g = 0.0;
00081    color.b = 0.0;
00082    color.a = alpha;
00083    colors_.push_back(color);
00084    color.r = 0.0;
00085    color.g = 1.0;
00086    color.b = 0.0;
00087    colors_.push_back(color);
00088    color.r = 0.0;
00089    color.g = 0.0;
00090    color.b = 1.0;
00091    colors_.push_back(color);
00092    color.r = 0.0;
00093    color.g = 1.0;
00094    color.b = 1.0;
00095    colors_.push_back(color);
00096    color.r = 1.0;
00097    color.g = 1.0;
00098    color.b = 0.0;
00099    colors_.push_back(color);
00100    color.r = 1.0;
00101    color.g = 0.0;
00102    color.b = 1.0;
00103    colors_.push_back(color);
00104    // 6 default colors
00105 }
00106 
00107 // Corext Data Handler is called everytime new data is recieved from the cortex thread
00108 // this has to be global, so we call the actual handler (member function) in here
00109 void CortexDataHandler(sFrameOfData* frame, void *params)
00110 {
00111    ((MocapInterface*)params)->handleCortexFrame(frame);
00112 }
00113 
00114 
00115 // Actual handler for processing a frame of the Cortex Data Stream
00116 void MocapInterface::handleCortexFrame(void *frame)
00117 {
00118    static unsigned int frame_count = 0;
00119    if (frame_count % 200 == 0)
00120    {
00121       ROS_INFO("Got frame (this message shows only every 2 secs)");
00122       frame_count = 0;
00123    }
00124    frame_count++;
00125    sFrameOfData *f = (sFrameOfData*)frame;
00126    ros::Time timestamp = ros::Time::now() - ros::Duration(f->fDelay); // TODO: subtract network transfer delay
00127 
00128    double scale_fac = 0.05;
00129    sBodyData *b = f->BodyData;
00130    markerArrayMsg.markers.clear();
00131    boost::recursive_mutex::scoped_lock marker_array_msglock(marker_array_msg_lock_);
00132    // loop over all bodies in that frame
00133    for (int i=0; i<f->nBodies; i++, b++) {
00134       visualization_msgs::Marker markerMsg;
00135       markerMsg.type = visualization_msgs::Marker::CUBE_LIST; // we use cubes because they can be colorized individually (unlike spheres for whatever reason...)
00136       markerMsg.header.frame_id = marker_frame_id_;
00137       markerMsg.header.stamp = timestamp;
00138       markerMsg.header.seq = f->iFrame;
00139       markerMsg.action = visualization_msgs::Marker::ADD;
00140       markerMsg.id = 0; // marker id is 0, because we use a different namespace for every body
00141       markerMsg.ns = b->szName; // marker namespace is body name
00142       markerMsg.points.clear();
00143       markerMsg.colors.clear();
00144       // set color for markers of that body (newer ROS versions will use the colors vector variable instead)
00145       markerMsg.color.r = 1.0;
00146       markerMsg.color.g = 1.0;
00147       markerMsg.color.b = 1.0;
00148       markerMsg.color.a = 1.0;
00149       markerMsg.scale.x = scale_fac;
00150       markerMsg.scale.y = scale_fac;
00151       markerMsg.scale.z = scale_fac;
00152       geometry_msgs::Pose pose;
00153       // body pose is not known (requires some model fitting and tracking) 
00154       // so set body origin to (0,0,0) and alter marker positions instead
00155       pose.position.x = 0;
00156       pose.position.y = 0;
00157       pose.position.z = 0;
00158       for (int j=0; j<b->nMarkers; j++) {
00159          geometry_msgs::Point p;
00160          std_msgs::ColorRGBA color;
00161          // if marker not detected by Cortex publish NaN
00162          if (b->Markers[j][0] == XEMPTY &&
00163                b->Markers[j][1] == XEMPTY &&
00164                b->Markers[j][2] == XEMPTY)
00165          {
00166             float quietNan = std::numeric_limits<float>::quiet_NaN();
00167             p.x = quietNan;
00168             p.y = quietNan;
00169             p.z = quietNan;
00170          }
00171          else
00172          {
00173             p.x = b->Markers[j][0]*conversionFactor;
00174             p.y = b->Markers[j][1]*conversionFactor;
00175             p.z = b->Markers[j][2]*conversionFactor;
00176          }
00177          color = colors_[ j % colors_.size() ];
00178          markerMsg.colors.push_back(color);
00179          markerMsg.points.push_back(p);
00180          // ignore marker names right now
00181          // this is what we should do:
00182          // markerMsg.body[b->szName].marker[body[b->szName].markerNames[j]] = m;
00183       }
00184       markerArrayMsg.markers.push_back(markerMsg);
00185    }
00186    marker_pub.publish(markerArrayMsg);
00187 }
00188 
00189 // global Error Msg Handler for Cortex
00190 void CortexErrorMsgHandler(int iLevel, const char *szMsg, void*)
00191 {
00192    if (iLevel == VL_Debug) {
00193       ROS_DEBUG("Cortex: %s", szMsg);
00194    } else if (iLevel == VL_Info) {
00195       ROS_INFO("Cortex: %s", szMsg);
00196    } else if (iLevel == VL_Warning) {
00197       ROS_WARN("Cortex: %s", szMsg);
00198    } else if (iLevel == VL_Error) {
00199       ROS_ERROR("Cortex: %s", szMsg);
00200    } else {
00201       ROS_ERROR("Received unknown Cortex Error Msg");
00202    }
00203 }
00204 
00205 // Initialization of Cortex stream (e.g. body definitions, ports, etc)
00206 void MocapInterface::processOnce()
00207 {
00208    Cortex_SetVerbosityLevel(VL_Info);
00209    Cortex_SetErrorMsgHandlerFunc(CortexErrorMsgHandler, this);
00210    if (Cortex_SetRequestPort(cortexRequestPort) != RC_Okay)
00211       return;
00212    if (Cortex_SetMulticastPort(cortexMulticastPort) != RC_Okay)
00213       return;
00214    if (Cortex_Initialize(cortexAddress.c_str()) != RC_Okay) {
00215       std::cerr << "Unable to initialize Cortex client\n";
00216       return;
00217    }
00218 
00219    // request distance unit
00220    void *response = NULL;
00221    int numBytes = 0;
00222    int retval;
00223    retval = Cortex_Request("GetConversionToMillimeters", &response, &numBytes, requestCortexTimeout);
00224    if (retval != RC_Okay || numBytes != 4) {
00225       std::cerr << "Error: Failed to get conversion factor to millimeters\n";
00226       Cortex_Exit();
00227       return;
00228    }
00229    float factor;
00230    memcpy(&factor, response, 4);
00231    conversionFactor = factor/1000.0;
00232    std::cerr << "Got conversion factor " << conversionFactor << " meters per MoCap unit\n";
00233 
00234    // request frame rate
00235    numBytes = 0;
00236    retval = Cortex_Request("GetContextFrameRate", &response, &numBytes, requestCortexTimeout);
00237    if (retval != RC_Okay || numBytes != 4) {
00238       std::cerr << "Error: Failed to get frame rate\n";
00239       Cortex_Exit();
00240       return;
00241    }
00242    float rate;
00243    memcpy(&rate, response, 4);
00244    frameRate = rate;
00245    //std::cerr << "Got frame rate " << frameRate << " Hz\n";
00246    ROS_INFO("Got frame rate %4.2f Hz",frameRate);
00247 
00248    // request body definitions
00249    sBodyDefs *bodies = Cortex_GetBodyDefs(requestCortexTimeout);
00250    if (bodies == NULL) {
00251       std::cerr << "Error: Failed to get body definitions\n";
00252       Cortex_Exit();
00253       return;
00254    }
00255    // get bodies from cortex
00256    // a body consists of a name and a set of markers
00257    // every marker has a (unique) name 
00258    std::cerr << "Got body definitions:";
00259    sBodyDef *b = bodies->BodyDefs;
00260    for (int i=0; i<bodies->nBodyDefs; i++, b++) {
00261       BodyDefinition bd;
00262       bd.markerNames.reserve(b->nMarkers);
00263       for (int j=0; j<b->nMarkers; j++)
00264          bd.markerNames.push_back(b->szMarkerNames[j]);
00265       body[b->szName] = bd;
00266       std::cerr << " " << b->szName;
00267    }
00268    std::cerr << "\n";
00269 
00270    // start data handling
00271    Cortex_SetDataHandlerFunc(CortexDataHandler, this);
00272 }
00273 
00274 
00275 int main(int argc, char ** argv)
00276 {
00277    ros::init(argc,argv,"cortex_stream");
00278    ros::NodeHandle nh;
00279    marker_pub = nh.advertise<visualization_msgs::MarkerArray>( "cortex_marker_array", 0 );
00280    MocapInterface mocap; // create interface
00281    mocap.processOnce(); // call initialization
00282    ros::Rate r(100.0);
00283    while(ros::ok())
00284    {
00285       r.sleep();
00286       ros::spinOnce();
00287    }
00288    Cortex_Exit();
00289    ROS_INFO("Exit peacefully");
00290    return 0;
00291 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines


cortex_stream
Author(s): Daniel Maier
autogenerated on Wed Oct 31 2012 08:22:56