diff --git a/CMakeLists.txt b/CMakeLists.txt
index 671ca98e..196eb6eb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,6 +6,7 @@ set(
CONVERTERS_SRC
src/converters/audio.cpp
src/converters/touch.cpp
+ src/converters/people.cpp
src/converters/camera.cpp
src/converters/diagnostics.cpp
src/converters/imu.cpp
@@ -19,7 +20,9 @@ set(
src/converters/memory/string.cpp
src/converters/sonar.cpp
src/converters/log.cpp
+ src/converters/battery.cpp
src/converters/odom.cpp
+ src/converters/sound.cpp
)
set(
TOOLS_SRC
@@ -40,12 +43,24 @@ set(
SUBSCRIBER_SRC
src/subscribers/teleop.cpp
src/subscribers/moveto.cpp
+ src/subscribers/navigateto.cpp
src/subscribers/speech.cpp
+ src/subscribers/animated_speech.cpp
+ src/subscribers/play_animation.cpp
+ src/subscribers/relocalizeinmap.cpp
)
set(
SERVICES_SRC
src/services/robot_config.cpp
+ src/services/behavior_manager.cpp
+ src/services/localization.cpp
+ src/services/tracking.cpp
+ src/services/motion.cpp
+ src/services/navigation.cpp
+ src/services/text_to_speech.cpp
+ src/services/animated_speech.cpp
+ src/services/robot_posture.cpp
)
set(
@@ -66,6 +81,8 @@ set(
src/event/basic.hpp
src/event/audio.cpp
src/event/touch.cpp
+ src/event/people.cpp
+ src/event/sound.cpp
)
# use catkin if qibuild is not found
diff --git a/CMakeLists_catkin.txt b/CMakeLists_catkin.txt
index 3f42cc14..9dce6d55 100644
--- a/CMakeLists_catkin.txt
+++ b/CMakeLists_catkin.txt
@@ -11,12 +11,14 @@ find_package(catkin COMPONENTS
image_transport
kdl_parser
naoqi_bridge_msgs
+ nao_interaction_msgs
naoqi_libqi
naoqi_libqicore
robot_state_publisher
rosbag_storage
rosgraph_msgs
sensor_msgs
+ std_srvs
tf2_geometry_msgs
tf2_msgs
tf2_ros
diff --git a/README.rst b/README.rst
index 95c01686..073aa7f8 100644
--- a/README.rst
+++ b/README.rst
@@ -17,13 +17,12 @@ How it works
============
The **naoqi_driver** module is a NAOqi module that also acts
-as a ROS node. As there is no **roscore** on the robot, it
-needs to be given the IP of the **roscore** in order to be
+as a ROS node. It needs to be given the IP of the **roscore** in order to be
registered as a node in the ROS processing graph. Usually,
-you will start your **roscore** on your local desktop.
+you will start your **roscore** on your local desktop
+(or on a robot in case of instaling ROS there).
-Once connected, normal ROS communication is happening between
-your robot, running NAOqi OS, and your desktop, running ROS.
+Once connected, ROS communicates with NAOqi OS running on your robot.
For further information, you can go `here `_ or build the doc:
diff --git a/launch/register_depth.launch b/launch/register_depth.launch
new file mode 100644
index 00000000..5a79da73
--- /dev/null
+++ b/launch/register_depth.launch
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package.xml b/package.xml
index aecd7151..053438fb 100644
--- a/package.xml
+++ b/package.xml
@@ -18,6 +18,7 @@
image_transport
kdl_parser
naoqi_bridge_msgs
+ nao_interaction_msgs
naoqi_libqi
naoqi_libqicore
orocos_kdl
@@ -25,6 +26,7 @@
rosbag_storage
rosgraph_msgs
sensor_msgs
+ std_srvs
tf2_geometry_msgs
tf2_msgs
tf2_ros
@@ -36,6 +38,7 @@
image_transport
kdl_parser
naoqi_bridge_msgs
+ nao_interaction_msgs
naoqi_libqi
naoqi_libqicore
orocos_kdl
diff --git a/share/boot_config.json b/share/boot_config.json
index 513254e8..cb508382 100644
--- a/share/boot_config.json
+++ b/share/boot_config.json
@@ -11,7 +11,7 @@
},
"bottom_camera":
{
- "enabled" : true,
+ "enabled" : false,
"resolution" : 1,
"fps" : 10,
"recorder_fps" : 5
@@ -70,10 +70,21 @@
"enabled" : true,
"frequency" : 10
},
+ "battery":
+ {
+ "enabled" : true,
+ "frequency" : 10
+ },
"audio":
{
"enabled" : true
},
+ "sound":
+ {
+ "enabled" : true,
+ "energy" : true,
+ "sensitivity" : 0.9
+ },
"bumper":
{
"enabled" : true
@@ -89,7 +100,15 @@
"odom":
{
"enabled" : true,
- "frequency" : 15
+ "frequency" : 50
+ },
+ "face":
+ {
+ "enabled" : true
+ },
+ "people":
+ {
+ "enabled" : true
}
}
}
diff --git a/src/converters/battery.cpp b/src/converters/battery.cpp
new file mode 100644
index 00000000..34960a2d
--- /dev/null
+++ b/src/converters/battery.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2015 Aldebaran
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+/*
+* LOCAL includes
+*/
+#include "battery.hpp"
+#include "../tools/from_any_value.hpp"
+
+/*
+* BOOST includes
+*/
+#include
+#define for_each BOOST_FOREACH
+
+namespace naoqi
+{
+namespace converter
+{
+
+BatteryConverter::BatteryConverter( const std::string& name, const float& frequency, const qi::SessionPtr& session )
+ : BaseConverter( name, frequency, session ),
+ p_memory_( session->service("ALMemory") ),
+ p_battery_( session->service("ALBattery") ),
+ is_subscribed_(false)
+{
+ std::vector keys;
+ keys.push_back("Device/SubDeviceList/Battery/Charge/Sensor/Value");
+ keys.push_back("Device/SubDeviceList/Battery/Charge/Sensor/TotalVoltage");
+ keys.push_back("Device/SubDeviceList/Battery/Current/Sensor/Value");
+ keys.push_back("Device/SubDeviceList/Platform/ILS/Sensor/Value");
+ keys.push_back("Device/SubDeviceList/Battery/Charge/Sensor/Charging");
+ keys.push_back("ALBattery/ConnectedToChargingStation");
+
+ keys_.resize(keys.size());
+ size_t i = 0;
+ for(std::vector::const_iterator it = keys.begin(); it != keys.end(); ++it, ++i)
+ keys_[i] = *it;
+}
+
+BatteryConverter::~BatteryConverter()
+{
+ if (is_subscribed_)
+ {
+ is_subscribed_ = false;
+ }
+}
+
+void BatteryConverter::registerCallback( message_actions::MessageAction action, Callback_t cb )
+{
+ callbacks_[action] = cb;
+}
+
+void BatteryConverter::callAll( const std::vector& actions )
+{
+ if (!is_subscribed_)
+ {
+ is_subscribed_ = true;
+ }
+
+ std::vector values;
+ try {
+ qi::AnyValue anyvalues = p_memory_.call("getListData", keys_);
+ tools::fromAnyValueToFloatVector(anyvalues, values);
+ } catch (const std::exception& e) {
+ std::cerr << "Exception caught in BatteryConverter: " << e.what() << std::endl;
+ return;
+ }
+
+ msg_.header.stamp = ros::Time::now();
+ msg_.charge = (int)(values[0] * 100.0);
+ msg_.voltage = values[1];
+ msg_.current = values[2];
+ msg_.hatch_open = (bool)values[3];
+ msg_.charging = ((int)values[4]) == 8;
+ msg_.connected_to_charging_station = (bool)values[5];
+
+ for_each( message_actions::MessageAction action, actions )
+ {
+ callbacks_[action]( msg_ );
+ }
+}
+
+void BatteryConverter::reset( )
+{
+ if (is_subscribed_)
+ {
+// p_battery_.call("unsubscribe", "ROS");
+ is_subscribed_ = false;
+ }
+}
+
+} // publisher
+} //naoqi
diff --git a/src/converters/battery.hpp b/src/converters/battery.hpp
new file mode 100644
index 00000000..589c3664
--- /dev/null
+++ b/src/converters/battery.hpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2015 Aldebaran
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+#ifndef BATTERY_CONVERTER_HPP
+#define BATTERY_CONVERTER_HPP
+
+/*
+* LOCAL includes
+*/
+#include "converter_base.hpp"
+#include
+
+/*
+* ROS includes
+*/
+#include
+
+namespace naoqi
+{
+namespace converter
+{
+
+class BatteryConverter : public BaseConverter
+{
+
+ typedef boost::function Callback_t;
+
+
+public:
+ BatteryConverter( const std::string& name, const float& frequency, const qi::SessionPtr& session );
+
+ ~BatteryConverter();
+
+ void reset( );
+
+ void registerCallback( message_actions::MessageAction action, Callback_t cb );
+
+ void callAll( const std::vector& actions );
+
+
+private:
+ std::map callbacks_;
+
+ /** Battery (Proxy) configurations */
+ qi::AnyObject p_battery_;
+ /** Memory (Proxy) configurations */
+ qi::AnyObject p_memory_;
+ /** Key describeing whether we are subscribed to the ALBattery module */
+ bool is_subscribed_;
+
+ /** The memory keys of the battery */
+ std::vector keys_;
+ /** Pre-filled messges that are sent */
+ nao_interaction_msgs::BatteryInfo msg_;
+};
+
+} //publisher
+} //naoqi
+
+#endif
diff --git a/src/converters/camera_info_definitions.hpp b/src/converters/camera_info_definitions.hpp
index 7d935f3a..73a65492 100644
--- a/src/converters/camera_info_definitions.hpp
+++ b/src/converters/camera_info_definitions.hpp
@@ -60,14 +60,14 @@ inline sensor_msgs::CameraInfo createCameraInfoTOPQVGA()
cam_info_msg.width = 320;
cam_info_msg.height = 240;
- cam_info_msg.K = boost::array{{ 274.139508945831, 0, 141.184472810944, 0, 275.741846757374, 106.693773654172, 0, 0, 1 }};
+ cam_info_msg.K = boost::array{{ 299.6062514048825, 0.0, 158.1342557533627, 0.0, 299.0567251221516, 128.32075058816002, 0.0, 0.0, 1.0 }};
cam_info_msg.distortion_model = "plumb_bob";
- cam_info_msg.D = boost::assign::list_of(-0.0870160932911717)(0.128210165050533)(0.003379500659424)(-0.00106205540818586)(0).convert_to_container >();
+ cam_info_msg.D = boost::assign::list_of(0.10703186895554358)(-0.29398440554631)(-0.000510763491296248)(-0.0007849727454197071)(0).convert_to_container >();
cam_info_msg.R = boost::array{{ 1, 0, 0, 0, 1, 0, 0, 0, 1 }};
- cam_info_msg.P = boost::array{{ 272.423675537109, 0, 141.131930791285, 0, 0, 273.515747070312, 107.391746054313, 0, 0, 0, 1, 0 }};
+ cam_info_msg.P = boost::array{{ 300.6907958984375, 0.0, 157.3720124539832, 0.0, 0.0, 300.78662109375, 127.71553373332426, 0.0, 0.0, 0.0, 1.0, 0.0 }};
return cam_info_msg;
}
@@ -173,8 +173,8 @@ inline sensor_msgs::CameraInfo createCameraInfoDEPTHVGA()
cam_info_msg.height = 480;
cam_info_msg.K = boost::array{{ 525, 0, 319.5000000, 0, 525, 239.5000000000000, 0, 0, 1 }};
- //cam_info_msg.distortion_model = "plumb_bob";
- //cam_info_msg.D = boost::assign::list_of(-0.0688388724945936)(0.0697453843669642)(0.00309518737071049)(-0.00570486993696543)(0);
+ cam_info_msg.distortion_model = "plumb_bob";
+ cam_info_msg.D = boost::assign::list_of(-0.0688388724945936)(0.0697453843669642)(0.00309518737071049)(-0.00570486993696543)(0).convert_to_container >();
cam_info_msg.R = boost::array{{ 1, 0, 0, 0, 1, 0, 0, 0, 1 }};
@@ -192,14 +192,14 @@ inline sensor_msgs::CameraInfo createCameraInfoDEPTHQVGA()
cam_info_msg.width = 320;
cam_info_msg.height = 240;
- cam_info_msg.K = boost::array{{ 525/2.0f, 0, 319.5000000/2.0f, 0, 525/2.0f, 239.5000000000000/2.0f, 0, 0, 1 }};
+ cam_info_msg.K = boost::array{{ 285.6768151355473, 0.0, 161.1691935721059, 0.0, 285.5373311462721, 127.602991640182, 0.0, 0.0, 1.0 }};
- //cam_info_msg.distortion_model = "plumb_bob";
- //cam_info_msg.D = boost::assign::list_of(-0.0688388724945936)(0.0697453843669642)(0.00309518737071049)(-0.00570486993696543)(0);
+ cam_info_msg.distortion_model = "plumb_bob";
+ cam_info_msg.D = boost::assign::list_of(0.016936081367960803)(-0.06749793149686571)(-0.0003138996585151219)(-0.000699207560377712)(0).convert_to_container >();
cam_info_msg.R = boost::array{{ 1, 0, 0, 0, 1, 0, 0, 0, 1 }};
- cam_info_msg.P = boost::array{{ 525/2.0f, 0, 319.500000/2.0f, 0, 0, 525/2.0f, 239.5000000000/2.0f, 0, 0, 0, 1, 0 }};
+ cam_info_msg.P = boost::array{{ 284.4026794433594, 0.0, 160.49353466767207, 0.0, 0.0, 284.6112365722656, 127.04678797627457, 0.0, 0.0, 0.0, 1.0, 0.0 }};
return cam_info_msg;
}
@@ -214,8 +214,8 @@ inline sensor_msgs::CameraInfo createCameraInfoDEPTHQQVGA()
cam_info_msg.height = 120;
cam_info_msg.K = boost::array{{ 525/4.0f, 0, 319.5000000/4.0f, 0, 525/4.0f, 239.5000000000000/4.0f, 0, 0, 1 }};
- //cam_info_msg.distortion_model = "plumb_bob";
- //cam_info_msg.D = boost::assign::list_of(-0.0688388724945936)(0.0697453843669642)(0.00309518737071049)(-0.00570486993696543)(0);
+ cam_info_msg.distortion_model = "plumb_bob";
+ cam_info_msg.D = boost::assign::list_of(-0.0688388724945936)(0.0697453843669642)(0.00309518737071049)(-0.00570486993696543)(0).convert_to_container >();
cam_info_msg.R = boost::array{{ 1, 0, 0, 0, 1, 0, 0, 0, 1 }};
diff --git a/src/converters/people.cpp b/src/converters/people.cpp
new file mode 100644
index 00000000..f5ef665a
--- /dev/null
+++ b/src/converters/people.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2015 Aldebaran
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+/*
+* LOCAL includes
+*/
+#include "people.hpp"
+
+/*
+* BOOST includes
+*/
+#include
+#define for_each BOOST_FOREACH
+
+namespace naoqi{
+
+namespace converter{
+
+template
+PeopleEventConverter::PeopleEventConverter(const std::string& name, const float& frequency, const qi::SessionPtr& session)
+ : BaseConverter >(name, frequency, session)
+{
+}
+
+template
+PeopleEventConverter::~PeopleEventConverter() {
+}
+
+template
+void PeopleEventConverter::reset()
+{
+}
+
+template
+void PeopleEventConverter::registerCallback( const message_actions::MessageAction action, Callback_t cb )
+{
+ callbacks_[action] = cb;
+}
+
+template
+void PeopleEventConverter::callAll(const std::vector& actions, T& msg)
+{
+ msg_ = msg;
+ for_each( message_actions::MessageAction action, actions )
+ {
+ callbacks_[action](msg_);
+ }
+}
+
+// http://stackoverflow.com/questions/8752837/undefined-reference-to-template-class-constructor
+template class PeopleEventConverter;
+template class PeopleEventConverter;
+}
+
+}
diff --git a/src/converters/people.hpp b/src/converters/people.hpp
new file mode 100644
index 00000000..9f2e04d8
--- /dev/null
+++ b/src/converters/people.hpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 Aldebaran
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+#ifndef PEOPLE_EVENT_CONVERTER_HPP
+#define PEOPLE_EVENT_CONVERTER_HPP
+
+/*
+* LOCAL includes
+*/
+#include "converter_base.hpp"
+#include
+
+/*
+* ROS includes
+*/
+#include
+#include
+/*
+* ALDEBARAN includes
+*/
+#include
+
+namespace naoqi{
+
+namespace converter{
+
+template
+class PeopleEventConverter : public BaseConverter >
+{
+
+ typedef boost::function Callback_t;
+
+public:
+ PeopleEventConverter(const std::string& name, const float& frequency, const qi::SessionPtr& session);
+
+ ~PeopleEventConverter();
+
+ virtual void reset();
+
+ void registerCallback( const message_actions::MessageAction action, Callback_t cb );
+
+ void callAll(const std::vector& actions, T& msg);
+
+private:
+ /** Registered Callbacks **/
+ std::map callbacks_;
+ T msg_;
+};
+
+}
+
+}
+
+#endif // PEOPLE_CONVERTER_HPP
diff --git a/src/converters/sound.cpp b/src/converters/sound.cpp
new file mode 100644
index 00000000..3ca89dd5
--- /dev/null
+++ b/src/converters/sound.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 Aldebaran
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+/*
+* LOCAL includes
+*/
+#include "sound.hpp"
+
+/*
+* BOOST includes
+*/
+#include
+#define for_each BOOST_FOREACH
+
+namespace naoqi{
+
+namespace converter{
+
+template
+SoundEventConverter::SoundEventConverter(const std::string& name, const float& frequency, const qi::SessionPtr& session)
+ : BaseConverter >(name, frequency, session)
+{
+}
+
+template
+SoundEventConverter::~SoundEventConverter() {
+}
+
+template
+void SoundEventConverter::reset()
+{
+}
+
+template
+void SoundEventConverter::registerCallback( const message_actions::MessageAction action, Callback_t cb )
+{
+ callbacks_[action] = cb;
+}
+
+template
+void SoundEventConverter::callAll(const std::vector& actions, T& msg)
+{
+ msg_ = msg;
+ for_each( message_actions::MessageAction action, actions )
+ {
+ callbacks_[action](msg_);
+ }
+}
+
+// http://stackoverflow.com/questions/8752837/undefined-reference-to-template-class-constructor
+template class SoundEventConverter;
+}
+
+}
diff --git a/src/converters/sound.hpp b/src/converters/sound.hpp
new file mode 100644
index 00000000..ef3c364b
--- /dev/null
+++ b/src/converters/sound.hpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015 Aldebaran
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+#ifndef SOUND_EVENT_CONVERTER_HPP
+#define SOUND_EVENT_CONVERTER_HPP
+
+/*
+* LOCAL includes
+*/
+#include "converter_base.hpp"
+#include
+
+/*
+* ROS includes
+*/
+#include
+/*
+* ALDEBARAN includes
+*/
+#include
+
+namespace naoqi{
+
+namespace converter{
+
+template
+class SoundEventConverter : public BaseConverter >
+{
+
+ typedef boost::function Callback_t;
+
+public:
+ SoundEventConverter(const std::string& name, const float& frequency, const qi::SessionPtr& session);
+
+ ~SoundEventConverter();
+
+ virtual void reset();
+
+ void registerCallback( const message_actions::MessageAction action, Callback_t cb );
+
+ void callAll(const std::vector& actions, T& msg);
+
+private:
+ /** Registered Callbacks **/
+ std::map callbacks_;
+ T msg_;
+};
+
+}
+
+}
+
+#endif // PEOPLE_CONVERTER_HPP
diff --git a/src/event/people.cpp b/src/event/people.cpp
new file mode 100644
index 00000000..f0968d76
--- /dev/null
+++ b/src/event/people.cpp
@@ -0,0 +1,522 @@
+/*
+ * Copyright 2015 Aldebaran
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+#include
+#include
+
+#include
+
+#include
+
+#include
+
+#include
+#include
+#include "../tools/from_any_value.hpp"
+#include
+
+#include "people.hpp"
+
+namespace naoqi
+{
+
+template
+PeopleEventRegister::PeopleEventRegister()
+{
+}
+
+template
+PeopleEventRegister::PeopleEventRegister( const std::string& name, const std::vector keys, const float& frequency, const qi::SessionPtr& session )
+ : serviceId(0),
+ p_memory_( session->service("ALMemory")),
+ p_people_( session->service("ALPeoplePerception") ),
+ p_gaze_( session->service("ALGazeAnalysis") ),
+ p_face_( session->service("ALFaceCharacteristics") ),
+ p_waving_( session->service("ALWavingDetection") ),
+ session_(session),
+ isStarted_(false),
+ isPublishing_(false),
+ isRecording_(false),
+ isDumping_(false),
+ prefix("PeoplePerception/Person/")
+{
+ memory_keys.push_back("/IsFaceDetected");
+ memory_keys.push_back("/IsWaving");
+ memory_keys.push_back("/GazeDirection");
+ memory_keys.push_back("/HeadAngles");
+ memory_keys.push_back("/IsLookingAtRobot");
+ memory_keys.push_back("/LookingAtRobotScore");
+ memory_keys.push_back("/AgeProperties");
+ memory_keys.push_back("/GenderProperties");
+ memory_keys.push_back("/SmileProperties");
+ memory_keys.push_back("/ExpressionProperties");
+
+ publisher_ = boost::make_shared >( name );
+ //recorder_ = boost::make_shared >( name );
+ converter_ = boost::make_shared >( name, frequency, session );
+
+ converter_->registerCallback( message_actions::PUBLISH, boost::bind(&publisher::BasicPublisher::publish, publisher_, _1) );
+ //converter_->registerCallback( message_actions::RECORD, boost::bind(&recorder::BasicEventRecorder::write, recorder_, _1) );
+ //converter_->registerCallback( message_actions::LOG, boost::bind(&recorder::BasicEventRecorder::bufferize, recorder_, _1) );
+
+ keys_.resize(keys.size());
+ size_t i = 0;
+ for(std::vector::const_iterator it = keys.begin(); it != keys.end(); ++it, ++i)
+ keys_[i] = *it;
+
+ name_ = name;
+}
+
+template
+PeopleEventRegister::~PeopleEventRegister()
+{
+ stopProcess();
+}
+
+template
+void PeopleEventRegister::resetPublisher(ros::NodeHandle& nh)
+{
+ publisher_->reset(nh);
+}
+
+template
+void PeopleEventRegister::resetRecorder( boost::shared_ptr gr )
+{
+ //recorder_->reset(gr, converter_->frequency());
+}
+
+template
+void PeopleEventRegister::startProcess()
+{
+ boost::mutex::scoped_lock start_lock(mutex_);
+ if (!isStarted_)
+ {
+ if(!serviceId)
+ {
+ //std::string serviceName = std::string("ROS-Driver-") + typeid(T).name();
+ std::string serviceName = std::string("ROS-Driver-") + keys_[0];
+ serviceId = session_->registerService(serviceName, this->shared_from_this());
+ for(std::vector::const_iterator it = keys_.begin(); it != keys_.end(); ++it) {
+ std::cerr << *it << std::endl;
+ p_memory_.call("subscribeToEvent",it->c_str(), serviceName, "peopleCallback");
+ }
+ if(keys_[0].compare("PeoplePerception/PeopleDetected")==0) {
+ std::cout< People : Start"<("subscribe", "ROS");
+ std::cout< Gaze : Start"<("subscribe", "ROS");
+ std::cout< Face : Start"<("subscribe", "ROS");
+ std::cout< Waving : Start"<("subscribe", "ROS");
+ }
+ std::cout << serviceName << " : Start" << std::endl;
+ }
+ isStarted_ = true;
+ }
+}
+
+template
+void PeopleEventRegister::stopProcess()
+{
+ boost::mutex::scoped_lock stop_lock(mutex_);
+ if (isStarted_)
+ {
+ //std::string serviceName = std::string("ROS-Driver-") + typeid(T).name();
+ std::string serviceName = std::string("ROS-Driver-") + keys_[0];
+ if(serviceId){
+ if(keys_[0].compare("PeoplePerception/PeopleDetected")==0) {
+ std::cout< People : Stop"<("unsubscribe", "ROS");
+ std::cout< Gaze : Stop"<("unsubscribe", "ROS");
+ std::cout< Face : Stop"<("unsubscribe", "ROS");
+ std::cout< Waving : Stop"<("unsubscribe", "ROS");
+ }
+ for(std::vector::const_iterator it = keys_.begin(); it != keys_.end(); ++it) {
+ p_memory_.call("unsubscribeToEvent",it->c_str(), serviceName);
+ }
+ session_->unregisterService(serviceId);
+ serviceId = 0;
+ }
+ std::cout << serviceName << " : Stop" << std::endl;
+ isStarted_ = false;
+ }
+}
+
+template
+void PeopleEventRegister::writeDump(const ros::Time& time)
+{
+ if (isStarted_)
+ {
+ //recorder_->writeDump(time);
+ }
+}
+
+template
+void PeopleEventRegister::setBufferDuration(float duration)
+{
+ //recorder_->setBufferDuration(duration);
+}
+
+template
+void PeopleEventRegister::isRecording(bool state)
+{
+ boost::mutex::scoped_lock rec_lock(mutex_);
+ isRecording_ = state;
+}
+
+template
+void PeopleEventRegister::isPublishing(bool state)
+{
+ boost::mutex::scoped_lock pub_lock(mutex_);
+ isPublishing_ = state;
+}
+
+template
+void PeopleEventRegister::isDumping(bool state)
+{
+ boost::mutex::scoped_lock dump_lock(mutex_);
+ isDumping_ = state;
+}
+
+template
+void PeopleEventRegister::registerCallback()
+{
+}
+
+template
+void PeopleEventRegister::unregisterCallback()
+{
+}
+
+template
+void PeopleEventRegister::peopleCallback(std::string &key, qi::AnyValue &value, qi::AnyValue &message)
+{
+ T msg = T();
+
+ peopleCallbackMessage(key, value, msg);
+
+ std::vector actions;
+ boost::mutex::scoped_lock callback_lock(mutex_);
+
+ if (isStarted_) {
+ // CHECK FOR PUBLISH
+ if ( isPublishing_ && publisher_->isSubscribed() )
+ {
+ actions.push_back(message_actions::PUBLISH);
+ }
+ // CHECK FOR RECORD
+ if ( isRecording_ )
+ {
+ //actions.push_back(message_actions::RECORD);
+ }
+ if ( !isDumping_ )
+ {
+ //actions.push_back(message_actions::LOG);
+ }
+ if (actions.size() >0)
+ {
+ converter_->callAll( actions, msg );
+ }
+ }
+}
+
+template
+void PeopleEventRegister::peopleCallbackMessage(std::string &key, qi::AnyValue &value, nao_interaction_msgs::FaceDetectedArray &msg)
+{
+ tools::NaoqiFaceDetected faces;
+ try {
+ faces = tools::fromAnyValueToNaoqiFaceDetected(value);
+ }
+ catch(std::runtime_error& e)
+ {
+ ROS_DEBUG_STREAM("Cannot retrieve facedetect: " << e.what());
+ return;
+ }
+ if ( faces.face_info.size() == 0 ) return;
+
+ msg.header.frame_id = "CameraTop_optical_frame";
+ msg.header.stamp = ros::Time::now();
+
+ for(int i = 0; i < faces.face_info.size(); i++) {
+ nao_interaction_msgs::FaceDetected face;
+ face.header = msg.header;
+ face.face_id.data = faces.face_info[i].extra_info[0].face_id;
+ face.score_reco.data = faces.face_info[i].extra_info[0].score_reco;
+ face.face_label.data = faces.face_info[i].extra_info[0].face_label;
+
+ face.shape_alpha.data = faces.face_info[i].shape_info.alpha;
+ face.shape_beta.data = faces.face_info[i].shape_info.beta;
+ face.shape_sizeX.data = faces.face_info[i].shape_info.sizeX;
+ face.shape_sizeY.data = faces.face_info[i].shape_info.sizeY;
+
+ face.right_eye_eyeCenter_x.data = faces.face_info[i].extra_info[0].right_eye_points.eye_center_x;
+ face.right_eye_eyeCenter_y.data = faces.face_info[i].extra_info[0].right_eye_points.eye_center_y;
+ face.right_eye_noseSideLimit_x.data = faces.face_info[i].extra_info[0].right_eye_points.nose_side_limit_x;
+ face.right_eye_noseSideLimit_y.data = faces.face_info[i].extra_info[0].right_eye_points.nose_side_limit_y;
+ face.right_eye_earSideLimit_x.data = faces.face_info[i].extra_info[0].right_eye_points.ear_side_limit_x;
+ face.right_eye_earSideLimit_y.data = faces.face_info[i].extra_info[0].right_eye_points.ear_side_limit_y;
+
+ face.left_eye_eyeCenter_x.data = faces.face_info[i].extra_info[0].left_eye_points.eye_center_x;
+ face.left_eye_eyeCenter_y.data = faces.face_info[i].extra_info[0].left_eye_points.eye_center_y;
+ face.left_eye_noseSideLimit_x.data = faces.face_info[i].extra_info[0].left_eye_points.nose_side_limit_x;
+ face.left_eye_noseSideLimit_y.data = faces.face_info[i].extra_info[0].left_eye_points.nose_side_limit_y;
+ face.left_eye_earSideLimit_x.data = faces.face_info[i].extra_info[0].left_eye_points.ear_side_limit_x;
+ face.left_eye_earSideLimit_y.data = faces.face_info[i].extra_info[0].left_eye_points.ear_side_limit_y;
+
+ face.nose_bottomCenterLimit_x.data = faces.face_info[i].extra_info[0].nose_points.bottom_center_limit_x;
+ face.nose_bottomCenterLimit_y.data = faces.face_info[i].extra_info[0].nose_points.bottom_center_limit_y;
+ face.nose_bottomLeftLimit_x.data = faces.face_info[i].extra_info[0].nose_points.bottom_left_limit_x;
+ face.nose_bottomLeftLimit_y.data = faces.face_info[i].extra_info[0].nose_points.bottom_left_limit_y;
+ face.nose_bottomRightLimit_x.data = faces.face_info[i].extra_info[0].nose_points.bottom_right_limit_x;
+ face.nose_bottomRightLimit_y.data = faces.face_info[i].extra_info[0].nose_points.bottom_right_limit_y;
+
+ face.mouth_leftLimit_x.data = faces.face_info[i].extra_info[0].mouth_points.left_limit_x;
+ face.mouth_leftLimit_y.data = faces.face_info[i].extra_info[0].mouth_points.left_limit_y;
+ face.mouth_rightLimit_x.data = faces.face_info[i].extra_info[0].mouth_points.right_limit_x;
+ face.mouth_rightLimit_y.data = faces.face_info[i].extra_info[0].mouth_points.right_limit_y;
+ face.mouth_topLimit_x.data = faces.face_info[i].extra_info[0].mouth_points.top_limit_x;
+ face.mouth_topLimit_y.data = faces.face_info[i].extra_info[0].mouth_points.top_limit_y;
+
+ msg.face_array.push_back(face);
+ }
+}
+
+template
+geometry_msgs::Point PeopleEventRegister::toCartesian(float dist, float azi, float inc) {
+ geometry_msgs::Point p;
+ p.x = dist * std::sin(inc) * std::cos(azi) * (-1); // Inverted
+ p.y = dist * std::sin(inc) * std::sin(azi);
+ p.z = dist * std::cos(inc);
+ return p;
+}
+
+template
+void PeopleEventRegister::peopleCallbackMessage(std::string &key, qi::AnyValue &value, nao_interaction_msgs::PersonDetectedArray &msg)
+{
+ tools::NaoqiPersonDetected people;
+ try {
+ people = tools::fromAnyValueToNaoqiPersonDetected(value);
+ }
+ catch(std::runtime_error& e)
+ {
+ ROS_DEBUG_STREAM("Cannot retrieve persondetected: " << e.what());
+ return;
+ }
+
+ msg.header.frame_id = "CameraDepth_optical_frame";
+ msg.header.stamp = ros::Time::now();
+
+ for(int i = 0; i < people.person_info.size(); i++) {
+ std::string sid = num_to_str(people.person_info[i].id);
+ std::vector keys;
+ for(int j = 0; j < memory_keys.size(); j++) {
+ keys.push_back(prefix+sid+memory_keys[j]);
+ }
+
+ qi::AnyValue data = (qi::AnyValue)p_memory_.call("getListData", keys);
+
+ nao_interaction_msgs::PersonDetected pd;
+ pd.face.gender = -1; // Since 0 = female, initialising as -1 to disambigute no data from femal.
+
+ /* People Perception */
+ try {
+ pd.id = people.person_info[i].id;
+ pd.person.distance = people.person_info[i].distance_to_camera;
+ pd.person.yaw = people.person_info[i].yaw_angle_in_image;
+ pd.person.pitch = people.person_info[i].pitch_angle_in_image;
+ pd.person.position.position = toCartesian(pd.person.distance, pd.person.pitch, pd.person.yaw);
+ pd.person.position.orientation.w = 1.0;
+
+ if(data.size() != keys.size()) {
+ msg.person_array.push_back(pd);
+ ROS_DEBUG("Could not retrieve any face information");
+ continue;
+ }
+
+ try {
+ pd.person.face_detected = (bool)data[0].content().asInt32();
+ } catch(...) {
+ ROS_DEBUG("Error retreiving face detected");
+ }
+
+ try {
+ pd.person.is_waving = (bool)data[1].content().asInt32();
+ } catch(...) {
+ ROS_DEBUG("Error retreiving if waving");
+ }
+
+ if(pd.person.face_detected) {
+ /* Gaze Analysis */
+ try {
+ qi::AnyReference gaze = data[2].content();
+ if(gaze.kind() == qi::TypeKind_List && gaze.size() == 2)
+ {
+ qi::AnyReference g, yaw, pitch;
+ yaw = gaze[0].content();
+ pitch = gaze[1].content();
+ if(yaw.kind() == qi::TypeKind_Float && pitch.kind() == qi::TypeKind_Float) {
+ tf::Quaternion q;
+ q.setRPY(0.0, pitch.asFloat(), yaw.asFloat());
+ pd.gaze.gaze_angle.x = q.x();
+ pd.gaze.gaze_angle.y = q.y();
+ pd.gaze.gaze_angle.z = q.z();
+ pd.gaze.gaze_angle.w = q.w();
+ } else {
+ ROS_DEBUG("Could not retrieve yaw/pitch");
+ }
+ } else {
+ ROS_DEBUG("Could not retrieve gaze");
+ }
+ } catch(std::runtime_error& e) {
+ ROS_DEBUG_STREAM("Error retrieving gaze angle: " << e.what());
+ }
+ try {
+ qi::AnyReference head_angle = data[3].content();
+ if(head_angle.kind() == qi::TypeKind_List && head_angle.size() == 3)
+ {
+ qi::AnyReference yaw, pitch, roll;
+ yaw = head_angle[0].content();
+ pitch = head_angle[1].content();
+ roll = head_angle[2].content();
+ if(yaw.kind() == qi::TypeKind_Float && pitch.kind() == qi::TypeKind_Float && roll.kind() == qi::TypeKind_Float) {
+ tf::Quaternion q;
+ q.setRPY(roll.asFloat(), pitch.asFloat(), yaw.asFloat());
+ pd.gaze.head_angle.x = q.x();
+ pd.gaze.head_angle.y = q.y();
+ pd.gaze.head_angle.z = q.z();
+ pd.gaze.head_angle.w = q.w();
+ } else {
+ ROS_DEBUG("Could not retrieve yaw/pitch/roll");
+ }
+ } else {
+ ROS_DEBUG("Could not retrieve head angle");
+ }
+ } catch(std::runtime_error& e) {
+ ROS_DEBUG_STREAM("Error retrieving head angle: " << e.what());
+ }
+ try {
+ pd.gaze.looking_at_robot = (bool)data[4].content().asInt32();
+ pd.gaze.looking_at_robot_score = data[5].content().asFloat();
+ } catch(std::runtime_error& e) {
+ ROS_DEBUG_STREAM("Error retrieving looking at robot: " << e.what());
+ }
+
+ /* Face Charcteristics */
+ try {
+ qi::AnyReference age_props = data[6].content();
+ if(age_props.kind() == qi::TypeKind_List && age_props.size() == 2)
+ {
+ qi::AnyReference age, conf;
+ age = age_props[0].content();
+ conf = age_props[1].content();
+ if(age.kind() == qi::TypeKind_Float && conf.kind() == qi::TypeKind_Float) {
+ pd.face.age = (int)age.asFloat();
+ pd.face.age_confidence = conf.asFloat();
+ } else {
+ ROS_DEBUG("Could not retrieve age and confidence");
+ }
+ } else {
+ ROS_DEBUG("Could not retrieve age");
+ }
+ } catch(std::runtime_error& e) {
+ ROS_DEBUG_STREAM("Error retrieving age: " << e.what());
+ }
+ try {
+ qi::AnyReference gender_props = data[7].content();
+ if(gender_props.kind() == qi::TypeKind_List && gender_props.size() == 2)
+ {
+ qi::AnyReference gender, conf;
+ gender = gender_props[0].content();
+ conf = gender_props[1].content();
+ if(gender.kind() == qi::TypeKind_Float && conf.kind() == qi::TypeKind_Float) {
+ pd.face.gender = (int)gender.asFloat();
+ pd.face.gender_confidence = conf.asFloat();
+ } else {
+ ROS_DEBUG("Could not retrieve gender and confidence");
+ }
+ } else {
+ ROS_DEBUG("Could not retrieve gender");
+ }
+ } catch(std::runtime_error& e) {
+ ROS_DEBUG_STREAM("Error retrieving gender: " << e.what());
+ }
+ try {
+ qi::AnyReference smile_props = data[8].content();
+ if(smile_props.kind() == qi::TypeKind_List && smile_props.size() == 2)
+ {
+ qi::AnyReference smile_degree, conf;
+ smile_degree = smile_props[0].content();
+ conf = smile_props[1].content();
+ if(smile_degree.kind() == qi::TypeKind_Float && conf.kind() == qi::TypeKind_Float) {
+ pd.face.smile_degree = smile_degree.asFloat();
+ pd.face.smile_degree_confidence = conf.asFloat();
+ } else {
+ ROS_DEBUG("Could not retrieve smile degree and confidence");
+ }
+ } else {
+ ROS_DEBUG("Could not retrieve smile");
+ }
+ } catch(std::runtime_error& e) {
+ ROS_DEBUG_STREAM("Error retrieving smile: " << e.what());
+ }
+ try {
+ qi::AnyReference expression_props = data[9].content();
+ if(expression_props.kind() == qi::TypeKind_List && expression_props.size() == 5)
+ {
+ qi::AnyReference neutral, happy, surprised, angry, sad;
+ neutral = expression_props[0].content();
+ happy = expression_props[1].content();
+ surprised = expression_props[2].content();
+ angry = expression_props[3].content();
+ sad = expression_props[4].content();
+ if(neutral.kind() == qi::TypeKind_Float
+ && happy.kind() == qi::TypeKind_Float
+ && surprised.kind() == qi::TypeKind_Float
+ && angry.kind() == qi::TypeKind_Float
+ && sad.kind() == qi::TypeKind_Float) {
+ pd.face.expression_properties.neutral = neutral.asFloat();
+ pd.face.expression_properties.happy = happy.asFloat();
+ pd.face.expression_properties.surprised = surprised.asFloat();
+ pd.face.expression_properties.angry = angry.asFloat();
+ pd.face.expression_properties.sad = sad.asFloat();
+ } else {
+ ROS_DEBUG("Could not retrieve neutral/happy/surprised/angry/sad");
+ }
+ } else {
+ ROS_DEBUG("Could not retrieve expression");
+ }
+ } catch(std::runtime_error& e) {
+ ROS_DEBUG_STREAM("Error retrieving expression: " << e.what());
+ }
+ }
+ } catch(std::runtime_error& e) {
+ ROS_DEBUG_STREAM("Error retrieving person information: " << e.what());
+ }
+
+ msg.person_array.push_back(pd);
+ }
+}
+
+// http://stackoverflow.com/questions/8752837/undefined-reference-to-template-class-constructor
+template class PeopleEventRegister;
+template class PeopleEventRegister;
+
+}//namespace
diff --git a/src/event/people.hpp b/src/event/people.hpp
new file mode 100644
index 00000000..df130e14
--- /dev/null
+++ b/src/event/people.hpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2015 Aldebaran
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+#ifndef PEOPLE_EVENT_REGISTER_HPP
+#define PEOPLE_EVENT_REGISTER_HPP
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "../tools/naoqi_facedetected.hpp"
+
+// Converter
+#include "../src/converters/people.hpp"
+// Publisher
+#include "../src/publishers/basic.hpp"
+// Recorder
+#include "../recorder/basic_event.hpp"
+
+namespace naoqi
+{
+
+/**
+* @brief GlobalRecorder concept interface
+* @note this defines an private concept struct,
+* which each instance has to implement
+* @note a type erasure pattern in implemented here to avoid strict inheritance,
+* thus each possible publisher instance has to implement the virtual functions mentioned in the concept
+*/
+template
+class PeopleEventRegister: public boost::enable_shared_from_this >
+{
+
+public:
+
+ /**
+ * @brief Constructor for recorder interface
+ */
+ PeopleEventRegister();
+ PeopleEventRegister(const std::string& name, const std::vector keys, const float& frequency, const qi::SessionPtr& session );
+ ~PeopleEventRegister();
+
+ void resetPublisher( ros::NodeHandle& nh );
+ void resetRecorder( boost::shared_ptr gr );
+
+ void startProcess();
+ void stopProcess();
+
+ void writeDump(const ros::Time& time);
+ void setBufferDuration(float duration);
+
+ void isRecording(bool state);
+ void isPublishing(bool state);
+ void isDumping(bool state);
+
+ void peopleCallback(std::string &key, qi::AnyValue &value, qi::AnyValue &message);
+ void peopleCallbackMessage(std::string &key, qi::AnyValue &value, nao_interaction_msgs::FaceDetectedArray &msg);
+ void peopleCallbackMessage(std::string &key, qi::AnyValue &value, nao_interaction_msgs::PersonDetectedArray &msg);
+
+private:
+ void registerCallback();
+ void unregisterCallback();
+ void onEvent();
+ geometry_msgs::Point toCartesian(float dist, float azi, float inc);
+ template
+ std::string num_to_str(N num) {
+ std::stringstream ss;
+ ss << num;
+ return ss.str();
+ }
+
+private:
+ boost::shared_ptr > converter_;
+ boost::shared_ptr > publisher_;
+ //boost::shared_ptr > recorder_;
+
+ qi::SessionPtr session_;
+ qi::AnyObject p_memory_, p_people_, p_gaze_, p_face_, p_waving_;
+ unsigned int serviceId;
+ std::string name_;
+
+ boost::mutex mutex_;
+
+ bool isStarted_;
+ bool isPublishing_;
+ bool isRecording_;
+ bool isDumping_;
+
+ std::string prefix;
+ std::vector memory_keys;
+
+protected:
+ std::vector keys_;
+}; // class
+
+
+class FaceDetectedEventRegister: public PeopleEventRegister
+{
+public:
+ FaceDetectedEventRegister( const std::string& name, const std::vector keys, const float& frequency, const qi::SessionPtr& session ) : PeopleEventRegister(name, keys, frequency, session) {}
+};
+
+class PersonDetectedEventRegister: public PeopleEventRegister
+{
+public:
+ PersonDetectedEventRegister( const std::string& name, const std::vector keys, const float& frequency, const qi::SessionPtr& session ) : PeopleEventRegister(name, keys, frequency, session) {}
+};
+
+//QI_REGISTER_OBJECT(FaceDetectEventRegister, peopleCallback)
+//QI_REGISTER_OBJECT(PersonDetectedEventRegister, peopleCallback)
+
+static bool _qiregisterPeopleEventRegisterFaceDetected() {
+ ::qi::ObjectTypeBuilder > b;
+ QI_VAARGS_APPLY(__QI_REGISTER_ELEMENT, PeopleEventRegister, peopleCallback)
+ b.registerType();
+ return true;
+ }
+static bool BOOST_PP_CAT(__qi_registration, __LINE__) = _qiregisterPeopleEventRegisterFaceDetected();
+
+static bool _qiregisterPeopleEventRegisterPersonDetected() {
+ ::qi::ObjectTypeBuilder > b;
+ QI_VAARGS_APPLY(__QI_REGISTER_ELEMENT, PeopleEventRegister, peopleCallback)
+ b.registerType();
+ return true;
+ }
+static bool BOOST_PP_CAT(__qi_registration, __LINE__) = _qiregisterPeopleEventRegisterPersonDetected();
+
+} //naoqi
+
+#endif
diff --git a/src/event/sound.cpp b/src/event/sound.cpp
new file mode 100644
index 00000000..e820cc46
--- /dev/null
+++ b/src/event/sound.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2015 Aldebaran
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+#include
+#include
+
+#include
+
+#include
+
+#include
+
+#include
+#include
+
+#include "sound.hpp"
+#include "../tools/from_any_value.hpp"
+
+namespace naoqi
+{
+
+template
+SoundEventRegister::SoundEventRegister()
+{
+}
+
+template
+SoundEventRegister::SoundEventRegister(const std::string& name, std::vector keys, const float& frequency, const qi::SessionPtr& session )
+ : serviceId(0),
+ keys_(keys),
+ p_memory_(session->service("ALMemory")),
+ p_sound_loc_(session->service("ALSoundLocalization")),
+ session_(session),
+ isStarted_(false),
+ isPublishing_(false),
+ isRecording_(false),
+ isDumping_(false)
+{
+
+ publisher_ = boost::make_shared >( name );
+ recorder_ = boost::make_shared >( name );
+ converter_ = boost::make_shared >( name, frequency, session );
+
+ converter_->registerCallback( message_actions::PUBLISH, boost::bind(&publisher::BasicPublisher::publish, publisher_, _1) );
+ converter_->registerCallback( message_actions::RECORD, boost::bind(&recorder::BasicEventRecorder::write, recorder_, _1) );
+ converter_->registerCallback( message_actions::LOG, boost::bind(&recorder::BasicEventRecorder::bufferize, recorder_, _1) );
+
+}
+
+template
+SoundEventRegister::~SoundEventRegister()
+{
+ stopProcess();
+}
+
+template
+void SoundEventRegister::resetPublisher(ros::NodeHandle& nh)
+{
+ publisher_->reset(nh);
+}
+
+template
+void SoundEventRegister::resetRecorder( boost::shared_ptr gr )
+{
+ recorder_->reset(gr, converter_->frequency());
+}
+
+template
+void SoundEventRegister::setEnergyComputation(bool run) {
+ p_sound_loc_.call("setParameter", "EnergyComputation", run);
+}
+
+template
+void SoundEventRegister::setSensitivity(float level) {
+ p_sound_loc_.call("setParameter", "Sensitivity", level);
+}
+
+template
+void SoundEventRegister::startProcess()
+{
+ boost::mutex::scoped_lock start_lock(mutex_);
+ if (!isStarted_)
+ {
+ if(!serviceId)
+ {
+ std::string serviceName = std::string("ROS-Driver-") + keys_[0];
+ serviceId = session_->registerService(serviceName, this->shared_from_this());
+ for(std::vector::const_iterator it = keys_.begin(); it != keys_.end(); ++it) {
+ std::cerr << *it << std::endl;
+ p_memory_.call("subscribeToEvent",it->c_str(), serviceName, "soundCallback");
+ }
+ std::cout << serviceName << " : Start" << std::endl;
+ }
+ isStarted_ = true;
+ }
+}
+
+template
+void SoundEventRegister::stopProcess()
+{
+ boost::mutex::scoped_lock stop_lock(mutex_);
+ if (isStarted_)
+ {
+ std::string serviceName = std::string("ROS-Driver-") + keys_[0];
+ if(serviceId){
+ for(std::vector::const_iterator it = keys_.begin(); it != keys_.end(); ++it) {
+ p_memory_.call("unsubscribeToEvent",it->c_str(), serviceName);
+ }
+ session_->unregisterService(serviceId);
+ serviceId = 0;
+ }
+ std::cout << serviceName << " : Stop" << std::endl;
+ isStarted_ = false;
+ }
+}
+
+template
+void SoundEventRegister::writeDump(const ros::Time& time)
+{
+ if (isStarted_)
+ {
+ recorder_->writeDump(time);
+ }
+}
+
+template
+void SoundEventRegister::setBufferDuration(float duration)
+{
+ recorder_->setBufferDuration(duration);
+}
+
+template
+void SoundEventRegister::isRecording(bool state)
+{
+ boost::mutex::scoped_lock rec_lock(mutex_);
+ isRecording_ = state;
+}
+
+template
+void SoundEventRegister::isPublishing(bool state)
+{
+ boost::mutex::scoped_lock pub_lock(mutex_);
+ isPublishing_ = state;
+}
+
+template
+void SoundEventRegister::isDumping(bool state)
+{
+ boost::mutex::scoped_lock dump_lock(mutex_);
+ isDumping_ = state;
+}
+
+template
+void SoundEventRegister::registerCallback()
+{
+}
+
+template
+void SoundEventRegister::unregisterCallback()
+{
+}
+
+template
+void SoundEventRegister::soundCallback(std::string &key, qi::AnyValue &value, qi::AnyValue &message) {
+ T msg = T();
+
+ soundCallbackMessage(key, value, msg);
+
+ std::vector actions;
+ boost::mutex::scoped_lock callback_lock(mutex_);
+ if (isStarted_) {
+ // CHECK FOR PUBLISH
+ if ( isPublishing_ && publisher_->isSubscribed() )
+ {
+ actions.push_back(message_actions::PUBLISH);
+ }
+ // CHECK FOR RECORD
+ if ( isRecording_ )
+ {
+ actions.push_back(message_actions::RECORD);
+ }
+ if ( !isDumping_ )
+ {
+ actions.push_back(message_actions::LOG);
+ }
+ if (actions.size() >0)
+ {
+ converter_->callAll( actions, msg );
+ }
+ }
+}
+
+template
+void SoundEventRegister::soundCallbackMessage(std::string &key, qi::AnyValue &value, nao_interaction_msgs::AudioSourceLocalization &msg) {
+ msg.header.stamp = ros::Time::now();
+ msg.header.frame_id = "Head";
+
+ qi::AnyReferenceVector anyref;
+ try{
+ anyref = value.asListValuePtr();
+ }
+ catch(std::runtime_error& e)
+ {
+ ROS_DEBUG_STREAM("Could not transform AnyValue into list: " << e.what());
+ }
+
+ if(anyref.size() != 4) {
+ ROS_DEBUG("Could not retrieve sound location");
+ return;
+ }
+
+ qi::AnyReference ref = anyref[1].content();
+
+ if(ref.kind() == qi::TypeKind_List && ref.size() == 4) {
+ qi::AnyReference azi, ele, conf, ener;
+ azi = ref[0].content();
+ ele = ref[1].content();
+ conf = ref[2].content();
+ ener = ref[3].content();
+ if(azi.kind() == qi::TypeKind_Float && ele.kind() == qi::TypeKind_Float
+ && conf.kind() == qi::TypeKind_Float && ener.kind() == qi::TypeKind_Float) {
+ msg.azimuth.data = azi.asFloat();
+ msg.elevation.data = ele.asFloat();
+ msg.confidence.data = conf.asFloat();
+ msg.energy.data = ener.asFloat();
+ } else{
+ ROS_DEBUG("Could not retrieve azi/ele/conf/ener");
+ }
+ } else {
+ ROS_DEBUG("Could not retrieve sound location");
+ }
+}
+
+// http://stackoverflow.com/questions/8752837/undefined-reference-to-template-class-constructor
+template class SoundEventRegister;
+
+}//namespace
diff --git a/src/event/sound.hpp b/src/event/sound.hpp
new file mode 100644
index 00000000..2f6a8fdb
--- /dev/null
+++ b/src/event/sound.hpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2015 Aldebaran
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+#ifndef SOUND_EVENT_REGISTER_HPP
+#define SOUND_EVENT_REGISTER_HPP
+
+#include
+
+#include
+#include
+#include
+#include