Added SaveObjectsExample node (added optional dependency on find_object_2d). Updated demo_find_object.launch. rtabmap: Added mutex around user data access.

This commit is contained in:
matlabbe
2018-05-23 10:53:13 -04:00
parent a39ffe382c
commit 2139338b11
7 changed files with 344 additions and 52 deletions
+12
View File
@@ -15,6 +15,7 @@ find_package(catkin REQUIRED COMPONENTS
find_package(costmap_2d) find_package(costmap_2d)
find_package(octomap_ros) find_package(octomap_ros)
find_package(rviz) find_package(rviz)
find_package(find_object_2d)
## System dependencies are found with CMake's conventions ## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system) # find_package(Boost REQUIRED COMPONENTS system)
@@ -122,6 +123,9 @@ ENDIF(octomap_ros_FOUND)
IF(rviz_FOUND) IF(rviz_FOUND)
SET(optional_dependencies ${optional_dependencies} rviz) SET(optional_dependencies ${optional_dependencies} rviz)
ENDIF(rviz_FOUND) ENDIF(rviz_FOUND)
IF(find_object_2d_FOUND)
SET(optional_dependencies ${optional_dependencies} find_object_2d)
ENDIF(find_object_2d_FOUND)
catkin_package( catkin_package(
INCLUDE_DIRS include INCLUDE_DIRS include
@@ -310,6 +314,14 @@ target_link_libraries(wifi_signal_pub rtabmap_ros ${Libraries})
add_executable(wifi_signal_sub src/WifiSignalSubNode.cpp) add_executable(wifi_signal_sub src/WifiSignalSubNode.cpp)
target_link_libraries(wifi_signal_sub rtabmap_ros ${Libraries}) target_link_libraries(wifi_signal_sub rtabmap_ros ${Libraries})
# If find_object_2d is found, add save objects example
IF(find_object_2d_FOUND)
MESSAGE(STATUS "WITH find_object_2d")
include_directories(${find_object_2d_INCLUDE_DIRS})
add_executable(save_objects_example src/SaveObjectsExample.cpp)
target_link_libraries(save_objects_example rtabmap_ros ${Libraries} ${find_object_2d_LIBRARIES})
ENDIF(find_object_2d_FOUND)
add_executable(camera src/CameraNode.cpp) add_executable(camera src/CameraNode.cpp)
add_dependencies(camera ${${PROJECT_NAME}_EXPORTED_TARGETS}) add_dependencies(camera ${${PROJECT_NAME}_EXPORTED_TARGETS})
target_link_libraries(camera ${Libraries}) target_link_libraries(camera ${Libraries})
+1
View File
@@ -272,6 +272,7 @@ private:
ros::Subscriber userDataAsyncSub_; ros::Subscriber userDataAsyncSub_;
cv::Mat userData_; cv::Mat userData_;
UMutex userDataMutex_;
ros::Subscriber globalPoseAsyncSub_; ros::Subscriber globalPoseAsyncSub_;
geometry_msgs::PoseWithCovarianceStamped globalPose_; geometry_msgs::PoseWithCovarianceStamped globalPose_;
+48 -46
View File
@@ -6,7 +6,7 @@ Panels:
Expanded: Expanded:
- /Global Options1 - /Global Options1
- /TF1/Frames1 - /TF1/Frames1
Splitter Ratio: 0.434783 Splitter Ratio: 0.434783012
Tree Height: 590 Tree Height: 590
- Class: rviz/Selection - Class: rviz/Selection
Name: Selection Name: Selection
@@ -15,7 +15,7 @@ Panels:
- /2D Pose Estimate1 - /2D Pose Estimate1
- /2D Nav Goal1 - /2D Nav Goal1
Name: Tool Properties Name: Tool Properties
Splitter Ratio: 0.588679 Splitter Ratio: 0.588679016
- Class: rviz/Views - Class: rviz/Views
Expanded: Expanded:
- /Current View1 - /Current View1
@@ -36,7 +36,7 @@ Visualization Manager:
Color: 160; 160; 164 Color: 160; 160; 164
Enabled: true Enabled: true
Line Style: Line Style:
Line Width: 0.03 Line Width: 0.0299999993
Value: Lines Value: Lines
Name: Grid Name: Grid
Normal Cell Count: 0 Normal Cell Count: 0
@@ -51,8 +51,8 @@ Visualization Manager:
- Alpha: 1 - Alpha: 1
Autocompute Intensity Bounds: true Autocompute Intensity Bounds: true
Autocompute Value Bounds: Autocompute Value Bounds:
Max Value: 2.02684 Max Value: 2.02683997
Min Value: -1.12646 Min Value: -1.12645996
Value: true Value: true
Axis: Z Axis: Z
Channel Name: rgb Channel Name: rgb
@@ -63,17 +63,18 @@ Visualization Manager:
Enabled: true Enabled: true
Invert Rainbow: false Invert Rainbow: false
Max Color: 255; 255; 255 Max Color: 255; 255; 255
Max Intensity: 2.34177e-38 Max Intensity: 2.34176998e-38
Min Color: 0; 0; 0 Min Color: 0; 0; 0
Min Intensity: 9.21942e-41 Min Intensity: 9.21942286e-41
Name: PointCloud2 Name: PointCloud2
Position Transformer: XYZ Position Transformer: XYZ
Queue Size: 10 Queue Size: 10
Selectable: true Selectable: true
Size (Pixels): 3 Size (Pixels): 3
Size (m): 0.01 Size (m): 0.00999999978
Style: Points Style: Points
Topic: /voxel_cloud Topic: /voxel_cloud
Unreliable: false
Use Fixed Frame: true Use Fixed Frame: true
Use rainbow: true Use rainbow: true
Value: true Value: true
@@ -100,16 +101,6 @@ Visualization Manager:
Value: true Value: true
map: map:
Value: true Value: true
object_4:
Value: true
object_5:
Value: true
object_6:
Value: true
object_7:
Value: true
object_8:
Value: true
odom: odom:
Value: true Value: true
wheelLB_linkWheel_link: wheelLB_linkWheel_link:
@@ -146,16 +137,7 @@ Visualization Manager:
{} {}
camera_rgb_frame: camera_rgb_frame:
camera_rgb_optical_frame: camera_rgb_optical_frame:
object_4: {}
{}
object_5:
{}
object_6:
{}
object_7:
{}
object_8:
{}
wheelLB_linkWheel_link: wheelLB_linkWheel_link:
wheelLB_wheel_link: wheelLB_wheel_link:
{} {}
@@ -173,8 +155,8 @@ Visualization Manager:
- Alpha: 1 - Alpha: 1
Autocompute Intensity Bounds: true Autocompute Intensity Bounds: true
Autocompute Value Bounds: Autocompute Value Bounds:
Max Value: -0.574923 Max Value: 4.7127676
Min Value: -5.11672 Min Value: 0.0444712937
Value: true Value: true
Axis: X Axis: X
Channel Name: intensity Channel Name: intensity
@@ -193,19 +175,22 @@ Visualization Manager:
Queue Size: 10 Queue Size: 10
Selectable: true Selectable: true
Size (Pixels): 5 Size (Pixels): 5
Size (m): 0.01 Size (m): 0.00999999978
Style: Points Style: Points
Topic: /base_scan Topic: /base_scan
Unreliable: false
Use Fixed Frame: false Use Fixed Frame: false
Use rainbow: true Use rainbow: true
Value: true Value: true
- Alpha: 0.7 - Alpha: 0.699999988
Class: rviz/Map Class: rviz/Map
Color Scheme: map Color Scheme: map
Draw Behind: false Draw Behind: false
Enabled: true Enabled: true
Name: Map Name: Map
Topic: /rtabmap/grid_map Topic: /rtabmap/grid_map
Unreliable: false
Use Timestamp: false
Value: true Value: true
- Alpha: 1 - Alpha: 1
Class: rviz/RobotModel Class: rviz/RobotModel
@@ -233,6 +218,7 @@ Visualization Manager:
Normalize Range: true Normalize Range: true
Queue Size: 2 Queue Size: 2
Transport Hint: compressed Transport Hint: compressed
Unreliable: false
Value: false Value: false
- Alpha: 1 - Alpha: 1
Autocompute Intensity Bounds: true Autocompute Intensity Bounds: true
@@ -245,12 +231,14 @@ Visualization Manager:
Class: rtabmap_ros/MapCloud Class: rtabmap_ros/MapCloud
Cloud decimation: 4 Cloud decimation: 4
Cloud max depth (m): 3 Cloud max depth (m): 3
Cloud voxel size (m): 0.02 Cloud min depth (m): 0
Cloud voxel size (m): 0.0199999996
Color: 255; 255; 255 Color: 255; 255; 255
Color Transformer: RGB8 Color Transformer: RGB8
Download graph: false Download graph: false
Download map: false Download map: false
Enabled: true Enabled: true
Filter ceiling (m): 0
Filter floor (m): 0 Filter floor (m): 0
Invert Rainbow: false Invert Rainbow: false
Max Color: 255; 255; 255 Max Color: 255; 255; 255
@@ -259,12 +247,13 @@ Visualization Manager:
Min Intensity: 0 Min Intensity: 0
Name: MapCloud Name: MapCloud
Node filtering angle (degrees): 20 Node filtering angle (degrees): 20
Node filtering radius (m): 0.2 Node filtering radius (m): 0.200000003
Position Transformer: XYZ Position Transformer: XYZ
Size (Pixels): 3 Size (Pixels): 3
Size (m): 0.01 Size (m): 0.00999999978
Style: Points Style: Points
Topic: /rtabmap/mapData Topic: /rtabmap/mapData
Unreliable: false
Use Fixed Frame: true Use Fixed Frame: true
Use rainbow: true Use rainbow: true
Value: true Value: true
@@ -272,10 +261,20 @@ Visualization Manager:
Enabled: true Enabled: true
Name: Info Name: Info
Topic: /rtabmap/info Topic: /rtabmap/info
Unreliable: false
Value: true
- Class: rviz/MarkerArray
Enabled: true
Marker Topic: /objectsMarkers
Name: MarkerArray
Namespaces:
{}
Queue Size: 100
Value: true Value: true
Enabled: true Enabled: true
Global Options: Global Options:
Background Color: 48; 48; 48 Background Color: 48; 48; 48
Default Light: true
Fixed Frame: map Fixed Frame: map
Frame Rate: 30 Frame Rate: 30
Name: root Name: root
@@ -293,22 +292,25 @@ Visualization Manager:
Views: Views:
Current: Current:
Class: rtabmap_ros/OrbitOriented Class: rtabmap_ros/OrbitOriented
Distance: 7.89956 Distance: 7.89955997
Enable Stereo Rendering: Enable Stereo Rendering:
Stereo Eye Separation: 0.06 Stereo Eye Separation: 0.0599999987
Stereo Focal Distance: 1 Stereo Focal Distance: 1
Swap Stereo Eyes: false Swap Stereo Eyes: false
Value: false Value: false
Focal Point: Focal Point:
X: 0.0199225 X: 0.0199225005
Y: 0.23516 Y: 0.235159993
Z: -0.0896359 Z: -0.0896359012
Focal Shape Fixed Size: true
Focal Shape Size: 0.0500000007
Invert Z Axis: false
Name: Current View Name: Current View
Near Clip Distance: 0.01 Near Clip Distance: 0.00999999978
Pitch: 0.819797 Pitch: 0.819796979
Target Frame: base_link Target Frame: base_link
Value: OrbitOriented (rtabmap) Value: OrbitOriented (rtabmap)
Yaw: 3.14375 Yaw: 3.14374995
Saved: ~ Saved: ~
Window Geometry: Window Geometry:
Displays: Displays:
@@ -318,7 +320,7 @@ Window Geometry:
Hide Right Dock: false Hide Right Dock: false
Image: Image:
collapsed: false collapsed: false
QMainWindow State: 000000ff00000000fd0000000400000000000001b0000002ddfc0200000007fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006400fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c0061007900730100000000000002dd000000dd00fffffffb0000000a0049006d006100670065000000022f000000ae0000001600fffffffb0000000a0049006d006100670065010000027d000000fa0000000000000000000000010000010f00000377fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000000000000377000000b000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004a00000003efc0100000002fb0000000800540069006d00650000000000000004a0000002f600fffffffb0000000800540069006d0065010000000000000450000000000000000000000463000002dd00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730000000000ffffffff0000000000000000 QMainWindow State: 000000ff00000000fd0000000400000000000001b0000002ddfc0200000007fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006100fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c0061007900730100000000000002dd000000d700fffffffb0000000a0049006d006100670065000000022f000000ae0000001600fffffffb0000000a0049006d006100670065010000027d000000fa0000000000000000000000010000010f00000377fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000000000000377000000ad00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004a00000003efc0100000002fb0000000800540069006d00650000000000000004a00000030000fffffffb0000000800540069006d0065010000000000000450000000000000000000000459000002dd00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730000000000ffffffff0000000000000000
Selection: Selection:
collapsed: false collapsed: false
Time: Time:
@@ -327,6 +329,6 @@ Window Geometry:
collapsed: false collapsed: false
Views: Views:
collapsed: false collapsed: false
Width: 1561 Width: 1551
X: 42 X: 49
Y: 107 Y: 107
+13 -1
View File
@@ -4,13 +4,17 @@
<!-- Choose visualization --> <!-- Choose visualization -->
<arg name="rviz" default="true" /> <arg name="rviz" default="true" />
<arg name="rtabmapviz" default="false" /> <arg name="rtabmapviz" default="false" />
<arg name="save_objects" default="false"/>
<arg name="localization" default="false"/>
<arg if="$(arg localization)" name="rtabmap_args" default=""/>
<arg unless="$(arg localization)" name="rtabmap_args" default="--delete_db_on_start"/>
<param name="use_sim_time" type="bool" value="True"/> <param name="use_sim_time" type="bool" value="True"/>
<!-- SLAM (robot side) --> <!-- SLAM (robot side) -->
<!-- args: "delete_db_on_start" and "udebug" --> <!-- args: "delete_db_on_start" and "udebug" -->
<group ns="rtabmap"> <group ns="rtabmap">
<node name="rtabmap" pkg="rtabmap_ros" type="rtabmap" output="screen" args="--delete_db_on_start"> <node name="rtabmap" pkg="rtabmap_ros" type="rtabmap" output="screen" args="$(arg rtabmap_args)">
<param name="frame_id" type="string" value="base_footprint"/> <param name="frame_id" type="string" value="base_footprint"/>
<param name="subscribe_depth" type="bool" value="true"/> <param name="subscribe_depth" type="bool" value="true"/>
@@ -18,6 +22,7 @@
<remap from="odom" to="/base_controller/odom"/> <remap from="odom" to="/base_controller/odom"/>
<remap from="scan" to="/base_scan"/> <remap from="scan" to="/base_scan"/>
<remap if="$(arg save_objects)" from="user_data_async" to="/objectsData"/>
<remap from="rgb/image" to="/camera/data_throttled_image"/> <remap from="rgb/image" to="/camera/data_throttled_image"/>
<remap from="depth/image" to="/camera/data_throttled_image_depth"/> <remap from="depth/image" to="/camera/data_throttled_image_depth"/>
@@ -46,6 +51,7 @@
<param name="Mem/NotLinkedNodesKept" type="string" value="false"/> <param name="Mem/NotLinkedNodesKept" type="string" value="false"/>
<param name="Optimizer/Slam2D" type="string" value="true"/> <param name="Optimizer/Slam2D" type="string" value="true"/>
<param name="Reg/Force3DoF" type="string" value="true"/> <param name="Reg/Force3DoF" type="string" value="true"/>
<param if="$(arg localization)" name="Mem/IncrementalMemory" type="string" value="false"/>
</node> </node>
<!-- Visualisation RTAB-Map --> <!-- Visualisation RTAB-Map -->
@@ -101,5 +107,11 @@
<param name="rgb/image_transport" type="string" value="compressed"/> <param name="rgb/image_transport" type="string" value="compressed"/>
<param name="depth_registered/image_transport" type="string" value="compressedDepth"/> <param name="depth_registered/image_transport" type="string" value="compressedDepth"/>
</node> </node>
<!-- Save objects to database example -->
<node if="$(arg save_objects)" name="save_objects_example" pkg="rtabmap_ros" type="save_objects_example" output="screen">
<remap from="mapData" to="/rtabmap/mapData"/>
<param name="frame_id" value="base_footprint"/>
</node>
</launch> </launch>
+2
View File
@@ -40,6 +40,7 @@
<build_depend>costmap_2d</build_depend> <build_depend>costmap_2d</build_depend>
<build_depend>octomap_ros</build_depend> <build_depend>octomap_ros</build_depend>
<build_depend>image_geometry</build_depend> <build_depend>image_geometry</build_depend>
<build_depend>find_object_2d</build_depend>
<run_depend>cv_bridge</run_depend> <run_depend>cv_bridge</run_depend>
<run_depend>roscpp</run_depend> <run_depend>roscpp</run_depend>
@@ -71,6 +72,7 @@
<run_depend>costmap_2d</run_depend> <run_depend>costmap_2d</run_depend>
<run_depend>octomap_ros</run_depend> <run_depend>octomap_ros</run_depend>
<run_depend>image_geometry</run_depend> <run_depend>image_geometry</run_depend>
<run_depend>find_object_2d</run_depend>
<build_depend>libpcl-all-dev</build_depend> <build_depend>libpcl-all-dev</build_depend>
+11 -5
View File
@@ -1117,6 +1117,7 @@ void CoreWrapper::commonDepthCallbackImpl(
if(userDataMsg.get()) if(userDataMsg.get())
{ {
userData = rtabmap_ros::userDataFromROS(*userDataMsg); userData = rtabmap_ros::userDataFromROS(*userDataMsg);
UScopeMutex lock(userDataMutex_);
if(!userData_.empty()) if(!userData_.empty())
{ {
NODELET_WARN("Synchronized and asynchronized user data topics cannot be used at the same time. Async user data dropped!"); NODELET_WARN("Synchronized and asynchronized user data topics cannot be used at the same time. Async user data dropped!");
@@ -1125,6 +1126,7 @@ void CoreWrapper::commonDepthCallbackImpl(
} }
else else
{ {
UScopeMutex lock(userDataMutex_);
userData = userData_; userData = userData_;
userData_ = cv::Mat(); userData_ = cv::Mat();
} }
@@ -1363,6 +1365,7 @@ void CoreWrapper::commonStereoCallback(
if(userDataMsg.get()) if(userDataMsg.get())
{ {
userData = rtabmap_ros::userDataFromROS(*userDataMsg); userData = rtabmap_ros::userDataFromROS(*userDataMsg);
UScopeMutex lock(userDataMutex_);
if(!userData_.empty()) if(!userData_.empty())
{ {
NODELET_WARN("Synchronized and asynchronized user data topics cannot be used at the same time. Async user data dropped!"); NODELET_WARN("Synchronized and asynchronized user data topics cannot be used at the same time. Async user data dropped!");
@@ -1371,6 +1374,7 @@ void CoreWrapper::commonStereoCallback(
} }
else else
{ {
UScopeMutex lock(userDataMutex_);
userData = userData_; userData = userData_;
userData_ = cv::Mat(); userData_ = cv::Mat();
} }
@@ -1663,6 +1667,7 @@ void CoreWrapper::userDataAsyncCallback(const rtabmap_ros::UserDataConstPtr & da
{ {
if(!paused_) if(!paused_)
{ {
UScopeMutex lock(userDataMutex_);
if(!userData_.empty()) if(!userData_.empty())
{ {
ROS_WARN("Overwriting previous user data set. Asynchronous user " ROS_WARN("Overwriting previous user data set. Asynchronous user "
@@ -1670,10 +1675,7 @@ void CoreWrapper::userDataAsyncCallback(const rtabmap_ros::UserDataConstPtr & da
"lower rate than map update rate (current %s=%f).", "lower rate than map update rate (current %s=%f).",
Parameters::kRtabmapDetectionRate().c_str(), rate_); Parameters::kRtabmapDetectionRate().c_str(), rate_);
} }
else userData_ = rtabmap_ros::userDataFromROS(*dataMsg);
{
userData_ = rtabmap_ros::userDataFromROS(*dataMsg);
}
} }
} }
@@ -1912,8 +1914,10 @@ bool CoreWrapper::resetRtabmapCallback(std_srvs::Empty::Request&, std_srvs::Empt
latestNodeWasReached_ = false; latestNodeWasReached_ = false;
mapsManager_.clear(); mapsManager_.clear();
previousStamp_ = ros::Time(0); previousStamp_ = ros::Time(0);
userData_ = cv::Mat();
globalPose_.header.stamp = ros::Time(0); globalPose_.header.stamp = ros::Time(0);
userDataMutex_.lock();
userData_ = cv::Mat();
userDataMutex_.unlock();
return true; return true;
} }
@@ -1967,7 +1971,9 @@ bool CoreWrapper::backupDatabaseCallback(std_srvs::Empty::Request&, std_srvs::Em
currentMetricGoal_.setNull(); currentMetricGoal_.setNull();
lastPublishedMetricGoal_.setNull(); lastPublishedMetricGoal_.setNull();
latestNodeWasReached_ = false; latestNodeWasReached_ = false;
userDataMutex_.lock();
userData_ = cv::Mat(); userData_ = cv::Mat();
userDataMutex_.unlock();
globalPose_.header.stamp = ros::Time(0); globalPose_.header.stamp = ros::Time(0);
NODELET_INFO("Backup: Saving \"%s\" to \"%s\"...", databasePath_.c_str(), (databasePath_+".back").c_str()); NODELET_INFO("Backup: Saving \"%s\" to \"%s\"...", databasePath_.c_str(), (databasePath_+".back").c_str());
+257
View File
@@ -0,0 +1,257 @@
/*
Copyright (c) 2011-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <ros/ros.h>
#include <tf/transform_listener.h>
#include <find_object_2d/ObjectsStamped.h>
#include <rtabmap/utilite/UConversion.h>
#include <opencv2/core.hpp>
#include <rtabmap_ros/UserData.h>
#include <rtabmap_ros/MsgConversion.h>
#include <rtabmap/core/Compression.h>
#include <visualization_msgs/MarkerArray.h>
class SaveObjectsExample
{
public:
SaveObjectsExample() :
objFramePrefix_("object"),
frameId_("base_link")
{
ros::NodeHandle pnh("~");
pnh.param("object_prefix", objFramePrefix_, objFramePrefix_);
pnh.param("frame_id", frameId_, frameId_);
ros::NodeHandle nh;
subObjects_ = nh.subscribe("objectsStamped", 1, &SaveObjectsExample::objectsDetectedCallback, this);
subsMapData_ = nh.subscribe("mapData", 1, &SaveObjectsExample::mapDataCallback, this);
pub_ = nh.advertise<rtabmap_ros::UserData>("objectsData", 1);
pubMarkers_ = nh.advertise<visualization_msgs::MarkerArray>("objectsMarkers", 1);
}
// from find_object_2d to rtabmap
void objectsDetectedCallback(const find_object_2d::ObjectsStampedConstPtr & msg)
{
if(msg->objects.data.size())
{
cv::Mat data(msg->objects.data.size()/12, 9, CV_64FC1);
for(unsigned int i=0; i<msg->objects.data.size(); i+=12)
{
// get data
int id = (int)msg->objects.data[i];
std::string objectFrameId = uFormat("%s_%d", objFramePrefix_.c_str(),id); // "object_1", "object_2"
// get pose of the object in base frame
tf::StampedTransform pose;
try
{
tfListener_.lookupTransform(frameId_, objectFrameId, msg->header.stamp, pose);
}
catch(tf::TransformException & ex)
{
ROS_WARN("%s",ex.what());
return;
}
data.at<double>(i, 0) = double(id);
data.at<double>(i, 1) = ros::Time(msg->header.stamp).toSec();
data.at<double>(i, 2) = pose.getOrigin().x();
data.at<double>(i, 3) = pose.getOrigin().y();
data.at<double>(i, 4) = pose.getOrigin().z();
data.at<double>(i, 5) = pose.getRotation().x();
data.at<double>(i, 6) = pose.getRotation().y();
data.at<double>(i, 7) = pose.getRotation().z();
data.at<double>(i, 8) = pose.getRotation().w();
}
rtabmap_ros::UserData dataMsg;
dataMsg.header.frame_id = msg->header.frame_id;
dataMsg.header.stamp = msg->header.stamp;
rtabmap_ros::userDataToROS(data, dataMsg, false);
pub_.publish(dataMsg);
}
}
// from rtabmap to rviz visualization
void mapDataCallback(const rtabmap_ros::MapDataConstPtr & msg)
{
std::map<double, int> nodeStamps; // <stamp, id>
std::map<int, rtabmap::Signature> signatures;
std::map<int, rtabmap::Transform> poses;
std::multimap<int, rtabmap::Link> links;
rtabmap::Transform mapToOdom;
rtabmap_ros::mapDataFromROS(*msg, poses, links, signatures, mapToOdom);
for(std::map<int, rtabmap::Signature>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
{
int id = iter->first;
rtabmap::Signature & node = iter->second;
if(!node.sensorData().userDataCompressed().empty() && nodeToObjects_.find(id)==nodeToObjects_.end())
{
cv::Mat data = rtabmap::uncompressData(node.sensorData().userDataCompressed());
ROS_ASSERT(data.cols == 9 && data.type() == CV_64FC1);
ROS_INFO("Node %d has %d object(s)", id, data.rows);
nodeToObjects_.insert(std::make_pair(id, data));
}
// Sort stamps by stamps->id
nodeStamps.insert(std::make_pair(iter->second.getStamp(), iter->first));
}
// Publish markers accordingly to current optimized graph
std::map<int, float> objectsAdded;
visualization_msgs::MarkerArray markers;
if(nodeToObjects_.size())
{
for(std::map<int, rtabmap::Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
{
if(nodeToObjects_.find(iter->first) != nodeToObjects_.end())
{
cv::Mat data = nodeToObjects_.at(iter->first);
for(int i=0; i<data.rows; ++i)
{
int objId = int(data.at<double>(i,0));
double stamp = data.at<double>(i,1);
// The object detection may have been taken between two nodes, interpolate its position.
std::map<double, int>::iterator previousNode = nodeStamps.lower_bound(stamp); // lower bound of the stamp
if(previousNode!=nodeStamps.end() && previousNode->first > stamp && previousNode != nodeStamps.begin())
{
--previousNode;
}
std::map<double, int>::iterator nextNode = nodeStamps.upper_bound(stamp); // upper bound of the stamp
if(previousNode != nodeStamps.end() &&
nextNode != nodeStamps.end() &&
previousNode->second != nextNode->second &&
poses.find(previousNode->second)!=poses.end() && poses.find(nextNode->second)!=poses.end())
{
rtabmap::Transform poseA = poses.at(previousNode->second);
rtabmap::Transform poseB = poses.at(nextNode->second);
double stampA = previousNode->first;
double stampB = nextNode->first;
UASSERT(stamp>=stampA && stamp <=stampB);
rtabmap::Transform v = poseA.inverse() * poseB;
double ratio = (stamp-stampA)/(stampB-stampA);
rtabmap::Transform robotPose = poseA.interpolate(ratio, poseB);
// transform object pose in map frame
rtabmap::Transform objPose(
data.at<double>(i,2), data.at<double>(i,3), data.at<double>(i,4),
data.at<double>(i,5), data.at<double>(i,6), data.at<double>(i,7), data.at<double>(i,8));
float distanceFromNode = objPose.getNorm();
objPose = robotPose * objPose;
if(objectsAdded.find(objId) == objectsAdded.end())
{
visualization_msgs::Marker marker;
marker.header.frame_id = msg->header.frame_id;
marker.header.stamp = msg->header.stamp;
marker.ns = "objects";
marker.id = objId;
marker.action = visualization_msgs::Marker::ADD;
marker.pose.position.x = objPose.x();
marker.pose.position.y = objPose.y();
marker.pose.position.z = objPose.z();
Eigen::Quaterniond q = objPose.getQuaterniond();
marker.pose.orientation.x = q.x();
marker.pose.orientation.y = q.y();
marker.pose.orientation.z = q.z();
marker.pose.orientation.w = q.w();
marker.scale.x = 0.3;
marker.scale.y = 0.3;
marker.scale.z = 0.3;
marker.color.a = 0.8;
marker.color.r = 0.0;
marker.color.g = 1.0;
marker.color.b = 0.0;
// cube
marker.type = visualization_msgs::Marker::CUBE;
markers.markers.push_back(marker);
// text
marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
marker.text = uFormat("%s_%d", objFramePrefix_.c_str(), objId);
marker.id = -objId;
marker.color.a = 1.0;
marker.pose.position.z += 0.3; // text over the cube
markers.markers.push_back(marker);
objectsAdded.insert(std::make_pair(objId, distanceFromNode));
}
else
{
// update pose of the marker only if current observation is closer to robot
if(distanceFromNode < objectsAdded.at(objId))
{
for(unsigned int j=0; j<markers.markers.size(); ++j)
{
if(markers.markers[j].id == objId || markers.markers[j].id == -objId)
{
markers.markers[j].pose.position.x = objPose.x();
markers.markers[j].pose.position.y = objPose.y();
markers.markers[j].pose.position.z = objPose.z() + (markers.markers[j].id<0?0.3:0);
Eigen::Quaterniond q = objPose.getQuaterniond();
markers.markers[j].pose.orientation.x = q.x();
markers.markers[j].pose.orientation.y = q.y();
markers.markers[j].pose.orientation.z = q.z();
markers.markers[j].pose.orientation.w = q.w();
}
}
objectsAdded.at(objId) = distanceFromNode;
}
}
}
}
}
}
if(!markers.markers.empty())
{
pubMarkers_.publish(markers);
}
}
}
private:
std::string objFramePrefix_;
ros::Subscriber subObjects_;
ros::Subscriber subsMapData_;
tf::TransformListener tfListener_;
ros::Publisher pub_;
ros::Publisher pubMarkers_;
std::map<int, cv::Mat> nodeToObjects_;
std::string frameId_;
};
int main(int argc, char * argv[])
{
ros::init(argc, argv, "save_objects_example");
SaveObjectsExample sync;
ros::spin();
}