Skip to content

Commit 108bd9d

Browse files
aselimcvniclaspassalis
authored
New Feature: Continual SLAM (opendr-eu#424)
* initial commit * feat(Continual-SLAM): Finished __getitem__ dataset iterator Currently, still work in progress. But I have finished the simple data iteration, which returns the OpenDR type Image, Distance and Speed * feat(Continual-SLAM): Wrote the ROS node for image, velocity and distance publisher Currently still work in progress. Wrote the ROS node which publishes the sequantial images from KITTI as well as it publishes the velocity and distances at that current moment respectively * feat(Continual-SLAM): Extended ROS node to hold past 3 data values * feat(Continual-SLAM): [WIP] Implementation of CL-SLAM expert inference * feat(Continual-SLAM): [WIP] Implementation of CL-SLAM expert inference cont. started implementation of inference * feat(Continual-SLAM): Reverted dataset publisher into original single mode The caching of the previous times and previous images will be done in the reciever node * feat(Continual-SLAM): [WIP] Implemented predict function for depth-pose networks * feat(Continual-SLAM): [WIP] Started implementation of Learner class together with ROS Node (just for prediction mode now) * feat(Continual-SLAM): [WIP] ROS node for CL-SLAM Predictor * feat(Continual-SLAM): Add reconstruct depth images from disparity * feat(Continual-SLAM): [WIP] Ros node and learner class * feat(Continual-SLAM): [WIP] ROS nodes are implemented, synch is missing * feat(Continual-SLAM): ROS Node and Learner Implementation for only Predictor is done * feat(Continual-SLAM): [WIP] Fit/Adapt function is implemented, ROS Node publisher coordinate change * fix(Continual-SLAM): Fix small predictor mode requirements * feat(Continual-SLAM): [WIP] Learner/Predictor + ROS Nodes imp. done, need to fix bugs * refactor(Continual-SLAM): Refactored some parts to increase readability * feat(Continual-SLAM): [WIP] Working on adapt function * feat(Continual-SLAM): [WIP] Fix asterisk imports and init files * feat(Continual-SLAM): [WIP] Small addition for debugging, this commit can be ignored later on * refactor(Continual-SLAM): [WIP] changing couple of things to debug, not an important commit * feat(Continual-SLAM): Fixed algorithm, maybe there is room to improve * feat(Continual-SLAM): [WIP] trying to improve dataset publisher and visualization * feat(Continual-SLAM): [WIP] Added multi-device support back * feat(Continual-SLAM): Initial commit to Replay Buffer * feat(Continual-SLAM): [WIP] Replay buffer cont. * feat(Continual-SLAM): [WIP] for Replay buffer implementation * feat(Continual-SLAM): [WIP] Finished replay buffer implementation for ROS nodes as well * refactor(Continual-SLAM): Better namings, improvement in code * refactor(Continual-SLAM): Improvement of code quality for predictor node * refactor(Continual-SLAM): Improve code quality of ROS nodes * refactor(Continual-SLAM): Code quality improvement in CL-SLAM module * feat(Continual-SLAM): [WIP] new implementation of learner * feat(Continual-SLAM): [WIP] Fixed algorithm, improve replay buffer * feat(Continual-SLAM): [WIP] Improved ROS nodes * feat(Continual-SLAM): [WIP] Writing ROS2 nodes * feat(Continual-SLAM): Add ROS2 nodes * feat(Continual-SLAM): Added ROS2 node, and started writing tests * refactor(Continual-SLAM): Update default buffer size and publish rate for learner node * feat(Continual-SLAM): Added Loop Closure Detection * feat(Continual-SLAM): Fix small issues on Loop Closure Detection * feat(Continual-SLAM): [WIP] Loop Closure Performance * feat(Continual-SLAM): [WIP] Loop Closure Detection prob continues * feat(Continual-SLAM): Fixed LoopClosure * refactor(Continual-SLAM): Refactor code fix style problems, add LC update to ROS1 nodes * refactor(Continual-SLAM): Enable fit and infer tests * fix(Continual-SLAM): Fix small comment issue * feat(Continual-SLAM): [WIP] Demo * refactor(Continual-SLAM): Fix styling and get rid of debug lines * feat(Continual-SLAM): Update demo, add README's * docs(Continual-SLAM): Added docs for ROS nodes * feat(Continual-SLAM): Done with unit tests and demo * fix(Continual-SLAM): Fix typo bug on kitti.py * Adapt readme * feat(Continual-SLAM): Add publish pointcloud * feat(Continual-SLAM): Add pointcloud publish for ROS2 node * feat(Continual-SLAM): Add position graph for demo * feat(Continual-SLAM): Add dependencies * docs(Continual-SLAM): Fix deleting previous section mistake * feat(Continual-SLAM): Fix pep8, fix confused dataset files * feat(Continual-SLAM): Fix pep8, add pointcloud screenshot * fix(Continual-SLAM): Fix undetected local pep8 mistakes * feat(Continual-SLAM): Add g2o into skipped dirs for cpp style check * fix(Continual-SLAM): Place the skip dir correctly * fix(Continual-SLAM): Fix clang format * test(Continual-SLAM): Remove Loop Closure test due to not having g2o on test server * feat(Continual-SLAM): Update dependencies * feat(Continual-SLAM): Add the automatic installation of fixed g2opy * Update torch versions * Fix pep8 --------- Co-authored-by: Niclas Vödisch <[email protected]> Co-authored-by: Niclas <[email protected]> Co-authored-by: Nikolaos Passalis <[email protected]>
1 parent 6cf2bbf commit 108bd9d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+5794
-13
lines changed

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@
55
path = src/opendr/perception/panoptic_segmentation/efficient_lps/algorithm/EfficientLPS
66
url = https://github.com/robot-learning-freiburg/EfficientLPS.git
77
branch = opendr
8+
[submodule "src/opendr/perception/continual_slam/algorithm/g2o/g2opy"]
9+
path = src/opendr/perception/continual_slam/algorithm/g2o/g2opy
10+
url = https://github.com/uoip/g2opy

projects/opendr_ws/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ Currently, apart from tools, opendr_ws contains the following ROS nodes (categor
9090
1. [RGBD Hand Gesture Recognition](src/opendr_perception/README.md#rgbd-hand-gesture-recognition-ros-node)
9191
## RGB + Audio input
9292
1. [Audiovisual Emotion Recognition](src/opendr_perception/README.md#audiovisual-emotion-recognition-ros-node)
93+
94+
## RGB + IMU input
95+
1. [Continual SLAM](src/opendr_perception//README.md#continual-slam-ros-nodes)
9396
## Audio input
9497
1. [Speech Command Recognition](src/opendr_perception/README.md#speech-command-recognition-ros-node)
9598
2. [Speech Transcription](src/opendr_perception/README.md#speech-transcription-ros-node)

projects/opendr_ws/src/opendr_bridge/src/opendr_bridge/bridge.py

+186-6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121

2222
import numpy as np
2323
import struct
24+
25+
import rospy
26+
from rospy.rostime import Time
2427
from cv_bridge import CvBridge
2528
from vision_msgs.msg import Detection2DArray, Detection2D, BoundingBox2D, ObjectHypothesisWithPose,\
2629
Detection3DArray, Detection3D, BoundingBox3D as BoundingBox3DMsg, ObjectHypothesis, Classification2D
@@ -29,11 +32,17 @@
2932
from std_msgs.msg import ColorRGBA, String, Header
3033
from sensor_msgs.msg import Image as ImageMsg, PointCloud as PointCloudMsg, PointCloud2 as PointCloud2Msg,\
3134
ChannelFloat32 as ChannelFloat32Msg, PointField as PointFieldMsg
32-
import rospy
33-
from geometry_msgs.msg import Point32 as Point32Msg, Quaternion as QuaternionMsg
35+
from geometry_msgs.msg import (
36+
Point32 as Point32Msg,
37+
Quaternion as QuaternionMsg,
38+
Vector3Stamped as Vector3StampedMsg,
39+
TransformStamped as TransformStampedMsg
40+
)
41+
from visualization_msgs.msg import Marker as MarkerMsg, MarkerArray as MarkerArrayMsg
3442
from sensor_msgs import point_cloud2 as pc2
3543
from hri_msgs.msg import LiveSpeech
3644
from opendr_bridge.msg import OpenDRPose2D, OpenDRPose2DKeypoint
45+
import tf.transformations as tr
3746

3847

3948
class ROSBridge:
@@ -61,18 +70,31 @@ def from_ros_image(self, message: ImageMsg, encoding: str='passthrough') -> Imag
6170
image = Image(np.asarray(cv_image, dtype=np.uint8))
6271
return image
6372

64-
def to_ros_image(self, image: Image, encoding: str='passthrough') -> ImageMsg:
73+
def to_ros_image(self,
74+
image: Image,
75+
encoding: str='passthrough',
76+
frame_id: str = None,
77+
time: Time = None) -> ImageMsg:
6578
"""
6679
Converts an OpenDR image into a ROS image message
6780
:param image: OpenDR image to be converted
6881
:type image: engine.data.Image
6982
:param encoding: encoding to be used for the conversion (inherited from CvBridge)
7083
:type encoding: str
84+
:param frame_id: frame id of the image
85+
:type frame_id: str
86+
:param time: time of the image
87+
:type time: rospy.rostime.Time
7188
:return: ROS image
7289
:rtype: sensor_msgs.msg.Image
7390
"""
7491
# Convert from the OpenDR standard (CHW/RGB) to OpenCV standard (HWC/BGR)
75-
message = self._cv_bridge.cv2_to_imgmsg(image.opencv(), encoding=encoding)
92+
header = Header()
93+
if frame_id is not None:
94+
header.frame_id = frame_id
95+
if time is not None:
96+
header.stamp = time
97+
message = self._cv_bridge.cv2_to_imgmsg(image.opencv(), encoding=encoding, header=header)
7698
return message
7799

78100
def to_ros_pose(self, pose: Pose):
@@ -641,7 +663,7 @@ def from_ros_point_cloud2(self, point_cloud: PointCloud2Msg):
641663

642664
return result
643665

644-
def to_ros_point_cloud2(self, point_cloud: PointCloud, channels: str = None):
666+
def to_ros_point_cloud2(self, point_cloud: PointCloud, channels: str = None, frame_id="base_link"):
645667

646668
"""
647669
Converts an OpenDR PointCloud message into a ROS PointCloud2
@@ -655,7 +677,7 @@ def to_ros_point_cloud2(self, point_cloud: PointCloud, channels: str = None):
655677

656678
header = Header()
657679
header.stamp = rospy.Time.now()
658-
header.frame_id = "base_link"
680+
header.frame_id = frame_id
659681

660682
channel_count = point_cloud.data.shape[-1] - 3
661683

@@ -760,6 +782,164 @@ def to_ros_boxes_3d(self, boxes_3d: BoundingBox3DList, classes):
760782
ros_boxes_3d.detections.append(box)
761783
return ros_boxes_3d
762784

785+
def to_ros_marker(self,
786+
frame_id: str,
787+
position: list,
788+
id: int,
789+
rgba: tuple = None) -> MarkerMsg:
790+
"""
791+
Creates ROS Marker message given positions x,y,z and frame_id.
792+
:param frame_id: The frame_id of the marker.
793+
:type frame_id: str
794+
:param position: The position of the marker.
795+
:type position: list
796+
:param id: The id of the marker.
797+
:type id: int
798+
:param rgba: The color of the marker.
799+
:type rgba: tuple
800+
:return: ROS Marker message.
801+
:rtype: visualization_msgs.msg.Marker
802+
"""
803+
marker = MarkerMsg()
804+
marker.header.frame_id = frame_id
805+
marker.header.stamp = rospy.Time.now()
806+
marker.type = marker.SPHERE
807+
marker.id = id
808+
marker.action = marker.ADD
809+
marker.pose.position.x = position[0]
810+
marker.pose.position.y = position[1]
811+
marker.pose.position.z = position[2]
812+
marker.pose.orientation.x = 0.0
813+
marker.pose.orientation.y = 0.0
814+
marker.pose.orientation.z = 0.0
815+
marker.pose.orientation.w = 1.0
816+
marker.scale.x = 1.0
817+
marker.scale.y = 1.0
818+
marker.scale.z = 1.0
819+
if rgba is not None:
820+
marker.color.a = rgba[3]
821+
marker.color.r = rgba[0] / 255.0
822+
marker.color.g = rgba[1] / 255.0
823+
marker.color.b = rgba[2] / 255.0
824+
else:
825+
marker.color.a = 1.0
826+
marker.color.r = 1.0
827+
marker.color.g = 0.0
828+
marker.color.b = 0.0
829+
return marker
830+
831+
def to_ros_marker_array(self,
832+
position_list: list,
833+
frame_id_list: list,
834+
rgba: tuple = None) -> MarkerArrayMsg:
835+
"""
836+
Creates ROS MarkerArray message given positions x,y,z and frame_id.
837+
:param position_list: The list of positions of the markers.
838+
:type position_list: list
839+
:param frame_id_list: The list of frame_ids of the markers.
840+
:type frame_id_list: list
841+
:param rgba: The color of the marker.
842+
:type rgba: tuple
843+
"""
844+
marker_array = MarkerArrayMsg()
845+
for i in range(len(position_list)):
846+
marker_array.markers.append(self.to_ros_marker(frame_id_list[i],
847+
position_list[i],
848+
i,
849+
rgba))
850+
return marker_array
851+
852+
def to_ros_vector3_stamped(self,
853+
x: float,
854+
y: float,
855+
z: float,
856+
frame_id: str,
857+
time: Time) -> Vector3StampedMsg:
858+
"""
859+
Creates a Vector3Stamped message given x,y,z coordinates and frame_id and time
860+
:param x: The x coordinate of the vector.
861+
:type x: float
862+
:param y: The y coordinate of the vector.
863+
:type y: float
864+
:param z: The z coordinate of the vector.
865+
:type z: float
866+
:param frame_id: The frame_id of the vector.
867+
:type frame_id: str
868+
:param time: The time of the vector.
869+
:type time: rospy.rostime.Time
870+
:return: ROS message with the vector.
871+
:rtype: geometry_msgs.msg.Vector3Stamped
872+
"""
873+
874+
message = Vector3StampedMsg()
875+
message.header.frame_id = frame_id
876+
message.header.stamp = time
877+
message.vector.x = x
878+
message.vector.y = y
879+
message.vector.z = z
880+
881+
return message
882+
883+
def from_ros_vector3_stamped(self, message: Vector3StampedMsg):
884+
"""
885+
Creates a Vector3Stamped message given x,y,z coordinates and frame_id and time
886+
:param message: The ROS message to be converted.
887+
:type message: geometry_msgs.msg.Vector3Stamped
888+
:return: The frame_id and the vector.
889+
:rtype: tuple
890+
"""
891+
892+
x = message.vector.x
893+
y = message.vector.y
894+
z = message.vector.z
895+
896+
frame_id = message.header.frame_id
897+
898+
return frame_id, [x, y, z]
899+
900+
def to_ros_string(self, data: str) -> String:
901+
"""
902+
Creates a String message given data.
903+
:param data: The data to be converted.
904+
:type data: str
905+
:return: ROS message with the data.
906+
:rtype: std_msgs.msg.String
907+
"""
908+
909+
message = String()
910+
message.data = data
911+
912+
return message
913+
914+
def from_ros_string(self, message: String):
915+
"""
916+
Creates a String message given data.
917+
:param message: The ROS message to be converted.
918+
:type message: std_msgs.msg.String
919+
:return: The data.
920+
:rtype: str
921+
"""
922+
923+
return message.data
924+
925+
def to_ros_transformstamped(self, stamp, frame_id, child_frame_id, odometry):
926+
"""
927+
Creates a TransformStamped message given frame_id, child_frame_id and odometry.
928+
"""
929+
t = TransformStampedMsg()
930+
t.header.stamp = stamp
931+
t.header.frame_id = frame_id
932+
t.child_frame_id = child_frame_id
933+
t.transform.translation.x = -odometry[0, 3]
934+
t.transform.translation.y = 0.0
935+
t.transform.translation.z = -odometry[2, 3]
936+
q = tr.quaternion_from_matrix(odometry)
937+
t.transform.rotation.x = q[0]
938+
t.transform.rotation.y = q[1]
939+
t.transform.rotation.z = q[2]
940+
t.transform.rotation.w = q[3]
941+
return t
942+
763943
def from_ros_transcription(self, ros_transcripton: LiveSpeech) -> VoskTranscription:
764944
"""
765945
Converts an LiveSpeech object to a VoskTranscription object.

projects/opendr_ws/src/opendr_perception/CMakeLists.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ catkin_install_python(PROGRAMS
3939
scripts/object_detection_2d_gem_node.py
4040
scripts/semantic_segmentation_bisenet_node.py
4141
scripts/binary_high_resolution_node.py
42-
scripts/object_tracking_2d_siamrpn_node.py
42+
scripts/continual_slam_dataset_node.py
43+
scripts/continual_slam_predictor_node.py
44+
scripts/continual_slam_learner_node.py
4345
scripts/facial_emotion_estimation_node.py
4446
scripts/continual_skeleton_based_action_recognition_node.py
4547
scripts/point_cloud_2_publisher_node.py

projects/opendr_ws/src/opendr_perception/README.md

+55
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,61 @@ whose documentation can be found [here](../../../../docs/reference/audiovisual-e
879879
For viewing the output, refer to the [notes above.](#notes)
880880
881881
----
882+
## RGB + IMU input
883+
884+
### Continual SLAM ROS Nodes
885+
A ROS node for performing depth+position output mapping based on visual + imu input. Continual SLAM involves the use of two distinct ROS nodes, one dedicated to performing inference and the other exclusively focused on training. Both of the nodes are based on the learner class defined in [ContinualSLAMLearner](../../../../src/opendr/perception/continual_slam/continual_slam_learner.py).
886+
887+
You can find the continual slam ROS node python scripts here [learner](./scripts/continual_slam_learner_node.py), [predictor](./scripts/continual_slam_predictor_node.py). You can further also find the RGB image + IMU publisher node [here](./scripts/continual_slam_dataset_node.py).
888+
889+
#### Instructions for basic usage:
890+
891+
1. Download the KITTI Visual Odometry datased as it is described [here](../../../../src/opendr/perception/continual_slam/datasets/README.md).
892+
893+
2. Decide on the frame rate FPS, then one can start the dataset publisher node using the following line:
894+
```shell
895+
rosrun opendr_perception continual_slam_dataset_node.py
896+
```
897+
898+
The following optional arguments are available:
899+
- `-h or --help`: show a help message and exit
900+
- `--dataset_path`: path to the dataset (default=`./kitti`)
901+
- `--config_file_path`: path to the config file for learner class (default=`src/opendr/perception/continual_slam/configs/singlegpu_kitti.yaml`)
902+
- `--output_image_topic OUTPUT_IMAGE_TOPIC`: topic to which we are publishing the RGB image (default=`/cl_slam/image`)
903+
- `--output_distance_topic OUTPUT_DISTANCE_TOPIC`: topic to publish distances (default=`/cl_slam/distance`)
904+
- `--dataset_fps FPS`: frame rate which the dataset will be published, (default=`3`)
905+
906+
3. Start the Predictor Node
907+
```shell
908+
rosrun opendr_perception continual_slam_predictor_node.py
909+
```
910+
The following optional arguments are available:
911+
- `-h or --help`: show a help message and exit
912+
- `-c or --config_path`: path to the config file for the learner class (default=`src/opendr/perception/continual_slam/configs/singlegpu_kitti.yaml`)
913+
- `-it or --input_image_topic`: input image topic, listened from Continual SLAM Dataset Node (default=`/cl_slam/image`)
914+
- `-dt or --input_distance_topic`: input distance topic, listened from Continual SLAM Dataset Node (default=`/cl_slam/distance`)
915+
- `-odt or --output_depth_topic`: output depth topic, published to visual output tools (default=`/opendr/predicted/image`)
916+
- `-opt or --output_pose_topic`: output pose topic, published to visual output tools (default=`/opendr/predicted/pose`)
917+
- `-ppcl or --publish_pointcloud`: boolean to decide whether pointcloud output is asked or not (default=`false`)
918+
- `-opct or --output_pointcloud_topic`: output pointcloud topic, depending on `--publish_pointcloud`, published to visual output tools (default=`/opendr/predicted/pointcloud`)
919+
- `-ut or --update_topic`: update topic, listened from Continual SLAM Dataset Node (default=`/cl_slam/update`)
920+
921+
4. Start the Learner Node (Optional)
922+
```shell
923+
rosrun opendr_perception continual_slam_learner_node.py
924+
```
925+
The following optional arguments are available:
926+
- `-h or --help`: show a help message and exit
927+
- `-c or --config_path`: path to the config file for the learner class (default=`src/opendr/perception/continual_slam/configs/singlegpu_kitti.yaml`)
928+
- `-it or --input_image_topic`: input image topic, listened from Continual SLAM Dataset Node (default=`/cl_slam/image`)
929+
- `-dt or --input_distance_topic`: input distance topic, listened from Continual SLAM Dataset Node (default=`/cl_slam/distance`)
930+
- `-ot or --output_weights_topic`: output weights topic to be published to Continual SLAM Predictor Node (default=`/cl_slam/update`)
931+
- `-pr or --publish_rate`: publish rate of the weights (default=`20`)
932+
- `-bs or --buffer_size`: size of the replay buffer (default=`10`)
933+
- `-ss or --sample_size`: sample size of the replay buffer. If 0 is given, only online data is used (default=`3`)
934+
- `-sm or --save_memory`: whether to save memory or not. Add it to the command if you want to write to disk (default=`True`)
935+
----
936+
882937
## Audio input
883938
884939
### Speech Command Recognition ROS Node

0 commit comments

Comments
 (0)