diff --git a/CMakeLists.txt b/CMakeLists.txt
index 353e88399270ea098b65a857ecece7f34dca8d0e..ee63a29ada1ffdf8f0319cd32f88157578942eea 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -31,72 +31,15 @@ INCLUDE(cmake/ros.cmake)
 COMPUTE_PROJECT_ARGS(PROJECT_ARGS LANGUAGES CXX)
 PROJECT(${PROJECT_NAME} ${PROJECT_ARGS})
 
-# Project dependencies
-SET(CATKIN_REQUIRED_COMPONENTS roscpp std_msgs message_generation std_srvs geometry_msgs sensor_msgs tf2_ros
-    realtime_tools)
-ADD_PROJECT_DEPENDENCY(Boost REQUIRED COMPONENTS program_options)
-ADD_PROJECT_DEPENDENCY(dynamic_graph_bridge_msgs 0.3.0 REQUIRED)
-
-IF(BUILD_PYTHON_INTERFACE)
-  FINDPYTHON()
-  SEARCH_FOR_BOOST_PYTHON()
-  STRING(REGEX REPLACE "-" "_" PY_NAME ${PROJECT_NAME})
-  ADD_PROJECT_DEPENDENCY(dynamic-graph-python 4.0.0 REQUIRED)
-  SET(CATKIN_REQUIRED_COMPONENTS ${CATKIN_REQUIRED_COMPONENTS} rospy)
-
-  IF(Boost_VERSION GREATER 107299 OR Boost_VERSION_MACRO GREATER 107299)
-    # Silence a warning about a deprecated use of boost bind by boost >= 1.73
-    # without dropping support for boost < 1.73
-    ADD_DEFINITIONS(-DBOOST_BIND_GLOBAL_PLACEHOLDERS)
-  ENDIF()
-ENDIF(BUILD_PYTHON_INTERFACE)
-
-find_package(catkin REQUIRED COMPONENTS ${CATKIN_REQUIRED_COMPONENTS})
-
-ADD_PROJECT_DEPENDENCY(sot-core REQUIRED)
-
-# Main Library
-set(${PROJECT_NAME}_HEADERS
-  include/${PROJECT_NAME}/fwd.hh
-  include/${PROJECT_NAME}/ros_init.hh
-  include/${PROJECT_NAME}/sot_loader.hh
-  include/${PROJECT_NAME}/sot_loader_basic.hh
-  include/${PROJECT_NAME}/ros_interpreter.hh
-  src/converter.hh
-  src/sot_to_ros.hh
-  )
-
-SET(${PROJECT_NAME}_SOURCES
-  src/ros_init.cpp
-  src/sot_to_ros.cpp
-  src/ros_parameter.cpp
-  )
-
-ADD_LIBRARY(ros_bridge SHARED
-  ${${PROJECT_NAME}_SOURCES} ${${PROJECT_NAME}_HEADERS})
-TARGET_INCLUDE_DIRECTORIES(ros_bridge SYSTEM PUBLIC ${catkin_INCLUDE_DIRS})
-TARGET_INCLUDE_DIRECTORIES(ros_bridge PUBLIC $<INSTALL_INTERFACE:include>)
-TARGET_LINK_LIBRARIES(ros_bridge ${catkin_LIBRARIES}
-  sot-core::sot-core pinocchio::pinocchio)
-
-IF(SUFFIX_SO_VERSION)
-  SET_TARGET_PROPERTIES(ros_bridge PROPERTIES SOVERSION ${PROJECT_VERSION})
-ENDIF(SUFFIX_SO_VERSION)
-
-IF(NOT INSTALL_PYTHON_INTERFACE_ONLY)
-  INSTALL(TARGETS ros_bridge EXPORT ${TARGETS_EXPORT_NAME} DESTINATION lib)
-ENDIF(NOT INSTALL_PYTHON_INTERFACE_ONLY)
-
-add_subdirectory(src)
-add_subdirectory(tests)
-
-#install ros executables
-install(PROGRAMS
-  scripts/robot_pose_publisher
-  scripts/run_command
-  scripts/tf_publisher
-  DESTINATION share/${PROJECT_NAME}
-  )
+if(DEFINED ENV{ROS_VERSION} )
+  if ($ENV{ROS_VERSION} EQUAL 2) # if ROS2
+    add_subdirectory(ros2)
+  else()
+    add_subdirectory(ros1)
+  endif()
+else()
+  message(FATAL_ERROR "No ROS version found.")
+endif()
 
 # Install package information
-install(FILES manifest.xml package.xml DESTINATION share/${PROJECT_NAME})
+install(FILES manifest.xml package.xml DESTINATION share/${PROJECT_NAME})
\ No newline at end of file
diff --git a/package.xml b/package.xml
index 7ad0d4d1ee47ea66f94d94bf2ce99810928a1b40..e0d5432ab52990daa70ca3ed78135a8bbc4b6cbb 100644
--- a/package.xml
+++ b/package.xml
@@ -1,10 +1,8 @@
-<package format="2">
+<package format="3">
   <name>dynamic_graph_bridge</name>
   <version>3.4.1</version>
   <description>
-
      ROS bindings for dynamic graph.
-
   </description>
   <maintainer email="guilhem.saurel@laas.fr">guilhem.saurel@laas.fr</maintainer>
   <author email="hpp@laas.fr">hpp@laas.fr</author>
@@ -12,40 +10,58 @@
   <license>LGPL</license>
   <url>http://ros.org/wiki/dynamic_graph_bridge</url>
 
-  <export>
-    <rosdoc config="rosdoc.yaml" />
-  </export>
+  <!-- ROS1 dependencies -->
+  <buildtool_depend condition="$ROS_VERSION == 1">catkin</buildtool_depend>
 
-  <buildtool_depend>catkin</buildtool_depend>
+  <build_depend condition="$ROS_VERSION == 1">std_msgs</build_depend>
+  <build_depend condition="$ROS_VERSION == 1">std_srvs</build_depend>
+  <build_depend condition="$ROS_VERSION == 1">roscpp</build_depend>
+  <build_depend condition="$ROS_VERSION == 1">geometry_msgs</build_depend>
+  <build_depend condition="$ROS_VERSION == 1">sensor_msgs</build_depend>
+  <build_depend condition="$ROS_VERSION == 1">tf2_ros</build_depend>
+  <build_depend condition="$ROS_VERSION == 1">realtime_tools</build_depend>
+  <build_depend condition="$ROS_VERSION == 1">message_generation</build_depend>
+  <build_depend condition="$ROS_VERSION == 1">message_runtime</build_depend>
+  <build_depend condition="$ROS_VERSION == 1">dynamic-graph</build_depend>
+  <build_depend condition="$ROS_VERSION == 1">dynamic-graph-python</build_depend>
+  <build_depend condition="$ROS_VERSION == 1">sot-core</build_depend>
+  <build_depend condition="$ROS_VERSION == 1">sot-dynamic-pinocchio</build_depend>
+  <build_depend condition="$ROS_VERSION == 1">dynamic_graph_bridge_msgs</build_depend>
 
-  <build_depend>std_msgs</build_depend>
-  <build_depend>std_srvs</build_depend>
-  <build_depend>roscpp</build_depend>
-  <build_depend>geometry_msgs</build_depend>
-  <build_depend>sensor_msgs</build_depend>
-  <build_depend>tf2_ros</build_depend>
-  <build_depend>realtime_tools</build_depend>
-  <build_depend>message_generation</build_depend>
-  <build_depend>message_runtime</build_depend>
-  <build_depend>dynamic-graph</build_depend>
-  <build_depend>dynamic-graph-python</build_depend>
-  <build_depend>sot-core</build_depend>
-  <build_depend>sot-dynamic-pinocchio</build_depend>
-  <build_depend>dynamic_graph_bridge_msgs</build_depend>
+  <exec_depend condition="$ROS_VERSION == 1">std_msgs</exec_depend>
+  <exec_depend condition="$ROS_VERSION == 1">std_srvs</exec_depend>
+  <exec_depend condition="$ROS_VERSION == 1">roscpp</exec_depend>
+  <exec_depend condition="$ROS_VERSION == 1">geometry_msgs</exec_depend>
+  <exec_depend condition="$ROS_VERSION == 1">sensor_msgs</exec_depend>
+  <exec_depend condition="$ROS_VERSION == 1">tf2_ros</exec_depend>
+  <exec_depend condition="$ROS_VERSION == 1">realtime_tools</exec_depend>
+  <exec_depend condition="$ROS_VERSION == 1">message_generation</exec_depend>
+  <exec_depend condition="$ROS_VERSION == 1">message_runtime</exec_depend>
+  <exec_depend condition="$ROS_VERSION == 1">dynamic-graph</exec_depend>
+  <exec_depend condition="$ROS_VERSION == 1">dynamic-graph-python</exec_depend>
+  <exec_depend condition="$ROS_VERSION == 1">sot-core</exec_depend>
+  <exec_depend condition="$ROS_VERSION == 1">sot-dynamic-pinocchio</exec_depend>
+  <exec_depend condition="$ROS_VERSION == 1">dynamic_graph_bridge_msgs</exec_depend>
 
-  <exec_depend>std_msgs</exec_depend>
-  <exec_depend>std_srvs</exec_depend>
-  <exec_depend>roscpp</exec_depend>
-  <exec_depend>geometry_msgs</exec_depend>
-  <exec_depend>sensor_msgs</exec_depend>
-  <exec_depend>tf2_ros</exec_depend>
-  <exec_depend>realtime_tools</exec_depend>
-  <exec_depend>message_generation</exec_depend>
-  <exec_depend>message_runtime</exec_depend>
-  <exec_depend>dynamic-graph</exec_depend>
-  <exec_depend>dynamic-graph-python</exec_depend>
-  <exec_depend>sot-core</exec_depend>
-  <exec_depend>sot-dynamic-pinocchio</exec_depend>
-  <exec_depend>dynamic_graph_bridge_msgs</exec_depend>
+  <!-- ROS2 dependencies -->
+  <buildtool_depend condition="$ROS_VERSION == 2">ament_cmake</buildtool_depend>
+  <buildtool_depend condition="$ROS_VERSION == 2">ament_index_cpp</buildtool_depend>
+  <depend  condition="$ROS_VERSION == 2"> rclcpp </depend>
+  <exec_depend  condition="$ROS_VERSION == 2"> rclpy </exec_depend>
+  <depend  condition="$ROS_VERSION == 2"> rcutils </depend>
+  <depend  condition="$ROS_VERSION == 2"> std_msgs </depend>
+  <depend  condition="$ROS_VERSION == 2"> std_srvs </depend>
+  <depend  condition="$ROS_VERSION == 2"> geometry_msgs </depend>
+  <depend  condition="$ROS_VERSION == 2"> sensor_msgs </depend>
+  <depend  condition="$ROS_VERSION == 2"> tf2_ros </depend>
+  <depend  condition="$ROS_VERSION == 2"> boost </depend>
+  <depend  condition="$ROS_VERSION == 2"> dynamic_graph_bridge_msgs </depend>
+  <depend  condition="$ROS_VERSION == 2"> sot-core </depend>
+
+  <export>
+    <rosdoc config="rosdoc.yaml" />
+    <build_type condition="$ROS_VERSION == 2">ament_cmake</build_type>
+  </export>
 
+  <test_depend condition="$ROS_VERSION == 2">rclpy</test_depend>
 </package>
diff --git a/ros1/CMakeLists.txt b/ros1/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..87041c6d1e2fe22aad88441fdac53c7c60d768c3
--- /dev/null
+++ b/ros1/CMakeLists.txt
@@ -0,0 +1,76 @@
+# Copyright (C) 2008-2020 LAAS-CNRS, JRL AIST-CNRS.
+#
+# Author: Florent Lamiraux, Nirmal Giftsun, Guilhem Saurel, Maxmilien Naveau
+#
+
+# Project dependencies
+SET(CATKIN_REQUIRED_COMPONENTS roscpp std_msgs message_generation std_srvs geometry_msgs sensor_msgs tf2_ros
+    realtime_tools)
+ADD_PROJECT_DEPENDENCY(Boost REQUIRED COMPONENTS program_options)
+ADD_PROJECT_DEPENDENCY(dynamic_graph_bridge_msgs 0.3.0 REQUIRED)
+
+IF(BUILD_PYTHON_INTERFACE)
+  FINDPYTHON()
+  SEARCH_FOR_BOOST_PYTHON()
+  STRING(REGEX REPLACE "-" "_" PY_NAME ${PROJECT_NAME})
+  ADD_PROJECT_DEPENDENCY(dynamic-graph-python 4.0.0 REQUIRED)
+  SET(CATKIN_REQUIRED_COMPONENTS ${CATKIN_REQUIRED_COMPONENTS} rospy)
+
+  IF(Boost_VERSION GREATER 107299 OR Boost_VERSION_MACRO GREATER 107299)
+    # Silence a warning about a deprecated use of boost bind by boost >= 1.73
+    # without dropping support for boost < 1.73
+    ADD_DEFINITIONS(-DBOOST_BIND_GLOBAL_PLACEHOLDERS)
+  ENDIF()
+ENDIF(BUILD_PYTHON_INTERFACE)
+
+find_package(catkin REQUIRED COMPONENTS ${CATKIN_REQUIRED_COMPONENTS})
+
+ADD_PROJECT_DEPENDENCY(sot-core REQUIRED)
+
+# Main Library
+set(${PROJECT_NAME}_HEADERS
+  include/${PROJECT_NAME}/fwd.hh
+  include/${PROJECT_NAME}/ros_init.hh
+  include/${PROJECT_NAME}/sot_loader.hh
+  include/${PROJECT_NAME}/sot_loader_basic.hh
+  include/${PROJECT_NAME}/ros_interpreter.hh
+  src/converter.hh
+  src/sot_to_ros.hh
+  )
+
+SET(${PROJECT_NAME}_SOURCES
+  src/ros_init.cpp
+  src/sot_to_ros.cpp
+  src/ros_parameter.cpp
+  )
+
+ADD_LIBRARY(ros_bridge SHARED
+  ${${PROJECT_NAME}_SOURCES} ${${PROJECT_NAME}_HEADERS})
+TARGET_INCLUDE_DIRECTORIES(ros_bridge SYSTEM PUBLIC ${catkin_INCLUDE_DIRS})
+TARGET_INCLUDE_DIRECTORIES(ros_bridge PUBLIC $<INSTALL_INTERFACE:include>
+                                      PRIVATE ${PROJECT_SOURCE_DIR}/ros1/include)
+TARGET_LINK_LIBRARIES(ros_bridge
+  ${catkin_LIBRARIES}
+  sot-core::sot-core
+  pinocchio::pinocchio
+  dynamic_graph_bridge_msgs::dynamic_graph_bridge_msgs
+)
+IF(SUFFIX_SO_VERSION)
+  SET_TARGET_PROPERTIES(ros_bridge PROPERTIES SOVERSION ${PROJECT_VERSION})
+ENDIF(SUFFIX_SO_VERSION)
+
+IF(NOT INSTALL_PYTHON_INTERFACE_ONLY)
+  INSTALL(TARGETS ros_bridge EXPORT ${TARGETS_EXPORT_NAME} DESTINATION lib)
+ENDIF(NOT INSTALL_PYTHON_INTERFACE_ONLY)
+
+add_subdirectory(src)
+add_subdirectory(tests)
+
+#install ros executables
+install(PROGRAMS
+  scripts/robot_pose_publisher
+  scripts/run_command
+  scripts/tf_publisher
+  DESTINATION share/${PROJECT_NAME}
+  )
+
diff --git a/include/dynamic_graph_bridge/fwd.hh b/ros1/include/dynamic_graph_bridge/fwd.hh
similarity index 100%
rename from include/dynamic_graph_bridge/fwd.hh
rename to ros1/include/dynamic_graph_bridge/fwd.hh
diff --git a/include/dynamic_graph_bridge/ros_init.hh b/ros1/include/dynamic_graph_bridge/ros_init.hh
similarity index 100%
rename from include/dynamic_graph_bridge/ros_init.hh
rename to ros1/include/dynamic_graph_bridge/ros_init.hh
diff --git a/include/dynamic_graph_bridge/ros_interpreter.hh b/ros1/include/dynamic_graph_bridge/ros_interpreter.hh
similarity index 100%
rename from include/dynamic_graph_bridge/ros_interpreter.hh
rename to ros1/include/dynamic_graph_bridge/ros_interpreter.hh
diff --git a/include/dynamic_graph_bridge/ros_parameter.hh b/ros1/include/dynamic_graph_bridge/ros_parameter.hh
similarity index 100%
rename from include/dynamic_graph_bridge/ros_parameter.hh
rename to ros1/include/dynamic_graph_bridge/ros_parameter.hh
diff --git a/include/dynamic_graph_bridge/sot_loader.hh b/ros1/include/dynamic_graph_bridge/sot_loader.hh
similarity index 100%
rename from include/dynamic_graph_bridge/sot_loader.hh
rename to ros1/include/dynamic_graph_bridge/sot_loader.hh
diff --git a/include/dynamic_graph_bridge/sot_loader_basic.hh b/ros1/include/dynamic_graph_bridge/sot_loader_basic.hh
similarity index 100%
rename from include/dynamic_graph_bridge/sot_loader_basic.hh
rename to ros1/include/dynamic_graph_bridge/sot_loader_basic.hh
diff --git a/scripts/robot_pose_publisher b/ros1/scripts/robot_pose_publisher
similarity index 100%
rename from scripts/robot_pose_publisher
rename to ros1/scripts/robot_pose_publisher
diff --git a/scripts/run_command b/ros1/scripts/run_command
similarity index 100%
rename from scripts/run_command
rename to ros1/scripts/run_command
diff --git a/scripts/tf_publisher b/ros1/scripts/tf_publisher
similarity index 100%
rename from scripts/tf_publisher
rename to ros1/scripts/tf_publisher
diff --git a/ros1/src/CMakeLists.txt b/ros1/src/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e58c99d6d8936f107d5fc6c6cd70ed0a8c890dd1
--- /dev/null
+++ b/ros1/src/CMakeLists.txt
@@ -0,0 +1,198 @@
+#.rst:
+# .. command:: CUSTOM_DYNAMIC_GRAPH_PYTHON_MODULE ( SUBMODULENAME LIBRARYNAME TARGETNAME INSTALL_INIT_PY=1 SOURCE_PYTHON_MODULE=cmake/dynamic_graph/python-module-py.cc)
+#
+#   Add a python submodule to dynamic_graph
+#
+#   :param SUBMODULENAME: the name of the submodule (can be foo/bar),
+#
+#   :param LIBRARYNAME:   library to link the submodule with.
+#
+#   :param TARGETNAME:     name of the target: should be different for several
+#                   calls to the macro.
+#
+#   :param INSTALL_INIT_PY: if set to 1 install and generated a __init__.py file.
+#                   Set to 1 by default.
+#
+#   :param SOURCE_PYTHON_MODULE: Location of the cpp file for the python module in the package.
+#                   Set to cmake/dynamic_graph/python-module-py.cc by default.
+#
+#  .. note::
+#    Before calling this macro, set variable NEW_ENTITY_CLASS as
+#    the list of new Entity types that you want to be bound.
+#    Entity class name should match the name referencing the type
+#    in the factory.
+#
+MACRO(CUSTOM_DYNAMIC_GRAPH_PYTHON_MODULE SUBMODULENAME LIBRARYNAME TARGETNAME)
+
+  set(options DONT_INSTALL_INIT_PY)
+  set(oneValueArgs SOURCE_PYTHON_MODULE MODULE_HEADER)
+  cmake_parse_arguments(ARG "${options}" "${oneValueArgs}"
+                        "${multiValueArgs}" ${ARGN} )
+
+  # By default the __init__.py file is installed.
+  if(NOT DEFINED ARG_SOURCE_PYTHON_MODULE)
+    set(DYNAMICGRAPH_MODULE_HEADER ${ARG_MODULE_HEADER})
+    configure_file(
+      ${PROJECT_JRL_CMAKE_MODULE_DIR}/dynamic_graph/python-module-py.cc.in
+      ${PROJECT_BINARY_DIR}/ros1/src/dynamic_graph/${SUBMODULENAME}/python-module-py.cc
+      @ONLY
+      )
+    SET(ARG_SOURCE_PYTHON_MODULE "${PROJECT_BINARY_DIR}/ros1/src/dynamic_graph/${SUBMODULENAME}/python-module-py.cc")
+  endif()
+
+  IF(NOT DEFINED PYTHONLIBS_FOUND)
+    FINDPYTHON()
+  ELSEIF(NOT ${PYTHONLIBS_FOUND} STREQUAL "TRUE")
+    MESSAGE(FATAL_ERROR "Python has not been found.")
+  ENDIF()
+  if(NOT DEFINED Boost_PYTHON_LIBRARIES)
+    MESSAGE(FATAL_ERROR "Boost Python library must have been found to call this macro.")
+  endif()
+
+  SET(PYTHON_MODULE ${TARGETNAME})
+
+  ADD_LIBRARY(${PYTHON_MODULE}
+    MODULE
+    ${ARG_SOURCE_PYTHON_MODULE})
+
+  FILE(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/ros1/src/dynamic_graph/${SUBMODULENAME})
+
+  SET(PYTHON_INSTALL_DIR "${PYTHON_SITELIB}/dynamic_graph/${SUBMODULENAME}")
+  STRING(REGEX REPLACE "[^/]+" ".." PYTHON_INSTALL_DIR_REVERSE ${PYTHON_INSTALL_DIR})
+
+  SET_TARGET_PROPERTIES(${PYTHON_MODULE}
+    PROPERTIES PREFIX ""
+    OUTPUT_NAME dynamic_graph/${SUBMODULENAME}/wrap
+    BUILD_RPATH "${DYNAMIC_GRAPH_PLUGINDIR}:\$ORIGIN/${PYTHON_INSTALL_DIR_REVERSE}/${DYNAMIC_GRAPH_PLUGINDIR}"
+   )
+
+  IF (UNIX AND NOT APPLE)
+    TARGET_LINK_LIBRARIES(${PYTHON_MODULE} ${PUBLIC_KEYWORD} "-Wl,--no-as-needed")
+  ENDIF(UNIX AND NOT APPLE)
+  TARGET_LINK_LIBRARIES(${PYTHON_MODULE} ${PUBLIC_KEYWORD} ${LIBRARYNAME} ${PYTHON_LIBRARY} dynamic-graph::dynamic-graph)
+  TARGET_LINK_BOOST_PYTHON(${PYTHON_MODULE} ${PUBLIC_KEYWORD})
+  if(PROJECT_NAME STREQUAL "dynamic-graph-python")
+    TARGET_LINK_LIBRARIES(${PYTHON_MODULE} ${PUBLIC_KEYWORD} dynamic-graph-python)
+  else()
+    TARGET_LINK_LIBRARIES(${PYTHON_MODULE} ${PUBLIC_KEYWORD} dynamic-graph-python::dynamic-graph-python)
+  endif()
+
+  TARGET_INCLUDE_DIRECTORIES(${PYTHON_MODULE} SYSTEM PRIVATE ${PYTHON_INCLUDE_DIRS})
+
+  #
+  # Installation
+  #
+
+  INSTALL(TARGETS ${PYTHON_MODULE}
+    DESTINATION
+    ${PYTHON_INSTALL_DIR})
+
+  SET(ENTITY_CLASS_LIST "")
+  FOREACH (ENTITY ${NEW_ENTITY_CLASS})
+    SET(ENTITY_CLASS_LIST "${ENTITY_CLASS_LIST}${ENTITY}('')\n")
+  ENDFOREACH(ENTITY ${NEW_ENTITY_CLASS})
+
+  # Install if not DONT_INSTALL_INIT_PY
+  if(NOT DONT_INSTALL_INIT_PY)
+
+    CONFIGURE_FILE(
+      ${PROJECT_JRL_CMAKE_MODULE_DIR}/dynamic_graph/submodule/__init__.py.cmake
+      ${PROJECT_BINARY_DIR}/ros1/src/dynamic_graph/${SUBMODULENAME}/__init__.py
+      )
+
+    INSTALL(
+      FILES ${PROJECT_BINARY_DIR}/ros1/src/dynamic_graph/${SUBMODULENAME}/__init__.py
+      DESTINATION ${PYTHON_INSTALL_DIR}
+      )
+
+  endif()
+
+ENDMACRO(CUSTOM_DYNAMIC_GRAPH_PYTHON_MODULE SUBMODULENAME)
+
+
+
+
+
+
+
+
+SET(plugins
+  ros_publish
+  ros_subscribe
+  ros_queued_subscribe
+  ros_tf_listener
+  ros_time
+  )
+
+FOREACH(plugin ${plugins})
+  GET_FILENAME_COMPONENT(LIBRARY_NAME ${plugin} NAME)
+  ADD_LIBRARY(${LIBRARY_NAME} SHARED ${plugin}.cpp ${plugin}.hh)
+
+  IF(SUFFIX_SO_VERSION)
+    SET_TARGET_PROPERTIES(${LIBRARY_NAME} PROPERTIES SOVERSION ${PROJECT_VERSION})
+  ENDIF(SUFFIX_SO_VERSION)
+
+  TARGET_LINK_LIBRARIES(${LIBRARY_NAME} ${${LIBRARY_NAME}_deps} ${catkin_LIBRARIES} ros_bridge
+    dynamic_graph_bridge_msgs::dynamic_graph_bridge_msgs)
+  
+  TARGET_INCLUDE_DIRECTORIES(${LIBRARY_NAME} PUBLIC $<INSTALL_INTERFACE:include>
+    PRIVATE ${PROJECT_SOURCE_DIR}/ros1/include)
+
+  IF(NOT INSTALL_PYTHON_INTERFACE_ONLY)
+    INSTALL(TARGETS ${LIBRARY_NAME} EXPORT ${TARGETS_EXPORT_NAME}
+      DESTINATION ${DYNAMIC_GRAPH_PLUGINDIR})
+  ENDIF(NOT INSTALL_PYTHON_INTERFACE_ONLY)
+
+  IF(BUILD_PYTHON_INTERFACE)
+    STRING(REPLACE - _ PYTHON_LIBRARY_NAME ${LIBRARY_NAME})
+    if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${plugin}-python-module-py.cc")
+      CUSTOM_DYNAMIC_GRAPH_PYTHON_MODULE("ros/${PYTHON_LIBRARY_NAME}"
+        ${LIBRARY_NAME} ${PROJECT_NAME}-${PYTHON_LIBRARY_NAME}-wrap
+        SOURCE_PYTHON_MODULE "${CMAKE_CURRENT_SOURCE_DIR}/${plugin}-python-module-py.cc")
+    elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${plugin}-python.hh")
+      CUSTOM_DYNAMIC_GRAPH_PYTHON_MODULE("ros/${PYTHON_LIBRARY_NAME}"
+        ${LIBRARY_NAME} ${PROJECT_NAME}-${PYTHON_LIBRARY_NAME}-wrap
+        MODULE_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/${plugin}-python.hh")
+    endif()
+    TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME}-${PYTHON_LIBRARY_NAME}-wrap
+      PRIVATE ${PROJECT_SOURCE_DIR}/ros1/include)
+  ENDIF(BUILD_PYTHON_INTERFACE)
+ENDFOREACH(plugin)
+
+target_link_libraries(ros_publish ros_bridge)
+
+IF(BUILD_PYTHON_INTERFACE)
+  PYTHON_INSTALL_ON_SITE("dynamic_graph/ros" "__init__.py")
+  PYTHON_INSTALL_ON_SITE("dynamic_graph/ros" "ros.py")
+  PYTHON_INSTALL_ON_SITE("dynamic_graph/ros" "dgcompleter.py")
+
+  # ros_interperter library.
+  add_library(ros_interpreter ros_interpreter.cpp)
+  TARGET_LINK_LIBRARIES(ros_interpreter ros_bridge ${catkin_LIBRARIES}
+    dynamic-graph-python::dynamic-graph-python
+    dynamic_graph_bridge_msgs::dynamic_graph_bridge_msgs)
+  TARGET_INCLUDE_DIRECTORIES(ros_interpreter PUBLIC $<INSTALL_INTERFACE:include>
+    PRIVATE ${PROJECT_SOURCE_DIR}/ros1/include)
+
+
+  install(TARGETS ros_interpreter
+    EXPORT ${TARGETS_EXPORT_NAME}
+    DESTINATION lib)
+ENDIF(BUILD_PYTHON_INTERFACE)
+
+# Stand alone embedded intepreter with a robot controller.
+add_executable(geometric_simu geometric_simu.cpp sot_loader.cpp sot_loader_basic.cpp)
+TARGET_INCLUDE_DIRECTORIES(geometric_simu PUBLIC $<INSTALL_INTERFACE:include>
+    PRIVATE ${PROJECT_SOURCE_DIR}/ros1/include)
+target_link_libraries(geometric_simu Boost::program_options ${CMAKE_DL_LIBS} ${catkin_LIBRARIES} ros_bridge
+  dynamic_graph_bridge_msgs::dynamic_graph_bridge_msgs)
+install(TARGETS geometric_simu
+  DESTINATION lib/${PROJECT_NAME})
+
+# Sot loader library
+add_library(sot_loader sot_loader.cpp sot_loader_basic.cpp)
+TARGET_INCLUDE_DIRECTORIES(sot_loader PUBLIC $<INSTALL_INTERFACE:include>
+    PRIVATE ${PROJECT_SOURCE_DIR}/ros1/include)
+target_link_libraries(sot_loader Boost::program_options ${catkin_LIBRARIES} ros_bridge
+  dynamic_graph_bridge_msgs::dynamic_graph_bridge_msgs)
+install(TARGETS sot_loader EXPORT ${TARGETS_EXPORT_NAME} DESTINATION lib)
diff --git a/src/converter.hh b/ros1/src/converter.hh
similarity index 100%
rename from src/converter.hh
rename to ros1/src/converter.hh
diff --git a/src/dynamic_graph/ros/__init__.py b/ros1/src/dynamic_graph/ros/__init__.py
similarity index 100%
rename from src/dynamic_graph/ros/__init__.py
rename to ros1/src/dynamic_graph/ros/__init__.py
diff --git a/src/dynamic_graph/ros/dgcompleter.py b/ros1/src/dynamic_graph/ros/dgcompleter.py
similarity index 100%
rename from src/dynamic_graph/ros/dgcompleter.py
rename to ros1/src/dynamic_graph/ros/dgcompleter.py
diff --git a/src/dynamic_graph/ros/ros.py b/ros1/src/dynamic_graph/ros/ros.py
similarity index 100%
rename from src/dynamic_graph/ros/ros.py
rename to ros1/src/dynamic_graph/ros/ros.py
diff --git a/src/geometric_simu.cpp b/ros1/src/geometric_simu.cpp
similarity index 100%
rename from src/geometric_simu.cpp
rename to ros1/src/geometric_simu.cpp
diff --git a/src/ros_init.cpp b/ros1/src/ros_init.cpp
similarity index 100%
rename from src/ros_init.cpp
rename to ros1/src/ros_init.cpp
diff --git a/src/ros_interpreter.cpp b/ros1/src/ros_interpreter.cpp
similarity index 100%
rename from src/ros_interpreter.cpp
rename to ros1/src/ros_interpreter.cpp
diff --git a/src/ros_parameter.cpp b/ros1/src/ros_parameter.cpp
similarity index 100%
rename from src/ros_parameter.cpp
rename to ros1/src/ros_parameter.cpp
diff --git a/src/ros_publish-python-module-py.cc b/ros1/src/ros_publish-python-module-py.cc
similarity index 100%
rename from src/ros_publish-python-module-py.cc
rename to ros1/src/ros_publish-python-module-py.cc
diff --git a/src/ros_publish.cpp b/ros1/src/ros_publish.cpp
similarity index 100%
rename from src/ros_publish.cpp
rename to ros1/src/ros_publish.cpp
diff --git a/src/ros_publish.hh b/ros1/src/ros_publish.hh
similarity index 100%
rename from src/ros_publish.hh
rename to ros1/src/ros_publish.hh
diff --git a/src/ros_publish.hxx b/ros1/src/ros_publish.hxx
similarity index 100%
rename from src/ros_publish.hxx
rename to ros1/src/ros_publish.hxx
diff --git a/src/ros_queued_subscribe-python-module-py.cc b/ros1/src/ros_queued_subscribe-python-module-py.cc
similarity index 100%
rename from src/ros_queued_subscribe-python-module-py.cc
rename to ros1/src/ros_queued_subscribe-python-module-py.cc
diff --git a/src/ros_queued_subscribe.cpp b/ros1/src/ros_queued_subscribe.cpp
similarity index 100%
rename from src/ros_queued_subscribe.cpp
rename to ros1/src/ros_queued_subscribe.cpp
diff --git a/src/ros_queued_subscribe.hh b/ros1/src/ros_queued_subscribe.hh
similarity index 100%
rename from src/ros_queued_subscribe.hh
rename to ros1/src/ros_queued_subscribe.hh
diff --git a/src/ros_queued_subscribe.hxx b/ros1/src/ros_queued_subscribe.hxx
similarity index 100%
rename from src/ros_queued_subscribe.hxx
rename to ros1/src/ros_queued_subscribe.hxx
diff --git a/src/ros_subscribe-python-module-py.cc b/ros1/src/ros_subscribe-python-module-py.cc
similarity index 100%
rename from src/ros_subscribe-python-module-py.cc
rename to ros1/src/ros_subscribe-python-module-py.cc
diff --git a/src/ros_subscribe.cpp b/ros1/src/ros_subscribe.cpp
similarity index 100%
rename from src/ros_subscribe.cpp
rename to ros1/src/ros_subscribe.cpp
diff --git a/src/ros_subscribe.hh b/ros1/src/ros_subscribe.hh
similarity index 100%
rename from src/ros_subscribe.hh
rename to ros1/src/ros_subscribe.hh
diff --git a/src/ros_subscribe.hxx b/ros1/src/ros_subscribe.hxx
similarity index 100%
rename from src/ros_subscribe.hxx
rename to ros1/src/ros_subscribe.hxx
diff --git a/src/ros_tf_listener-python-module-py.cc b/ros1/src/ros_tf_listener-python-module-py.cc
similarity index 100%
rename from src/ros_tf_listener-python-module-py.cc
rename to ros1/src/ros_tf_listener-python-module-py.cc
diff --git a/src/ros_tf_listener.cpp b/ros1/src/ros_tf_listener.cpp
similarity index 100%
rename from src/ros_tf_listener.cpp
rename to ros1/src/ros_tf_listener.cpp
diff --git a/src/ros_tf_listener.hh b/ros1/src/ros_tf_listener.hh
similarity index 100%
rename from src/ros_tf_listener.hh
rename to ros1/src/ros_tf_listener.hh
diff --git a/src/ros_time-python.hh b/ros1/src/ros_time-python.hh
similarity index 100%
rename from src/ros_time-python.hh
rename to ros1/src/ros_time-python.hh
diff --git a/src/ros_time.cpp b/ros1/src/ros_time.cpp
similarity index 100%
rename from src/ros_time.cpp
rename to ros1/src/ros_time.cpp
diff --git a/src/ros_time.hh b/ros1/src/ros_time.hh
similarity index 100%
rename from src/ros_time.hh
rename to ros1/src/ros_time.hh
diff --git a/src/sot_loader.cpp b/ros1/src/sot_loader.cpp
similarity index 100%
rename from src/sot_loader.cpp
rename to ros1/src/sot_loader.cpp
diff --git a/src/sot_loader_basic.cpp b/ros1/src/sot_loader_basic.cpp
similarity index 100%
rename from src/sot_loader_basic.cpp
rename to ros1/src/sot_loader_basic.cpp
diff --git a/src/sot_to_ros.cpp b/ros1/src/sot_to_ros.cpp
similarity index 100%
rename from src/sot_to_ros.cpp
rename to ros1/src/sot_to_ros.cpp
diff --git a/src/sot_to_ros.hh b/ros1/src/sot_to_ros.hh
similarity index 100%
rename from src/sot_to_ros.hh
rename to ros1/src/sot_to_ros.hh
diff --git a/tests/CMakeLists.txt b/ros1/tests/CMakeLists.txt
similarity index 100%
rename from tests/CMakeLists.txt
rename to ros1/tests/CMakeLists.txt
diff --git a/tests/test_import.py b/ros1/tests/test_import.py
similarity index 100%
rename from tests/test_import.py
rename to ros1/tests/test_import.py
diff --git a/ros2/CMakeLists.txt b/ros2/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6e0fc7520e783ab30b8dbfd4da379fdc6f20d14d
--- /dev/null
+++ b/ros2/CMakeLists.txt
@@ -0,0 +1,54 @@
+# Copyright (C) 2021 LAAS-CNRS.
+#
+# Author: Maxmilien Naveau
+#
+
+if(NOT CMAKE_CXX_STANDARD)
+  set(CMAKE_CXX_STANDARD 14)
+endif()
+
+cmake_policy(SET CMP0057 NEW)
+find_package(ament_cmake REQUIRED)
+find_package(rclcpp REQUIRED)
+find_package(ament_cmake_core REQUIRED)
+find_package(ament_index_cpp REQUIRED)
+find_package(rcutils REQUIRED)
+find_package(std_msgs REQUIRED)  
+find_package(std_srvs REQUIRED)
+find_package(geometry_msgs REQUIRED)
+find_package(sensor_msgs REQUIRED)
+find_package(tf2_ros REQUIRED)
+
+add_project_dependency(Boost REQUIRED COMPONENTS program_options)
+add_project_dependency(dynamic_graph_bridge_msgs 0.3.0 REQUIRED)
+add_project_dependency(sot-core REQUIRED)
+
+IF(BUILD_PYTHON_INTERFACE)
+  findpython()
+  search_for_boost_python()
+  string(REGEX REPLACE "-" "_" PY_NAME ${PROJECT_NAME})
+  add_project_dependency(dynamic-graph-python 4.0.0 REQUIRED)
+
+  IF(Boost_VERSION GREATER 107299 OR Boost_VERSION_MACRO GREATER 107299)
+    # Silence a warning about a deprecated use of boost bind by boost >= 1.73
+    # without dropping support for boost < 1.73
+    add_definitions(-DBOOST_BIND_GLOBAL_PLACEHOLDERS)
+  ENDIF()
+ENDIF(BUILD_PYTHON_INTERFACE)
+
+add_subdirectory(src)
+# add_subdirectory(tests)
+
+#install ros executables
+install(PROGRAMS
+  scripts/robot_pose_publisher
+  scripts/run_command
+  scripts/tf_publisher
+  DESTINATION share/${PROJECT_NAME}
+  )
+
+# Install package information
+install(FILES package.xml DESTINATION share/${PROJECT_NAME})
+
+#ROS 2 packaging
+ament_package()
diff --git a/ros2/include/dynamic_graph_bridge/ros.hpp b/ros2/include/dynamic_graph_bridge/ros.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d173ffc7aefbf4686d2de5355443c01477f7a3bc
--- /dev/null
+++ b/ros2/include/dynamic_graph_bridge/ros.hpp
@@ -0,0 +1,126 @@
+/**
+ * @file
+ * @license License BSD-3-Clause
+ * @copyright Copyright (c) 2019, New York University and Max Planck
+ * Gesellschaft.
+ */
+
+#pragma once
+
+#include <memory>
+
+// ROS includes
+#include "dynamic_graph_bridge_msgs/srv/run_python_command.hpp"
+#include "dynamic_graph_bridge_msgs/srv/run_python_file.hpp"
+#include "rclcpp/rclcpp.hpp"
+#include "std_srvs/srv/empty.hpp"
+
+namespace dynamic_graph_bridge
+{
+const std::string DG_ROS_NODE_NAME = "dynamic_graph";
+const std::string HWC_ROS_NODE_NAME = "hardware_communication";
+
+/*
+ * A Bunch of convenient shortcuts.
+ */
+typedef rclcpp::Node RosNode;
+typedef std::shared_ptr<RosNode> RosNodePtr;
+typedef rclcpp::executors::MultiThreadedExecutor RosExecutor;
+typedef std::shared_ptr<RosExecutor> RosExecutorPtr;
+
+// Python commands shortcuts
+typedef dynamic_graph_bridge_msgs::srv::RunPythonCommand RunPythonCommandSrvType;
+typedef rclcpp::Service<RunPythonCommandSrvType>::SharedPtr
+    RunPythonCommandServerPtr;
+typedef rclcpp::Client<RunPythonCommandSrvType>::SharedPtr
+    RunPythonCommandClientPtr;
+typedef RunPythonCommandSrvType::Request::SharedPtr RunPythonCommandRequestPtr;
+typedef std::shared_ptr<RunPythonCommandSrvType::Response>
+    RunPythonCommandResponsePtr;
+typedef std::shared_future<std::shared_ptr<RunPythonCommandSrvType::Response> >
+    RunPythonCommandResponseFuturePtr;
+
+// Parse python file shortcuts.
+typedef dynamic_graph_bridge_msgs::srv::RunPythonFile RunPythonFileSrvType;
+typedef rclcpp::Service<RunPythonFileSrvType>::SharedPtr RunPythonFileServerPtr;
+typedef rclcpp::Client<RunPythonFileSrvType>::SharedPtr RunPythonFileClientPtr;
+typedef std::shared_ptr<RunPythonFileSrvType::Request> RunPythonFileRequestPtr;
+typedef std::shared_ptr<RunPythonFileSrvType::Response>
+    RunPythonFileResponsePtr;
+typedef std::shared_future<std::shared_ptr<RunPythonFileSrvType::Response> >
+    RunPythonFileResponseFuturePtr;
+
+// Shortcut for chrono constant handling.
+typedef std::chrono::duration<int64_t, std::ratio<1, 1> > DurationSec;
+
+// Used to save the hardware service pointers.
+typedef std::shared_ptr<rclcpp::ServiceBase> ServiceBasePtr;
+typedef rclcpp::Service<std_srvs::srv::Empty>::SharedPtr EmptyServicePtr;
+typedef std_srvs::srv::Empty EmptyServiceType;
+
+/**
+ * @brief rosInit is a global method that uses the structure GlobalRos.
+ * Its role is to create the ros::nodeHandle and the ros::spinner once at the
+ * first call. It always returns a reference to the node hanlde.
+ * @return the reference of GLOBAL_ROS_VAR.node_.
+ */
+RosNodePtr get_ros_node(std::string node_name);
+
+/**
+ * @brief Add a ros node to the global executor.
+ *
+ * @param node_name
+ */
+void ros_add_node_to_executor(const std::string& node_name);
+
+/**
+ * @brief Checks if the Node has been created.
+ *
+ * @param node_name
+ * @return true
+ * @return false
+ */
+bool ros_node_exists(std::string node_name);
+
+/**
+ * @brief Allow all the created ROS node to perform their callbacks.
+ * Warning: blocking function.
+ */
+void ros_spin();
+
+/**
+ * @brief Allow all the created ROS node to perform their callbacks.
+ */
+void ros_spin_non_blocking();
+
+/**
+ * @brief Stop the ros spinning.
+ */
+void ros_stop_spinning();
+
+/**
+ * @brief ros_shutdown shuts down ros and stop the ros spinner with the
+ * associate name
+ */
+void ros_shutdown(std::string node_name);
+
+/**
+ * @brief ros_shutdown shuts down ros and stop the ros spinners
+ */
+void ros_shutdown();
+
+/**
+ * @brief Remove all node from the executor and delete it.
+ */
+void ros_clean();
+
+/**
+ * @brief Check if ROS is fine.
+ *
+ * @param node_name
+ * @return true
+ * @return false
+ */
+bool ros_ok();
+
+}  // end of namespace dynamic_graph_bridge.
diff --git a/ros2/include/dynamic_graph_bridge/ros_parameter.hpp b/ros2/include/dynamic_graph_bridge/ros_parameter.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..688850ce0353159a4c60f1f75cf215e4b07362d8
--- /dev/null
+++ b/ros2/include/dynamic_graph_bridge/ros_parameter.hpp
@@ -0,0 +1,10 @@
+#ifndef _ROS_DYNAMIC_GRAPH_PARAMETER_
+#define _ROS_DYNAMIC_GRAPH_PARAMETER_
+
+#include "rclcpp/node.hpp"
+namespace dynamicgraph {
+
+  bool parameter_server_read_robot_description(rclcpp::Node::SharedPtr nh);
+
+}
+#endif /* _ROS_DYNAMIC_GRAPH_PARAMETER_ */
diff --git a/ros2/include/dynamic_graph_bridge/ros_python_interpreter_client.hpp b/ros2/include/dynamic_graph_bridge/ros_python_interpreter_client.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..aa0598605efd60885be10ba2a9abcac33e1ec3a2
--- /dev/null
+++ b/ros2/include/dynamic_graph_bridge/ros_python_interpreter_client.hpp
@@ -0,0 +1,152 @@
+/**
+ * @file
+ * @license BSD 3-clause
+ * @copyright Copyright (c) 2020, New York University and Max Planck
+ * Gesellschaft
+ *
+ * @brief Defines a C++ interface for the ros-service of the dynamic-graph
+ * python interpreter. (Available in python through bindings.)
+ */
+
+#pragma once
+
+#include "dynamic_graph_bridge/ros.hpp"
+
+namespace dynamic_graph_bridge
+{
+/**
+ * @brief Client of the RosPythonInterpreterServer through rosservices.
+ */
+class RosPythonInterpreterClient
+{
+public:
+    /**
+     * @brief Construct a new RosPythonInterpreterClient object.
+     */
+    RosPythonInterpreterClient();
+
+    /**
+     * @brief Destroy the RosPythonInterpreterClient object.
+     */
+    ~RosPythonInterpreterClient()
+    {
+    }
+
+    /**
+     * @brief Call the rosservice of the current running DynamicGraphManager.
+     *
+     * @param code_string To be executed in the embeded python interpreter.
+     * @return std::string
+     */
+    std::string run_python_command(const std::string& code_string);
+
+    /**
+     * @brief Call the rosservice of the current running DynamicGraphManager.
+     *
+     * @param filename
+     */
+    std::string run_python_script(const std::string& filename);
+
+private:
+    /**
+     * @brief Connect to a designated service.
+     *
+     * @tparam RosServiceType
+     * @param service_name
+     * @param client
+     * @param timeout
+     */
+    template <typename RosServiceType>
+    typename rclcpp::Client<RosServiceType>::SharedPtr connect_to_rosservice(
+        const std::string& service_name, const DurationSec& timeout)
+    {
+        typename rclcpp::Client<RosServiceType>::SharedPtr client;
+        try
+        {
+            RCLCPP_INFO(rclcpp::get_logger("RosPythonInterpreterClient"),
+                        "Waiting for service %s ...",
+                        service_name.c_str());
+            // let use wait for the existance of the services
+            client =
+                ros_node_->create_client<RosServiceType>(service_name.c_str());
+            if (client->wait_for_service(timeout))
+            {
+                RCLCPP_INFO(rclcpp::get_logger("RosPythonInterpreterClient"),
+                            "Successfully connected to %s",
+                            service_name.c_str());
+            }
+            else
+            {
+                RCLCPP_INFO(rclcpp::get_logger("RosPythonInterpreterClient"),
+                            "Failed to connect to %s",
+                            service_name.c_str());
+            }
+        }
+        catch (...)
+        {
+            throw std::runtime_error(service_name + " not available.");
+        }
+        return client;
+    }
+
+    /**
+     * @brief Connects to the RunCommand rosservice.
+     *
+     * @param timeout [in]
+     */
+    void connect_to_rosservice_run_python_command(
+        const DurationSec& timeout = DurationSec(-1))
+    {
+        command_client_ = connect_to_rosservice<RunPythonCommandSrvType>(
+            run_command_service_name_, timeout);
+    }
+
+    /**
+     * @brief Connects to the RunPythonFile rosservice.
+     *
+     * @param timeout [in]
+     */
+    void connect_to_rosservice_run_python_script(
+        const DurationSec& timeout = DurationSec(-1))
+    {
+        script_client_ = connect_to_rosservice<RunPythonFileSrvType>(
+            run_script_service_name_, timeout);
+    }
+
+private:
+    /**
+     * @brief Name of the local ros_node;
+     */
+    std::string ros_node_name_;
+
+    /** @brief Handle for manipulating ROS objects. */
+    RosNodePtr ros_node_;
+
+    /** @brief  Name of the DynamicGraphManager RosPythonInterpreterServer
+     * rosservice for running a python command. */
+    std::string run_command_service_name_;
+
+    /** @brief Rosservice to run a python command.
+     * @see run_command_service_name_ */
+    RunPythonCommandClientPtr command_client_;
+
+    /** @brief Input of the rosservice. */
+    RunPythonCommandRequestPtr run_command_request_;
+
+    /** @brief  Name of the DynamicGraphManager RosPythonInterpreterServer
+     * rosservice for running a python script. */
+    std::string run_script_service_name_;
+
+    /** @brief Rosservice to run a python script.
+     * @see run_command_service_name_ */
+    RunPythonFileClientPtr script_client_;
+
+    /** @brief Input of the rosservice. */
+    RunPythonFileRequestPtr run_file_request_;
+
+    /** @brief timeout used during the connection to the rosservices in
+     * seconds. */
+    DurationSec timeout_connection_s_;
+};
+
+}  // namespace dynamic_graph_bridge
\ No newline at end of file
diff --git a/ros2/include/dynamic_graph_bridge/ros_python_interpreter_server.hpp b/ros2/include/dynamic_graph_bridge/ros_python_interpreter_server.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..378665b04fbd27671815c1ad97ed67a2f67afe00
--- /dev/null
+++ b/ros2/include/dynamic_graph_bridge/ros_python_interpreter_server.hpp
@@ -0,0 +1,154 @@
+/**
+ * @file ros_interpreter.hpp
+ * @author Maximilien Naveau (maximilien.naveau@gmail.com)
+ * @license License BSD-3-Clause
+ * @copyright Copyright (c) 2019, New York University and Max Planck
+ * Gesellschaft.
+ * @date 2019-05-22
+ *
+ * This file declares a ros bridge on top of Python interpretor. It is used
+ * an asynchronuous communcation between the user and the controller.
+ */
+
+#ifndef DYNAMIC_GRAPH_BRIDGE_INTERPRETER_HH
+#define DYNAMIC_GRAPH_BRIDGE_INTERPRETER_HH
+
+#include "dynamic-graph/python/interpreter.hh"
+#include "dynamic_graph_bridge/ros.hpp"
+
+namespace dynamic_graph_bridge
+{
+/// \brief This class wraps the implementation of the runCommand
+/// service.
+///
+/// This takes as input a ROS node handle and do not handle the
+/// callback so that the service behavior can be controlled from
+/// the outside.
+class RosPythonInterpreterServer
+{
+public:
+    /**
+     * @brief run_python_command_callback_t define a std::function to be used
+     * as callback to the rclcpp::service.
+     *
+     * The first argument of "runCommandCallback"
+     * (const std::string & command) is bound to
+     * (dynamic_graph_manager::srv::RunPythonCommand::Request).
+     * And the second argument (std::string &result) is bound to
+     * (dynamic_graph_manager::srv::RunPythonCommand::Response)
+     */
+    typedef std::function<void(RunPythonCommandRequestPtr,
+                               RunPythonCommandResponsePtr)>
+        run_python_command_callback_t;
+
+    /**
+     * @brief run_python_file_callback_t define a std::function to be used as
+     * callback to the rclcpp::service.
+     *
+     * The first argument of "runPythonFileCallback"
+     * (std::string ifilename) is bound to
+     * (dynamic_graph_manager::srv::RunPythonCommand::Request).
+     * And a fake second argument is simulated in
+     * (dynamic_graph_manager::srv::RunPythonCommand::Response)
+     */
+    typedef std::function<void(RunPythonFileRequestPtr,
+                               RunPythonFileResponsePtr)>
+        run_python_file_callback_t;
+
+    /**
+     * @brief RosPythonInterpreterServer is the unique constructor of the class
+     * @param node_handle is the RosNode used to advertize the
+     *        rclcpp::services
+     */
+    explicit RosPythonInterpreterServer();
+
+    /**
+     * @brief ~RosPythonInterpreterServer is the default destructor of the class
+     */
+    ~RosPythonInterpreterServer();
+
+    /**
+     * @brief run_python_command used the python interpreter to execute the
+     * input command
+     * @param[in] command is the user input string command.
+     * @param[out] result is the numerical result of the operation done.
+     * @param[out] out is the string representation of the results.
+     * @param[out] err is the output error string from python.
+     */
+    void run_python_command(const std::string& command,
+                            std::string& result,
+                            std::string& out,
+                            std::string& err);
+
+    /**
+     * @brief run_python_file executes the input scripts in the python
+     * interpreter
+     * @param ifilename is the path to the script to execute
+     */
+    void run_python_file(const std::string ifilename,
+                         std::string& standarderror);
+
+    /**
+     * @brief start_ros_service advertize the "run_python_command" and
+     * "run_python_scripts" ros services
+     */
+    void start_ros_service();
+
+protected:
+    /**
+     * @brief runCommandCallback is the "run_python_command" ros service
+     * callback function.
+     * @param req is the request. it is defined as a string in the
+     *        RunCommand.msg
+     * @param res is the request. it is defined as a string in the
+     *        RunCommand.msg
+     * @return true
+     */
+    void runCommandCallback(RunPythonCommandRequestPtr req,
+                            RunPythonCommandResponsePtr res);
+
+    /**
+     * @brief runCommandCallback is the "run_python_script" ros service callback
+     *        function.
+     * @param req is the request. it is defined as a string in the
+     *        RunCommand.msg
+     * @param res is the request. it is defined as a string in the
+     *        RunCommand.msg
+     * @return true
+     */
+    void runPythonFileCallback(RunPythonFileRequestPtr req,
+                               RunPythonFileResponsePtr res);
+
+private:
+    /**
+     * @brief interpreter_ is the python interpreter itself
+     */
+    dynamicgraph::python::Interpreter interpreter_;
+    /**
+     * @brief ros_node_ is reference to the RosNode used to
+     * advertize the rclcpp::services
+     */
+    RosNodePtr ros_node_;
+    /**
+     * @brief run_python_command_srv_ is the "run_python_command"
+     * rclcpp::service c++ object
+     *
+     * This kind of ros object require *NOT* to be destroyed. otherwize the
+     * rclcpp::service is cancelled. This is the reason why this object is an
+     * attribute of the class
+     */
+    RunPythonCommandServerPtr run_python_command_srv_;
+    /**
+     * @brief run_python_file_srv_ is the "run_python_script" rclcpp::service
+     * c++ object
+     *
+     * This kind of ros object require *NOT* to be destroyed. otherwize the
+     * rclcpp::service is cancelled. This is the reason why this object is an
+     * attribute of the class
+     */
+    RunPythonFileServerPtr run_python_file_srv_;
+};
+
+}  // namespace dynamic_graph_bridge
+
+#endif  //! DYNAMIC_GRAPH_BRIDGE_INTERPRETER_HH
diff --git a/ros2/include/dynamic_graph_bridge/ros_sot_loader.hpp b/ros2/include/dynamic_graph_bridge/ros_sot_loader.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/ros2/scripts/remote_python_client.py b/ros2/scripts/remote_python_client.py
new file mode 100644
index 0000000000000000000000000000000000000000..d756d5f00cf8abc8c0007b421872392c31c859f7
--- /dev/null
+++ b/ros2/scripts/remote_python_client.py
@@ -0,0 +1,156 @@
+#!/usr/bin/env python
+
+"""@package dynamic_graph_manager
+
+@file
+@license License BSD-3-Clause
+@copyright Copyright (c) 2019, New York University and Max Planck Gesellschaft.
+
+@brief Instanciate a python terminal communication with the dynamic-graph
+embeded terminal.
+
+"""
+
+# Standard import.
+import optparse
+import os.path
+import code
+import os
+import sys
+import readline
+import atexit
+import signal
+import rclpy
+
+# Used to connect to ROS services
+from dynamic_graph_manager.ros.dgcompleter import DGCompleter
+from dynamic_graph_manager_cpp_bindings import RosPythonInterpreterClient
+
+
+def signal_handler(sig, frame):
+    """
+    Catch Ctrl+C and quit.
+    """
+    print("")
+    print("You pressed Ctrl+C! Closing ros client and shell.")
+    rclpy.try_shutdown()
+    sys.exit(0)
+
+
+# Command history, auto-completetion and keyboard management
+python_history = os.path.join(os.environ["HOME"], ".dg_python_history")
+readline.parse_and_bind("tab: complete")
+readline.set_history_length(100000)
+
+
+def save_history(histfile):
+    """ Write the history of the user command in a file """
+    readline.write_history_file(histfile)
+
+
+"""
+Read the current history if it exists and program its save upon the program end.
+"""
+if hasattr(readline, "read_history_file"):
+    try:
+        readline.read_history_file(python_history)
+    except IOError:
+        pass
+    atexit.register(save_history, python_history)
+
+
+class DynamicGraphInteractiveConsole(code.InteractiveConsole):
+    """
+    For the subtilities please read https://docs.python.org/3/library/code.html
+    """
+
+    def __init__(self):
+
+        # Create the python terminal
+        code.InteractiveConsole.__init__(self)
+
+        # Command lines from the terminal.
+        self.lines_pushed = ""
+
+        self.ros_python_interpreter = RosPythonInterpreterClient()
+        if sys.version[:2].startswith("2."):
+            self.dg_completer = DGCompleter(self.ros_python_interpreter)
+            readline.set_completer(self.dg_completer.complete)
+
+    def runcode(self, code):
+        """
+        Inherited from code.InteractiveConsole
+
+        We execute the code pushed in the cache `self.lines_pushed`. The code is
+        pushed whenever the user press enter during the interactive session.
+        see https://docs.python.org/3/library/code.html
+        """
+        try:
+            # we copy the line in a tmp var
+            code_string = self.lines_pushed[:-1]
+            result = self.ros_python_interpreter.run_python_command(
+                code_string
+            )
+            self.write(result)
+            if not result.endswith("\n"):
+                self.write("\n")
+            # we reset the cache here
+            self.lines_pushed = ""
+        except Exception as e:
+            self.write(str(e))
+            return False
+
+    def runsource(self, source, filename="<input>", symbol="single"):
+        """
+        Inherited from code.InteractiveConsole
+
+        see https://docs.python.org/3/library/code.html
+        """
+        try:
+            c = code.compile_command(source, filename, symbol)
+            if c:
+                return self.runcode(c)
+            else:
+                return True
+        except SyntaxError:
+            self.showsyntaxerror()
+            self.lines_pushed = ""
+            return False
+        except OverflowError:
+            self.showsyntaxerror()
+            self.write("OverflowError")
+            self.lines_pushed = ""
+            return False
+
+    def push(self, line):
+        """
+        Upon pressing enter in the interactive shell the user "push" a string.
+        This method is then called with the string pushed.
+        We catch the string to send it via the rosservice.
+        """
+        self.lines_pushed += line + "\n"
+        return code.InteractiveConsole.push(self, line)
+
+
+if __name__ == "__main__":
+    rclpy.init()
+
+    parser = optparse.OptionParser(usage="\n\t%prog [options]")
+    (options, args) = parser.parse_args(sys.argv[1:])
+
+    dg_console = DynamicGraphInteractiveConsole()
+
+    if args[:]:
+        infile = args[0]
+        response = dg_console.ros_python_interpreter.run_python_script(
+            os.path.abspath(infile)
+        )
+        print(
+            dg_console.ros_python_interpreter.run_python_command(
+                "print('File parsed')"
+            )
+        )
+
+    signal.signal(signal.SIGINT, signal_handler)
+    dg_console.interact("Interacting with remote python server.")
+    rclpy.shutdown()
diff --git a/ros2/src/CMakeLists.txt b/ros2/src/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..93229f7cae70b2832577c32d8327e218106b1ac7
--- /dev/null
+++ b/ros2/src/CMakeLists.txt
@@ -0,0 +1,114 @@
+# Copyright (C) 2021 LAAS-CNRS.
+#
+# Author: Maxmilien Naveau
+#
+
+# Main Library
+set(${PROJECT_NAME}_HEADERS
+    ${PROJECT_SOURCE_DIR}/ros2/include/${PROJECT_NAME}/ros_parameter.hpp
+    ${PROJECT_SOURCE_DIR}/ros2/include/${PROJECT_NAME}/ros_python_interpreter_client.hpp
+    ${PROJECT_SOURCE_DIR}/ros2/include/${PROJECT_NAME}/ros_python_interpreter_server.hpp
+    ${PROJECT_SOURCE_DIR}/ros2/src/dg_ros_mapping.hpp
+    ${PROJECT_SOURCE_DIR}/ros2/src/matrix_geometry.hpp
+    ${PROJECT_SOURCE_DIR}/ros2/src/time_point_io.hpp)
+set(${PROJECT_NAME}_SOURCES
+    ${PROJECT_SOURCE_DIR}/ros2/src/dg_ros_mapping.cpp #
+    ${PROJECT_SOURCE_DIR}/ros2/src/ros_python_interpreter_client.cpp #
+    ${PROJECT_SOURCE_DIR}/ros2/src/ros_python_interpreter_server.cpp #
+    ${PROJECT_SOURCE_DIR}/ros2/src/ros.cpp #
+    ${PROJECT_SOURCE_DIR}/ros2/src/ros_parameter.cpp #
+)
+add_library(ros_bridge SHARED ${${PROJECT_NAME}_SOURCES}
+                              ${${PROJECT_NAME}_HEADERS})
+target_include_directories(ros_bridge
+  PUBLIC $<INSTALL_INTERFACE:include>
+  PRIVATE ${PROJECT_SOURCE_DIR}/ros2/include)
+target_link_libraries(
+  ros_bridge
+  sot-core::sot-core #
+  pinocchio::pinocchio #
+  dynamic-graph-python::dynamic-graph-python #
+  dynamic_graph_bridge_msgs::dynamic_graph_bridge_msgs__rosidl_typesupport_cpp)
+ament_target_dependencies(
+  ros_bridge
+  ament_index_cpp
+  std_msgs
+  std_srvs
+  geometry_msgs
+  sensor_msgs
+  tf2_ros
+  rcutils)
+if(SUFFIX_SO_VERSION)
+  set_target_properties(ros_bridge PROPERTIES SOVERSION ${PROJECT_VERSION})
+endif(SUFFIX_SO_VERSION)
+if(NOT INSTALL_PYTHON_INTERFACE_ONLY)
+  install(
+    TARGETS ros_bridge
+    EXPORT ${TARGETS_EXPORT_NAME}
+    DESTINATION lib)
+endif(NOT INSTALL_PYTHON_INTERFACE_ONLY)
+
+# Dynamic graph ros plugin.
+set(plugins ros_publish ros_subscribe)
+foreach(plugin ${plugins})
+  get_filename_component(LIBRARY_NAME ${plugin} NAME)
+  add_library(${LIBRARY_NAME} SHARED
+    ${PROJECT_SOURCE_DIR}/ros2/src/${plugin}.cpp #
+    ${PROJECT_SOURCE_DIR}/ros2/src/${plugin}.hpp #
+  )
+  if(SUFFIX_SO_VERSION)
+    set_target_properties(${LIBRARY_NAME} PROPERTIES SOVERSION
+                                                     ${PROJECT_VERSION})
+  endif(SUFFIX_SO_VERSION)
+  target_link_libraries(
+    ${LIBRARY_NAME} ${${LIBRARY_NAME}_deps} ${catkin_LIBRARIES} ros_bridge
+    dynamic_graph_bridge_msgs::dynamic_graph_bridge_msgs__rosidl_typesupport_cpp
+  )
+  if(NOT INSTALL_PYTHON_INTERFACE_ONLY)
+    install(
+      TARGETS ${LIBRARY_NAME}
+      EXPORT ${TARGETS_EXPORT_NAME}
+      DESTINATION ${DYNAMIC_GRAPH_PLUGINDIR})
+  endif(NOT INSTALL_PYTHON_INTERFACE_ONLY)
+  if(BUILD_PYTHON_INTERFACE)
+    string(REPLACE - _ PYTHON_LIBRARY_NAME ${LIBRARY_NAME})
+    if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${plugin}-python-module-py.cc")
+      dynamic_graph_python_module(
+        "ros/${PYTHON_LIBRARY_NAME}" ${LIBRARY_NAME}
+        ${PROJECT_NAME}-${PYTHON_LIBRARY_NAME}-wrap SOURCE_PYTHON_MODULE
+        "${CMAKE_CURRENT_SOURCE_DIR}/${plugin}-python-module-py.cc")
+    elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${plugin}-python.hh")
+      dynamic_graph_python_module(
+        "ros/${PYTHON_LIBRARY_NAME}" ${LIBRARY_NAME}
+        ${PROJECT_NAME}-${PYTHON_LIBRARY_NAME}-wrap MODULE_HEADER
+        "${CMAKE_CURRENT_SOURCE_DIR}/${plugin}-python.hh")
+    endif()
+  endif(BUILD_PYTHON_INTERFACE)
+endforeach(plugin)
+
+if(BUILD_PYTHON_INTERFACE)
+  python_install_on_site("dynamic_graph/ros" "__init__.py")
+  python_install_on_site("dynamic_graph/ros" "ros.py")
+  python_install_on_site("dynamic_graph/ros" "dgcompleter.py")
+endif(BUILD_PYTHON_INTERFACE)
+
+# Stand alone embedded intepreter with a robot controller.
+# add_executable(geometric_simu 
+#   geometric_simu.cpp
+#   sot_loader.cpp  
+#   sot_loader_basic.cpp)
+# target_link_libraries(
+#   geometric_simu Boost::program_options ${CMAKE_DL_LIBS} ${catkin_LIBRARIES}
+#   ros_bridge
+#   dynamic_graph_bridge_msgs::dynamic_graph_bridge_msgs__rosidl_typesupport_cpp)
+# install(TARGETS geometric_simu DESTINATION lib/${PROJECT_NAME})
+
+# Sot loader library
+# add_library(sot_loader sot_loader.cpp sot_loader_basic.cpp)
+# target_link_libraries(
+#   sot_loader Boost::program_options ${catkin_LIBRARIES} ros_bridge
+#   dynamic_graph_bridge_msgs::dynamic_graph_bridge_msgs__rosidl_typesupport_cpp)
+# install(
+#   TARGETS sot_loader
+#   EXPORT ${TARGETS_EXPORT_NAME}
+#   DESTINATION lib)
diff --git a/ros2/src/dg_ros_mapping.cpp b/ros2/src/dg_ros_mapping.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0f85f6c9362ed1094a6ad30a4e74b23ac1f3b290
--- /dev/null
+++ b/ros2/src/dg_ros_mapping.cpp
@@ -0,0 +1,280 @@
+/**
+ * @file dg_to_ros.cpp
+ * @author Maximilien Naveau (maximilien.naveau@gmail.com)
+ * @license License BSD-3-Clause
+ * @copyright Copyright (c) 2019, New York University and Max Planck
+ * Gesellschaft.
+ * @date 2019-05-22
+ */
+
+#include "dg_ros_mapping.hpp"
+
+namespace dynamic_graph_bridge
+{
+#define DG_TO_ROS_IMPL(DgRosMappingType)                                   \
+    template <>                                                            \
+    void DgRosMappingType::dg_to_ros(const DgRosMappingType::dg_t& dg_src, \
+                                     DgRosMappingType::ros_t& ros_dst)
+
+#define ROS_TO_DG_IMPL(DgRosMappingType)                                     \
+    template <>                                                              \
+    void DgRosMappingType::ros_to_dg(const DgRosMappingType::ros_t& ros_src, \
+                                     DgRosMappingType::dg_t& dg_dst)
+
+#define DG_DEFAULT_VALUE(DgRosMappingType) \
+    template <>                            \
+    const DgRosMappingType::dg_t DgRosMappingType::default_value
+
+#define DG_SIGNAL_TYPE_NAME(DgRosMappingType) \
+    template <>                               \
+    const std::string DgRosMappingType::signal_type_name
+
+/*
+ * Create the list of available types for error and documentation.
+ * purposes.
+ */
+const std::vector<std::string> DgRosTypes::type_list =
+    DgRosTypes::create_type_list();
+
+/*
+ * Float
+ */
+typedef DgRosMapping<std_msgs::msg::Float64, double> DgRosMappingFloat;
+DG_SIGNAL_TYPE_NAME(DgRosMappingFloat) = DgRosTypes::get_double();
+DG_DEFAULT_VALUE(DgRosMappingFloat) = 0.0;
+DG_TO_ROS_IMPL(DgRosMappingFloat)
+{
+    ros_dst.data = dg_src;
+}
+ROS_TO_DG_IMPL(DgRosMappingFloat)
+{
+    dg_dst = ros_src.data;
+}
+
+/*
+ * Unsigned int
+ */
+
+typedef DgRosMapping<std_msgs::msg::UInt32, unsigned int>
+    DgRosMappingUnsignedInt;
+DG_SIGNAL_TYPE_NAME(DgRosMappingUnsignedInt) = DgRosTypes::get_unsigned();
+DG_DEFAULT_VALUE(DgRosMappingUnsignedInt) = 0.0;
+DG_TO_ROS_IMPL(DgRosMappingUnsignedInt)
+{
+    ros_dst.data = dg_src;
+}
+ROS_TO_DG_IMPL(DgRosMappingUnsignedInt)
+{
+    dg_dst = ros_src.data;
+}
+
+/*
+ * Matrix, DG and Ros matrix storage orders are row major.
+ */
+
+typedef DgRosMapping<RosMatrix, DgMatrix> DgRosMappingMatrix;
+DG_SIGNAL_TYPE_NAME(DgRosMappingMatrix) = DgRosTypes::get_matrix();
+DG_DEFAULT_VALUE(DgRosMappingMatrix) = DgMatrix::Zero(0, 0);
+DG_TO_ROS_IMPL(DgRosMappingMatrix)
+{
+    // For simplicity and easiness of maintenance we implement a slower version
+    // of the copy here.
+    ros_dst.width = static_cast<unsigned int>(dg_src.rows());
+    ros_dst.data.resize(dg_src.size());
+    for (int row = 0; row < dg_src.rows(); ++row)
+    {
+        for (int col = 0; col < dg_src.cols(); ++col)
+        {
+            ros_dst.data[row * ros_dst.width + col] = dg_src(row, col);
+        }
+    }
+}
+ROS_TO_DG_IMPL(DgRosMappingMatrix)
+{
+    // For simplicity and easiness of maintenance we implement a slower version
+    // of the copy here.
+    int rows = ros_src.width;
+    int cols = static_cast<int>(ros_src.data.size()) / static_cast<int>(rows);
+    dg_dst.resize(rows, cols);
+    for (int row = 0; row < dg_dst.rows(); ++row)
+    {
+        for (int col = 0; col < dg_dst.cols(); ++col)
+        {
+            dg_dst(row, col) = ros_src.data[row * rows + col];
+        }
+    }
+}
+
+/*
+ * Vector
+ */
+typedef DgRosMapping<RosVector, DgVector> DgRosMappingVector;
+DG_SIGNAL_TYPE_NAME(DgRosMappingVector) = DgRosTypes::get_vector();
+DG_DEFAULT_VALUE(DgRosMappingVector) = DgVector::Zero(0);
+DG_TO_ROS_IMPL(DgRosMappingVector)
+{
+    ros_dst.data.resize(static_cast<unsigned int>(dg_src.size()));
+    for (unsigned int i = 0; i < dg_src.size(); ++i)
+    {
+        ros_dst.data[i] = dg_src[i];
+    }
+}
+ROS_TO_DG_IMPL(DgRosMappingVector)
+{
+    dg_dst.resize(static_cast<int>(ros_src.data.size()));
+    for (unsigned int i = 0; i < dg_dst.size(); ++i)
+    {
+        dg_dst[i] = ros_src.data[i];
+    }
+}
+
+/*
+ * Vector3, ROS is {x, y, z}, DG is a DgVector
+ */
+typedef DgRosMapping<geometry_msgs::msg::Vector3, DgVector> DgRosMappingVector3;
+DG_SIGNAL_TYPE_NAME(DgRosMappingVector3) = DgRosTypes::get_vector3();
+DG_DEFAULT_VALUE(DgRosMappingVector3) = DgVector::Zero(3);
+DG_TO_ROS_IMPL(DgRosMappingVector3)
+{
+    if (dg_src.size() > 0)
+    {
+        ros_dst.x = dg_src(0);
+        if (dg_src.size() > 1)
+        {
+            ros_dst.y = dg_src(1);
+            if (dg_src.size() > 2)
+            {
+                ros_dst.z = dg_src(2);
+            }
+        }
+    }
+}
+ROS_TO_DG_IMPL(DgRosMappingVector3)
+{
+    dg_dst.resize(3);
+    dg_dst[0] = ros_src.x;
+    dg_dst[1] = ros_src.y;
+    dg_dst[2] = ros_src.z;
+}
+
+/*
+ * MatrixHomo, ROS is a Transform (x, y, z, qx, qy, qz, qw),
+ * DG is a homogeneous matrix.
+ */
+typedef DgRosMapping<geometry_msgs::msg::Transform, MatrixHomogeneous>
+    DgRosMappingMatrixHomo;
+DG_SIGNAL_TYPE_NAME(DgRosMappingMatrixHomo) =
+    DgRosTypes::get_matrix_homogeneous();
+DG_DEFAULT_VALUE(DgRosMappingMatrixHomo) = MatrixHomogeneous::Identity();
+DG_TO_ROS_IMPL(DgRosMappingMatrixHomo)
+{
+    ros_dst.translation.x = dg_src.translation()(0);
+    ros_dst.translation.y = dg_src.translation()(1);
+    ros_dst.translation.z = dg_src.translation()(2);
+
+    VectorQuaternion q(dg_src.linear());
+    ros_dst.rotation.x = q.x();
+    ros_dst.rotation.y = q.y();
+    ros_dst.rotation.z = q.z();
+    ros_dst.rotation.w = q.w();
+}
+ROS_TO_DG_IMPL(DgRosMappingMatrixHomo)
+{
+    dg_dst.translation()(0) = ros_src.translation.x;
+    dg_dst.translation()(1) = ros_src.translation.y;
+    dg_dst.translation()(2) = ros_src.translation.z;
+
+    VectorQuaternion q(ros_src.rotation.w,
+                       ros_src.rotation.x,
+                       ros_src.rotation.y,
+                       ros_src.rotation.z);
+    dg_dst.linear() = q.matrix();
+}
+
+/*
+ * MatrixHomo, ROS is a twist (x, y, z, wx, wy, wz),
+ * DG is a homogeneous matrix.
+ */
+typedef DgRosMapping<geometry_msgs::msg::Twist, DgVector> DgRosMappingTwist;
+DG_SIGNAL_TYPE_NAME(DgRosMappingTwist) = DgRosTypes::get_twist();
+DG_DEFAULT_VALUE(DgRosMappingTwist) = DgVector::Zero(6);
+DG_TO_ROS_IMPL(DgRosMappingTwist)
+{
+    if (dg_src.size() != 6)
+    {
+        throw std::runtime_error("failed to convert invalid twist");
+    }
+    ros_dst.linear.x = dg_src(0);
+    ros_dst.linear.y = dg_src(1);
+    ros_dst.linear.z = dg_src(2);
+    ros_dst.angular.x = dg_src(3);
+    ros_dst.angular.y = dg_src(4);
+    ros_dst.angular.z = dg_src(5);
+}
+ROS_TO_DG_IMPL(DgRosMappingTwist)
+{
+    dg_dst.resize(6);
+    dg_dst(0) = ros_src.linear.x;
+    dg_dst(1) = ros_src.linear.y;
+    dg_dst(2) = ros_src.linear.z;
+    dg_dst(3) = ros_src.angular.x;
+    dg_dst(4) = ros_src.angular.y;
+    dg_dst(5) = ros_src.angular.z;
+}
+
+/*
+ * Vector3Stamped, ROS is {x, y, z} stamped, DG is a DgVector
+ */
+typedef DgRosMapping<geometry_msgs::msg::Vector3Stamped, DgVector>
+    DgRosMappingVector3Stamped;
+DG_SIGNAL_TYPE_NAME(DgRosMappingVector3Stamped) =
+    DgRosTypes::get_vector3_stamped();
+DG_DEFAULT_VALUE(DgRosMappingVector3Stamped) = DgVector::Zero(3);
+DG_TO_ROS_IMPL(DgRosMappingVector3Stamped)
+{
+    make_header(ros_dst.header);
+    DgRosMappingVector3::dg_to_ros(dg_src, ros_dst.vector);
+}
+ROS_TO_DG_IMPL(DgRosMappingVector3Stamped)
+{
+    DgRosMappingVector3::ros_to_dg(ros_src.vector, dg_dst);
+}
+
+/*
+ * MatrixHomo, ROS is a stamped Transform (x, y, z, qx, qy, qz, qw),
+ * DG is a homogeneous matrix.
+ */
+typedef DgRosMapping<geometry_msgs::msg::TransformStamped, MatrixHomogeneous>
+    DgRosMappingMatrixHomoStamped;
+DG_SIGNAL_TYPE_NAME(DgRosMappingMatrixHomoStamped) =
+    DgRosTypes::get_matrix_homogeneous_stamped();
+DG_DEFAULT_VALUE(DgRosMappingMatrixHomoStamped) = MatrixHomogeneous::Identity();
+DG_TO_ROS_IMPL(DgRosMappingMatrixHomoStamped)
+{
+    make_header(ros_dst.header);
+    DgRosMappingMatrixHomo::dg_to_ros(dg_src, ros_dst.transform);
+}
+ROS_TO_DG_IMPL(DgRosMappingMatrixHomoStamped)
+{
+    DgRosMappingMatrixHomo::ros_to_dg(ros_src.transform, dg_dst);
+}
+
+/*
+ * MatrixHomo, ROS is a stamped twist (x, y, z, wx, wy, wz),
+ * DG is a homogeneous matrix.
+ */
+typedef DgRosMapping<geometry_msgs::msg::TwistStamped, DgVector>
+    DgRosMappingTwistStamped;
+DG_SIGNAL_TYPE_NAME(DgRosMappingTwistStamped) = DgRosTypes::get_twist_stamped();
+DG_DEFAULT_VALUE(DgRosMappingTwistStamped) = DgVector::Zero(6);
+DG_TO_ROS_IMPL(DgRosMappingTwistStamped)
+{
+    make_header(ros_dst.header);
+    DgRosMappingTwist::dg_to_ros(dg_src, ros_dst.twist);
+}
+ROS_TO_DG_IMPL(DgRosMappingTwistStamped)
+{
+    DgRosMappingTwist::ros_to_dg(ros_src.twist, dg_dst);
+}
+
+}  // namespace dynamic_graph_bridge
diff --git a/ros2/src/dg_ros_mapping.hpp b/ros2/src/dg_ros_mapping.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5d5d443be6353fa234ddc858961410e82251df1a
--- /dev/null
+++ b/ros2/src/dg_ros_mapping.hpp
@@ -0,0 +1,203 @@
+/**
+ * @file dg_to_ros.hpp
+ * @author Maximilien Naveau (maximilien.naveau@gmail.com)
+ * @license License BSD-3-Clause
+ * @copyright Copyright (c) 2019, New York University and Max Planck
+ * Gesellschaft.
+ * @date 2019-05-22
+ */
+#pragma once
+
+// Standard includes
+#include <sstream>
+#include <utility>
+#include <vector>
+
+// Dynamic Graph types.
+#include <dynamic-graph/linear-algebra.h>
+#include <dynamic-graph/signal-ptr.h>
+#include <dynamic-graph/signal-time-dependent.h>
+
+// ROS types
+#include <geometry_msgs/msg/transform.hpp>
+#include <geometry_msgs/msg/transform_stamped.hpp>
+#include <geometry_msgs/msg/twist.hpp>
+#include <geometry_msgs/msg/twist_stamped.hpp>
+#include <geometry_msgs/msg/vector3_stamped.hpp>
+#include <std_msgs/msg/float64.hpp>
+#include <std_msgs/msg/u_int32.hpp>
+
+// internal DG types
+#include "matrix_geometry.hpp"
+#include "time_point_io.hpp"
+
+// internal ros types
+#include "dynamic_graph_bridge/ros.hpp"
+#include "dynamic_graph_bridge_msgs/msg/matrix.hpp"
+#include "dynamic_graph_bridge_msgs/msg/vector.hpp"
+
+namespace dynamic_graph_bridge
+{
+/** @brief Conventient renaming for ease of implementation. */
+typedef dynamicgraph::Vector DgVector;
+/** @brief Conventient renaming for ease of implementation. */
+typedef dynamicgraph::Matrix DgMatrix;
+/** @brief Conventient renaming for ease of implementation. */
+typedef dynamic_graph_bridge_msgs::msg::Vector RosVector;
+/** @brief Conventient renaming for ease of implementation. */
+typedef dynamic_graph_bridge_msgs::msg::Matrix RosMatrix;
+
+struct DgRosTypes
+{
+    static std::vector<std::string> create_type_list()
+    {
+        std::vector<std::string> tmp_type_list;
+        tmp_type_list.push_back("double");
+        tmp_type_list.push_back("unsigned");
+        tmp_type_list.push_back("matrix");
+        tmp_type_list.push_back("vector");
+        tmp_type_list.push_back("vector3");
+        tmp_type_list.push_back("vector3_stamped");
+        tmp_type_list.push_back("matrix_homogeneous");
+        tmp_type_list.push_back("matrix_homogeneous_stamped");
+        tmp_type_list.push_back("twist");
+        tmp_type_list.push_back("twist_stamped");
+        return tmp_type_list;
+    }
+    // clang-format off
+    static const std::string& get_double(){return type_list[0];};
+    static const std::string& get_unsigned(){return type_list[1];};
+    static const std::string& get_matrix(){return type_list[2];};
+    static const std::string& get_vector(){return type_list[3];};
+    static const std::string& get_vector3(){return type_list[4];};
+    static const std::string& get_vector3_stamped(){return type_list[5];};
+    static const std::string& get_matrix_homogeneous(){return type_list[6];};
+    static const std::string& get_matrix_homogeneous_stamped()
+        {return type_list[7];};
+    static const std::string& get_twist(){return type_list[8];};
+    static const std::string& get_twist_stamped(){return type_list[9];};
+    // clang-format on
+    static const std::vector<std::string> type_list;
+};
+
+/**
+ * @brief DgRosMapping trait type.
+ *
+ * DG stands for Dynamic Graph and ROS for Robot Operating System.
+ * This trait provides types associated to a dynamic-graph type:
+ * - DG / ROS corresponding types,
+ * - Output/Input signal type,
+ * - ROS / DG callback type.
+ *
+ * @tparam RosType is the type of the ROS data.
+ * @tparam DgType is the type of the Dynamic Graph data.
+ */
+template <class RosType, class DgType>
+class DgRosMapping
+{
+public:
+    /*
+     * Some renaming first
+     */
+
+    /** @brief Dynamic Graph type. */
+    typedef DgType dg_t;
+    /** @brief Ros type. */
+    typedef RosType ros_t;
+    /** @brief Ros type as a shared pointer. */
+    typedef std::shared_ptr<RosType> ros_shared_ptr_t;
+    /** @brief Output signal type. */
+    typedef dynamicgraph::SignalTimeDependent<dg_t, int> signal_out_t;
+    /** @brief Output signal type. */
+    typedef dynamicgraph::SignalTimeDependent<timestamp_t, int>
+        signal_timestamp_out_t;
+    /** @brief Input signal type. */
+    typedef dynamicgraph::SignalPtr<dg_t, int> signal_in_t;
+    /** @brief Signal callback function types. */
+    typedef std::function<dg_t&(dg_t&, int)> signal_callback_t;
+
+    /** @brief Name of the signal type. Used during the creation of signals. */
+    static const std::string signal_type_name;
+    static const dg_t default_value;
+
+    /**
+     * @brief Set the default value to the inuput DG signal.
+     *
+     * @tparam SignalType (in/out)
+     * @param s
+     */
+    template <typename SignalTypePtr>
+    static void set_default(SignalTypePtr s)
+    {
+        s->setConstant(DgRosMapping<RosType, DgType>::default_value);
+    }
+
+    /**
+     * @brief Set the default value to the input DG object.
+     *
+     * @param s
+     */
+    static void set_default(dg_t& d)
+    {
+        d = DgRosMapping<RosType, DgType>::default_value;
+    }
+
+    /**
+     * @brief Convert ROS time to std::chrono.
+     *
+     * @param ros_time
+     * @return timestamp_t
+     */
+    static timestamp_t from_ros_time(rclcpp::Time ros_time)
+    {
+        return epoch_time() + std::chrono::nanoseconds(ros_time.nanoseconds());
+    }
+
+    /**
+     * @brief Get epoch time as ROS time start from there.
+     *
+     * @return timestamp_t
+     */
+    static timestamp_t epoch_time()
+    {
+        return std::chrono::time_point<std::chrono::high_resolution_clock>{};
+    }
+
+    /**
+     * @brief Convert a ROS object into DG one.
+     *
+     * @param src
+     * @param dst
+     */
+    static void ros_to_dg(const ros_t& ros_src, dg_t& dg_dst);
+
+    /**
+     * @brief Convert a DG object into a ROS one.
+     *
+     * @param src
+     * @param dst
+     */
+    static void dg_to_ros(const dg_t& dg_src, ros_t& ros_dst);
+};
+
+template <class RosEntity>
+inline std::string make_signal_string(const RosEntity& entity,
+                                      bool isInputSignal,
+                                      const std::string& signal_type,
+                                      const std::string& signal_name)
+{
+    std::ostringstream oss;
+    oss << entity.getClassName() << "(" << entity.getName() << ")"
+        << "::" << (isInputSignal ? "input" : "output") << "(" << signal_type
+        << ")"
+        << "::" << signal_name;
+    return oss.str();
+}
+
+inline void make_header(std_msgs::msg::Header& header)
+{
+    header.stamp = get_ros_node(DG_ROS_NODE_NAME)->get_clock()->now();
+    header.frame_id = "/dynamic_graph/world";
+}
+
+}  // namespace dynamic_graph_bridge
diff --git a/ros2/src/dynamic_graph/ros/__init__.py b/ros2/src/dynamic_graph/ros/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..cc585acab0f67b9d27a123f53b08b9249d91b81b
--- /dev/null
+++ b/ros2/src/dynamic_graph/ros/__init__.py
@@ -0,0 +1,11 @@
+"""@package dynamic_graph_manager
+
+@file __init__.py
+@author Maximilien Naveau (maximilien.naveau@gmail.com)
+@license License BSD-3-Clause
+@copyright Copyright (c) 2019, New York University and Max Planck Gesellschaft.
+@date 2019-05-22
+
+@brief This file Defines the python ROS import.
+
+"""
diff --git a/ros2/src/dynamic_graph/ros/dgcompleter.py b/ros2/src/dynamic_graph/ros/dgcompleter.py
new file mode 100644
index 0000000000000000000000000000000000000000..aa24433fdd03bec44b0860f87b6b7f6f932c8c65
--- /dev/null
+++ b/ros2/src/dynamic_graph/ros/dgcompleter.py
@@ -0,0 +1,92 @@
+"""Word completion for GNU readline.
+
+The completer completes keywords, built-ins and globals in a selectable
+namespace (which defaults to __main__); when completing NAME.NAME..., it
+evaluates (!) the expression up to the last dot and completes its attributes.
+
+It's very cool to do "import sys" type "sys.", hit the completion key (twice),
+and see the list of names defined by the sys module!
+
+Tip: to use the tab key as the completion key, call
+
+    readline.parse_and_bind("tab: complete")
+
+Notes:
+
+- Exceptions raised by the completer function are *ignored* (and generally cause
+  the completion to fail).  This is a feature -- since readline sets the tty
+  device in raw (or cbreak) mode, printing a traceback wouldn't work well
+  without some complicated hoopla to save, reset and restore the tty state.
+
+- The evaluation of the NAME.NAME... form may cause arbitrary application
+  defined code to be executed if an object with a __getattr__ hook is found.
+  Since it is the responsibility of the application (or the user) to enable this
+  feature, I consider this an acceptable risk.  More complicated expressions
+  (e.g. function calls or indexing operations) are *not* evaluated.
+
+- GNU readline is also used by the built-in functions input() and
+raw_input(), and thus these also benefit/suffer from the completer
+features.  Clearly an interactive application can benefit by
+specifying its own completer function and using raw_input() for all
+its input.
+
+- When the original stdin is not a tty device, GNU readline is never
+  used, and this module (and the readline module) are silently inactive.
+
+"""
+
+import ast
+from dynamic_graph_manager_cpp_bindings import RosPythonInterpreterClient
+
+__all__ = ["DGCompleter"]
+
+
+class DGCompleter:
+    def __init__(self, ros_python_interpreter_client=None):
+        """Create a new completer for the command line.
+
+        Completer([client]) -> completer instance.
+
+        Client is a ROS proxy to dynamic_graph run_python_command service.
+
+        Completer instances should be used as the completion mechanism of
+        readline via the set_completer() call:
+
+        readline.set_completer(Completer(client).complete)
+        """
+        if ros_python_interpreter_client is None:
+            self.client = RosPythonInterpreterClient()
+        else:
+            self.client = ros_python_interpreter_client
+
+        cmd = [
+            'if "local_completer" not in globals():\n'
+            '    print("Load the dg_completer")\n'
+            "    from rlcompleter import Completer\n"
+            "    local_completer=Completer()\n"
+            "    import readline\n"
+            "    readline.set_completer(local_completer.complete)\n"
+            '    readline.parse_and_bind("tab: complete")'
+        ]
+
+        for python_command in cmd:
+            print(python_command)
+            self.client.run_python_command(python_command)
+
+        self.buffer = []
+
+    def complete(self, text, state):
+        """Return the next possible completion for 'text'.readline.parse_and_bind("tab: complete")
+
+        This is called successively with state == 0, 1, 2, ... until it
+        returns None. The completion should begin with 'text'.
+        """
+        # self.client.run_python_command("global local_completer")
+        cmd = 'local_completer.complete("' + text + '",' + str(state) + ")"
+        response = self.client.run_python_command(cmd)
+        if not response or response is "\n" or response is None:
+            response = None
+            self.buffer = []
+        else:
+            self.buffer += [response]
+        return response
diff --git a/ros2/src/dynamic_graph/ros/ros.py b/ros2/src/dynamic_graph/ros/ros.py
new file mode 100644
index 0000000000000000000000000000000000000000..2bb925d12edc4091f73ad743c4055c64558a6748
--- /dev/null
+++ b/ros2/src/dynamic_graph/ros/ros.py
@@ -0,0 +1,31 @@
+"""@package dynamic_graph_manager
+
+@file ros.py
+@author Maximilien Naveau (maximilien.naveau@gmail.com)
+@license License BSD-3-Clause
+@copyright Copyright (c) 2019, New York University and Max Planck Gesellschaft.
+@date 2019-05-22
+
+@brief This file defines a class that create ros entities for the interaction
+between ROS and the dynamic graph
+
+"""
+
+from dynamic_graph import plug
+from dynamic_graph_manager.dynamic_graph.ros_entities import RosPublish
+from dynamic_graph_manager.dynamic_graph.ros_entities import RosSubscribe
+
+
+class Ros(object):
+    def __init__(self, device, suffix=""):
+        self.device = device
+        self.ros_publish = RosPublish("ros_publish" + suffix)
+        self.ros_subscribe = RosSubscribe("ros_subscribe" + suffix)
+
+        # make sure that the publishing is done by plugging the refresh
+        # (trigger) to the device periodic call system
+        self.device.after.addDownsampledSignal(
+            self.ros_publish.name + ".trigger", 1
+        )
+        # not needed for self.ros_subscribe and self.ros_subscribe as they get
+        # the information from ROS, they do not have output signals
diff --git a/ros2/src/matrix_geometry.hpp b/ros2/src/matrix_geometry.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..98ba8029c39da5c42cabb5dd1dd5c2584aefa0ea
--- /dev/null
+++ b/ros2/src/matrix_geometry.hpp
@@ -0,0 +1,47 @@
+/**
+ * @file matrix_geometry.hpp
+ * @author Maximilien Naveau (maximilien.naveau@gmail.com)
+ * @license License BSD-3-Clause
+ * @copyright Copyright (c) 2019, New York University and Max Planck
+ * Gesellschaft.
+ * @date 2019-05-22
+ */
+
+#ifndef MATRIX_GEOMETRY_HH
+#define MATRIX_GEOMETRY_HH
+
+#include <dynamic-graph/eigen-io.h>
+#include <dynamic-graph/linear-algebra.h>
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+#define MRAWDATA(x) x.data()
+
+namespace dynamic_graph_bridge
+{
+typedef Eigen::Transform<double, 3, Eigen::Affine> MatrixHomogeneous;
+typedef Eigen::Matrix<double, 3, 3> MatrixRotation;
+typedef Eigen::AngleAxis<double> VectorUTheta;
+typedef Eigen::Quaternion<double> VectorQuaternion;
+typedef Eigen::Vector3d VectorRotation;
+typedef Eigen::Vector3d VectorRollPitchYaw;
+typedef Eigen::Matrix<double, 6, 6> MatrixForce;
+typedef Eigen::Matrix<double, 6, 6> MatrixTwist;
+
+inline void buildFrom(const MatrixHomogeneous& MH, MatrixTwist& MT)
+{
+    Eigen::Vector3d _t = MH.translation();
+    MatrixRotation R(MH.linear());
+    Eigen::Matrix3d Tx;
+    Tx << 0, -_t(2), _t(1), _t(2), 0, -_t(0), -_t(1), _t(0), 0;
+    Eigen::Matrix3d sk;
+    sk = Tx * R;
+
+    MT.block<3, 3>(0, 0) = R;
+    MT.block<3, 3>(0, 3) = sk;
+    MT.block<3, 3>(3, 0).setZero();
+    MT.block<3, 3>(3, 3) = R;
+}
+}  // namespace dynamic_graph_bridge
+
+#endif  // MATRIX_GEOMETRY_HH
diff --git a/ros2/src/programs/geometric_simu.cpp b/ros2/src/programs/geometric_simu.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8dbe4459c9744f5dd00d8772883af3ebcf077734
--- /dev/null
+++ b/ros2/src/programs/geometric_simu.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011,
+ * Olivier Stasse,
+ *
+ * CNRS
+ *
+ */
+#include <iostream>
+
+
+#define ENABLE_RT_LOG
+#include <dynamic-graph/real-time-logger.h>
+
+#include <dynamic_graph_bridge/sot_loader.hh>
+#include <dynamic_graph_bridge/ros2_init.hh>
+
+int main(int argc, char *argv[]) {
+  ::dynamicgraph::RealTimeLogger::instance()
+    .addOutputStream(::dynamicgraph::LoggerStreamPtr_t(new dynamicgraph::LoggerIOStream(std::cout)));
+
+  rclcpp::init(argc, argv);
+
+  dynamicgraph::RosContext::SharedPtr aRosContext =
+    std::make_shared<dynamicgraph::RosContext>();
+
+  aRosContext->rosInit();
+
+  SotLoader aSotLoader;
+  if (aSotLoader.parseOptions(argc, argv) < 0) return -1;
+
+  // Advertize service "(start|stop)_dynamic_graph" and
+  // load parameter "robot_description in SoT.
+  aSotLoader.initializeFromRosContext(aRosContext);
+
+  // Load dynamic library and run python prologue.
+  aSotLoader.initPublication();
+
+  aSotLoader.initializeServices();
+
+  aRosContext->mtExecutor->spin();
+  return 0;
+}
diff --git a/ros2/src/ros.cpp b/ros2/src/ros.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b765654d703bf54e9059667f65748bb4fc44bda2
--- /dev/null
+++ b/ros2/src/ros.cpp
@@ -0,0 +1,332 @@
+/**
+ * @file ros_init.cpp
+ * @author Maximilien Naveau (maximilien.naveau@gmail.com)
+ * @license License BSD-3-Clause
+ * @copyright Copyright (c) 2019, New York University and Max Planck
+ * Gesellschaft.
+ * @date 2019-05-22
+ */
+
+#include <deque>
+#include <atomic>
+#include <fstream>
+#include <chrono>
+#include <thread>
+
+#include "dynamic_graph_bridge/ros.hpp"
+
+namespace dynamic_graph_bridge
+{
+/*
+ * Private methods
+ */
+
+/**
+ * @brief Shortcut.
+ */
+typedef std::map<std::string, RosNodePtr> GlobalListOfRosNodeType;
+
+/**
+ * @brief GLOBAL_LIST_OF_ROS_NODE is global variable that acts as a singleton on
+ * the ROS node handle and the spinner.
+ *
+ * The use of the std::unique_ptr allows to delete the object and re-create
+ * at will. It is usefull to reset the ros environment specifically for
+ * unittesting.
+ *
+ * If the node handle does not exist we call the global method rclcpp::init.
+ * This method has for purpose to initialize the ROS environment. The
+ * creation of ROS object is permitted only after the call of this function.
+ * After rclcpp::init being called we create the node handle which allows in
+ * turn to advertize the ROS services, or create topics (data pipe).
+ *
+ */
+static GlobalListOfRosNodeType GLOBAL_LIST_OF_ROS_NODE;
+
+/**
+ * @brief Small class allowing to start a ROS spin in a thread.
+ */
+class Executor
+{
+public:
+    Executor() : ros_executor_(rclcpp::executor::ExecutorArgs(), 4)
+    {
+        is_thread_running_ = false;
+        is_spinning_ = false;
+        list_node_added_.clear();
+    }
+
+    /**
+     * @brief Upon destruction close the thread and stop spinning.
+     *
+     * @return
+     */
+    ~Executor()
+    {
+        stop_spinning();
+    }
+
+    /**
+     * @brief Start ros_spin in a different thread to not block the current one.
+     */
+    void spin_non_blocking()
+    {
+        if (!is_thread_running_ && !is_spinning_)
+        {
+            std::cout << "Start ros spin in thread." << std::endl;
+            // Marking thread as started to avoid a second thread from getting
+            // started.
+            is_thread_running_ = true;
+            thread_ = std::thread(&Executor::thread_callback, this);
+        }
+    }
+
+    /**
+     * @brief Block the current thread and make ROS spinning.
+     */
+    void spin()
+    {
+        if (is_thread_running_)
+        {
+            while (ros_ok() && is_thread_running_)
+            {
+                std::this_thread::sleep_for(std::chrono::milliseconds(100));
+            }
+        }
+        else
+        {
+            is_spinning_ = true;
+            ros_executor_.spin();
+            is_spinning_ = false;
+        }
+    }
+
+    void add_node(const std::string& ros_node_name)
+    {
+        if (std::find(list_node_added_.begin(),
+                      list_node_added_.end(),
+                      ros_node_name) == list_node_added_.end())
+        {
+            list_node_added_.push_back(ros_node_name);
+            ros_executor_.add_node(get_ros_node(ros_node_name));
+        }
+    }
+
+    void remove_node(const std::string& ros_node_name)
+    {
+        std::deque<std::string>::iterator el = std::find(
+            list_node_added_.begin(), list_node_added_.end(), ros_node_name);
+        if (el != list_node_added_.end())
+        {
+            list_node_added_.erase(el);
+            assert(std::find(list_node_added_.begin(),
+                             list_node_added_.end(),
+                             ros_node_name) == list_node_added_.end() &&
+                   "The node has not been removed properly.");
+            ros_executor_.remove_node(get_ros_node(ros_node_name));
+        }
+    }
+
+    /**
+     * @brief Stop the spinning al together. Callable in a different thread.
+     */
+    void stop_spinning()
+    {
+        while (is_thread_running_ || is_spinning_)
+        {
+            ros_executor_.cancel();
+            std::this_thread::sleep_for(std::chrono::milliseconds(100));
+        }
+        if (thread_.joinable())
+        {
+            thread_.join();
+        }
+    }
+
+private:
+    /**
+     * @brief Thread callback function
+     */
+    void thread_callback()
+    {
+        ros_executor_.spin();
+        is_thread_running_ = false;
+    }
+
+    /**
+     * @brief Check if the thread is running.
+     */
+    std::atomic<bool> is_thread_running_;
+
+    /**
+     * @brief Check if the the executor is spinning.
+     */
+    std::atomic<bool> is_spinning_;
+
+    /**
+     * @brief Thread in which the EXECUTOR spins.
+     */
+    std::thread thread_;
+
+    /**
+     * @brief Object that execute the ROS callbacks in a different thread.
+     */
+    RosExecutor ros_executor_;
+
+    std::deque<std::string> list_node_added_;
+
+};  // class Executor
+
+typedef std::shared_ptr<Executor> ExecutorPtr;
+
+/**
+ * @brief EXECUTOR is a ros object that handles in a global way
+ * all the ros callbacks and interruption. Call EXECUTOR.spin()
+ * in order to start handling the callback in a separate thread.
+ */
+ExecutorPtr EXECUTOR = nullptr;
+
+/**
+ * @brief Private function that allow us to get the current executable name.
+ *
+ * @return std::string the current executable name.
+ */
+std::string executable_name()
+{
+#if defined(PLATFORM_POSIX) || \
+    defined(__linux__)  // check defines for your setup
+
+    std::string sp;
+    std::ifstream("/proc/self/comm") >> sp;
+    return sp;
+
+#elif defined(_WIN32)
+
+    char buf[MAX_PATH];
+    GetModuleFileNameA(nullptr, buf, MAX_PATH);
+    return buf;
+
+#else
+
+    static_assert(false, "unrecognized platform");
+
+#endif
+}
+
+/**
+ * @brief Private function that allow us to initialize ROS only once.
+ */
+void ros_init()
+{
+    if (!rclcpp::ok())
+    {
+        /** call rclcpp::init */
+        int argc = 1;
+        char* arg0 = strdup(executable_name().c_str());
+        char* argv[] = {arg0, nullptr};
+        rclcpp::init(argc, argv);
+        free(arg0);
+    }
+}
+
+/*
+ * Public Functions => user API, see ros.hpp for the docstrings.
+ */
+
+bool ros_node_exists(std::string node_name)
+{
+    if (GLOBAL_LIST_OF_ROS_NODE.find(node_name) ==
+        GLOBAL_LIST_OF_ROS_NODE.end())
+    {
+        return false;
+    }
+    if (GLOBAL_LIST_OF_ROS_NODE.at(node_name) == nullptr)
+    {
+        return false;
+    }
+    return true;
+}
+
+ExecutorPtr get_ros_executor()
+{
+    ros_init();
+    if (!EXECUTOR)
+    {
+        EXECUTOR = std::make_shared<Executor>();
+    }
+    return EXECUTOR;
+}
+
+RosNodePtr get_ros_node(std::string node_name)
+{
+    ros_init();
+    if (!ros_node_exists(node_name))
+    {
+        GLOBAL_LIST_OF_ROS_NODE[node_name] = RosNodePtr(nullptr);
+    }
+    if (!GLOBAL_LIST_OF_ROS_NODE[node_name] ||
+        GLOBAL_LIST_OF_ROS_NODE[node_name].get() == nullptr)
+    {
+        /** RosNode instanciation */
+        GLOBAL_LIST_OF_ROS_NODE[node_name] =
+            std::make_shared<RosNode>(node_name, "dynamic_graph_manager");
+    }
+    /** Return a reference to the node handle so any function can use it */
+    return GLOBAL_LIST_OF_ROS_NODE[node_name];
+}
+
+void ros_add_node_to_executor(const std::string& node_name)
+{
+    get_ros_executor()->add_node(node_name);
+}
+
+void ros_shutdown(std::string node_name)
+{
+    if (GLOBAL_LIST_OF_ROS_NODE.find(node_name) ==
+        GLOBAL_LIST_OF_ROS_NODE.end())
+    {
+        return;
+    }
+    get_ros_executor()->remove_node(node_name);
+    GLOBAL_LIST_OF_ROS_NODE.erase(node_name);
+}
+
+void ros_shutdown()
+{
+    // rclcpp::shutdown();
+}
+
+void ros_clean()
+{
+    ros_stop_spinning();
+    GlobalListOfRosNodeType::iterator ros_node_it =
+        GLOBAL_LIST_OF_ROS_NODE.begin();
+    while (!GLOBAL_LIST_OF_ROS_NODE.empty())
+    {
+        ros_shutdown(ros_node_it->first);
+        ros_node_it = GLOBAL_LIST_OF_ROS_NODE.begin();
+    }
+    GLOBAL_LIST_OF_ROS_NODE.clear();
+}
+
+bool ros_ok()
+{
+    return rclcpp::ok() && rclcpp::is_initialized();
+}
+
+void ros_spin()
+{
+    get_ros_executor()->spin();
+}
+
+void ros_spin_non_blocking()
+{
+    get_ros_executor()->spin_non_blocking();
+}
+
+void ros_stop_spinning()
+{
+    get_ros_executor()->stop_spinning();
+}
+
+}  // end of namespace dynamic_graph_bridge.
diff --git a/ros2/src/ros_parameter.cpp b/ros2/src/ros_parameter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..57dcfd180a1741bcb866552d99aabecae19ff54a
--- /dev/null
+++ b/ros2/src/ros_parameter.cpp
@@ -0,0 +1,60 @@
+#include <sot/core/robot-utils.hh>
+
+#include "pinocchio/multibody/model.hpp"
+#include "pinocchio/parsers/urdf.hpp"
+
+#include <stdexcept>
+#include <boost/make_shared.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <urdf_parser/urdf_parser.h>
+
+#include "dynamic_graph_bridge/ros_parameter.hpp"
+
+namespace dynamicgraph {
+  bool parameter_server_read_robot_description(rclcpp::Node::SharedPtr nh)
+  {
+
+    if (!nh->has_parameter("robot_description"))
+      {
+        nh->declare_parameter("robot_description",std::string(""));
+      }
+    
+    std::string robot_description;
+    std::string parameter_name("robot_description");
+    nh->get_parameter(parameter_name,robot_description);
+    if (robot_description.empty())
+      {
+        RCLCPP_FATAL(rclcpp::get_logger("dynamic_graph_bridge"),
+                     "Parameter robot_description is empty");
+        return false;
+      }
+    
+    std::string model_name("robot");
+    
+    // Search for the robot util related to robot_name.
+    sot::RobotUtilShrPtr aRobotUtil = sot::getRobotUtil(model_name);
+    // If does not exist then it is created.
+    if (aRobotUtil == sot::RefVoidRobotUtil())
+      aRobotUtil = sot::createRobotUtil(model_name);
+
+    // If the creation is fine
+    if (aRobotUtil != sot::RefVoidRobotUtil())
+      {
+        // Then set the robot model.
+        aRobotUtil->set_parameter(parameter_name,robot_description);
+        RCLCPP_INFO(rclcpp::get_logger("dynamic_graph_bridge"),
+                    "Set parameter_name : %s.",parameter_name.c_str());
+        // Everything went fine.
+        return true;
+      }
+    RCLCPP_FATAL(rclcpp::get_logger("dynamic_graph_bridge"),
+                 "Wrong initialization of parameter_name %s",
+                 parameter_name.c_str());
+
+    // Otherwise something went wrong.
+    return false;
+
+  }
+
+}
diff --git a/ros2/src/ros_publish-python-module-py.cc b/ros2/src/ros_publish-python-module-py.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5134a7873eea588da3f1d675f6e8716ee6ef0dfe
--- /dev/null
+++ b/ros2/src/ros_publish-python-module-py.cc
@@ -0,0 +1,19 @@
+#include <dynamic-graph/python/module.hh>
+#include "ros_publish.hh"
+
+namespace dg = dynamicgraph;
+
+BOOST_PYTHON_MODULE(wrap)
+{
+  bp::import("dynamic_graph");
+
+  dg::python::exposeEntity<dg::RosPublish, bp::bases<dg::Entity>,
+                           dg::python::AddCommands>()
+      .def("clear", &dg::RosPublish::clear,
+           "Remove all signals writing data to a ROS topic")
+      .def("rm", &dg::RosPublish::rm,
+           "Remove a signal writing data to a ROS topic",
+           bp::args("signal_name"))
+      .def("list", &dg::RosPublish::list,
+           "List signals writing data to a ROS topic");
+}
diff --git a/ros2/src/ros_publish.cpp b/ros2/src/ros_publish.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8bbd45972c14ffa3a43fb78a755beb4c227a393f
--- /dev/null
+++ b/ros2/src/ros_publish.cpp
@@ -0,0 +1,310 @@
+/**
+ * @file
+ * @license BSD 3-clause
+ * @copyright Copyright (c) 2020, New York University and Max Planck
+ * Gesellschaft
+ *
+ * @brief Implements the RosPublish class.
+ */
+
+#include "dynamic_graph_bridge/ros_entities/ros_publish.hpp"
+
+#include "dynamic_graph_bridge/ros.hpp"
+
+namespace dynamic_graph_bridge
+{
+/*
+ * RosPublish class
+ */
+
+const std::string RosPublish::doc_string_ =
+    "Publish dynamic-graph signals as ROS topics.\n"
+    "\n"
+    "  Use command \"add\" to publish a new ROS topic.\n";
+
+const std::string RosPublish::trigger_signal_name_ = "trigger";
+
+DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(RosPublish, "RosPublish");
+
+RosPublish::RosPublish(const std::string& n)
+    : dynamicgraph::Entity(n),
+      trigger_(boost::bind(&RosPublish::trigger, this, _1, _2),
+               dynamicgraph::sotNOSIGNAL,
+               make_signal_string(*this, true, "int", trigger_signal_name_)),
+      rate_nanosec_(std::chrono::nanoseconds(50000000))  // 50ms
+{
+    signalRegistration(trigger_);
+
+    ros_node_ = get_ros_node(DG_ROS_NODE_NAME);
+    ros_add_node_to_executor(DG_ROS_NODE_NAME);
+    ros_spin_non_blocking();
+    binded_signals_.clear();
+    /** @todo Check this needUpdateFromAllChildren */
+    trigger_.setNeedUpdateFromAllChildren(true);
+    try
+    {
+        last_publicated_ = ros_node_->get_clock()->now();
+    }
+    catch (const std::exception& exc)
+    {
+        throw std::runtime_error(
+            "Failed to call ros_node_->get_clock()->now():" +
+            std::string(exc.what()));
+    }
+    mutex_.unlock();
+
+    std::string doc_string;
+    doc_string =
+        "\n"
+        "  Add a signal writing data to a ROS topic.\n"
+        "\n"
+        "  Input:\n"
+        "    - type: string among:\n";
+    for (unsigned int i = 0; i < DgRosTypes::type_list.size(); ++i)
+    {
+        doc_string += "        - " + DgRosTypes::type_list[i] + "\n";
+    }
+    doc_string +=
+        "    - signal: the signal name in dynamic-graph,\n"
+        "    - topic:  the topic name in ROS.\n"
+        "\n";
+    addCommand("add", new command::ros_publish::Add(*this, doc_string));
+    doc_string =
+        "\n"
+        "  Remove a signal writing data to a ROS topic.\n"
+        "\n"
+        "  Input:\n"
+        "    - name of the signal to remove (see method list for the list of "
+        "signals).\n"
+        "\n";
+    addCommand("rm", new command::ros_publish::Rm(*this, doc_string));
+    doc_string =
+        "\n"
+        "  Remove all signals writing data to a ROS topic.\n"
+        "\n"
+        "  No input.\n"
+        "\n";
+    addCommand("clear", new command::ros_publish::Clear(*this, doc_string));
+    doc_string =
+        "\n"
+        "  List signals writing data to a ROS topic.\n"
+        "\n"
+        "  No input.\n"
+        "\n";
+    addCommand("list", new command::ros_publish::List(*this, doc_string));
+}  // namespace dynamic_graph_bridge
+
+RosPublish::~RosPublish()
+{
+}
+
+void RosPublish::display(std::ostream& os) const
+{
+    os << this->CLASS_NAME << "(" << this->name << ")." << std::endl;
+}
+
+void RosPublish::rm(const std::string& signal)
+{
+    if (binded_signals_.find(signal) == binded_signals_.end())
+    {
+        return;
+    }
+
+    if (signal == trigger_signal_name_)
+    {
+        std::cerr << "The trigger signal should not be removed. Aborting."
+                  << std::endl;
+        return;
+    }
+
+    // lock the mutex to avoid deleting the signal during a call to trigger
+    while (!mutex_.try_lock())
+    {
+    }
+    signalDeregistration(signal);
+    binded_signals_.erase(signal);
+    mutex_.unlock();
+}
+
+std::string RosPublish::list() const
+{
+    std::string result("[");
+    for (std::map<std::string, BindedSignal>::const_iterator it =
+             binded_signals_.begin();
+         it != binded_signals_.end();
+         it++)
+    {
+        result += "'" + it->first + "',";
+    }
+    result += "]";
+    return result;
+}
+
+void RosPublish::clear()
+{
+    std::map<std::string, BindedSignal>::iterator it = binded_signals_.begin();
+    for (; it != binded_signals_.end();)
+    {
+        if (it->first != trigger_signal_name_)
+        {
+            rm(it->first);
+            it = binded_signals_.begin();
+        }
+        else
+        {
+            ++it;
+        }
+    }
+}
+
+int& RosPublish::trigger(int& dummy, int)
+{
+    typedef std::map<std::string, BindedSignal>::iterator iterator_t;
+
+    // If we did not wait long enough (> rate_nanosec_), we do nothing.
+    rclcpp::Duration dt = ros_node_->get_clock()->now() - last_publicated_;
+    if (dt < rate_nanosec_)
+    {
+        return dummy;
+    }
+
+    // We reset the previous publishing time as "now".
+    last_publicated_ = ros_node_->get_clock()->now();
+
+    // We lock the mutex for the full duration of the publication.
+    mutex_.lock();
+    for (iterator_t it = binded_signals_.begin(); it != binded_signals_.end();
+         ++it)
+    {
+        // calling the callback corresponding to the input signal in the tuple.
+        std::get<1>(it->second)();
+    }
+    mutex_.unlock();
+    return dummy;
+}
+
+std::string RosPublish::getDocString() const
+{
+    return doc_string_;
+}
+
+/*
+ * RosPublish command
+ */
+namespace command
+{
+namespace ros_publish
+{
+Clear::Clear(RosPublish& entity, const std::string& doc_string)
+    : Command(entity, std::vector<Value::Type>(), doc_string)
+{
+}
+
+Value Clear::doExecute()
+{
+    RosPublish& entity = static_cast<RosPublish&>(owner());
+
+    entity.clear();
+    return Value();
+}
+
+List::List(RosPublish& entity, const std::string& doc_string)
+    : Command(entity, std::vector<Value::Type>(), doc_string)
+{
+}
+
+Value List::doExecute()
+{
+    RosPublish& entity = static_cast<RosPublish&>(owner());
+    return Value(entity.list());
+}
+
+Add::Add(RosPublish& entity, const std::string& doc_string)
+    : Command(
+          entity,
+          boost::assign::list_of(Value::STRING)(Value::STRING)(Value::STRING),
+          doc_string)
+{
+}
+
+Value Add::doExecute()
+{
+    RosPublish& entity = static_cast<RosPublish&>(owner());
+    std::vector<Value> values = getParameterValues();
+
+    const std::string& type = values[0].value();
+    const std::string& signal = values[1].value();
+    const std::string& topic = values[2].value();
+
+    if (type == DgRosTypes::get_double())
+    {
+        entity.add<std_msgs::msg::Float64, double>(signal, topic);
+    }
+    else if (type == DgRosTypes::get_unsigned())
+    {
+        entity.add<std_msgs::msg::UInt32, unsigned int>(signal, topic);
+    }
+    else if (type == DgRosTypes::get_matrix())
+    {
+        entity.add<RosMatrix, DgMatrix>(signal, topic);
+    }
+    else if (type == DgRosTypes::get_vector())
+    {
+        entity.add<RosVector, DgVector>(signal, topic);
+    }
+    else if (type == DgRosTypes::get_vector3())
+    {
+        entity.add<geometry_msgs::msg::Vector3, DgVector>(signal, topic);
+    }
+    else if (type == DgRosTypes::get_vector3_stamped())
+    {
+        entity.add<geometry_msgs::msg::Vector3Stamped, DgVector>(signal, topic);
+    }
+    else if (type == DgRosTypes::get_matrix_homogeneous())
+    {
+        entity.add<geometry_msgs::msg::Transform, MatrixHomogeneous>(signal,
+                                                                     topic);
+    }
+    else if (type == DgRosTypes::get_matrix_homogeneous_stamped())
+    {
+        entity.add<geometry_msgs::msg::TransformStamped, MatrixHomogeneous>(
+            signal, topic);
+    }
+    else if (type == DgRosTypes::get_twist())
+    {
+        entity.add<geometry_msgs::msg::Twist, DgVector>(signal, topic);
+    }
+    else if (type == DgRosTypes::get_twist_stamped())
+    {
+        entity.add<geometry_msgs::msg::TwistStamped, DgVector>(signal, topic);
+    }
+    else
+    {
+        std::cerr << "RosPublish(" << entity.getName()
+                  << ")::add(): bad type given (" << type << ")."
+                  << " Possible choice is among:";
+        for (unsigned int i = 0; i < DgRosTypes::type_list.size(); ++i)
+        {
+            std::cerr << "    - " << DgRosTypes::type_list[i] << std::endl;
+        }
+    }
+    return Value();
+}
+
+Rm::Rm(RosPublish& entity, const std::string& doc_string)
+    : Command(entity, boost::assign::list_of(Value::STRING), doc_string)
+{
+}
+
+Value Rm::doExecute()
+{
+    RosPublish& entity = static_cast<RosPublish&>(owner());
+    std::vector<Value> values = getParameterValues();
+    const std::string& signal = values[0].value();
+    entity.rm(signal);
+    return Value();
+}
+}  // namespace ros_publish
+}  // end of namespace command.
+
+}  // namespace dynamic_graph_bridge
diff --git a/ros2/src/ros_publish.hpp b/ros2/src/ros_publish.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..edb4f6ccc014540f9a0dcd3f587be85e0978e712
--- /dev/null
+++ b/ros2/src/ros_publish.hpp
@@ -0,0 +1,182 @@
+/**
+ * @file
+ * @license BSD 3-clause
+ * @copyright Copyright (c) 2020, New York University and Max Planck
+ * Gesellschaft
+ *
+ * @brief Declare the RosPublish class.
+ */
+
+#pragma once
+
+#include <dynamic-graph/command.h>
+#include <dynamic-graph/entity.h>
+#include <dynamic-graph/factory.h>
+#include <dynamic-graph/signal-time-dependent.h>
+
+#include <iostream>
+#include <map>
+#include <mutex>
+
+#include "dynamic_graph_bridge/ros_entities/dg_ros_mapping.hpp"
+
+namespace dynamic_graph_bridge
+{
+/** @brief Publish dynamic-graph information into ROS. */
+class RosPublish : public dynamicgraph::Entity
+{
+    DYNAMIC_GRAPH_ENTITY_DECL();
+
+public:
+    /**
+     * @brief Callback function publishing in the ROS topic.
+     * This callback is called during the trigger signal callback function.
+     */
+    typedef std::function<void(void)> PublisherCallback;
+
+    /**
+     * @brief Tuple composed by the generated input signal and its callback
+     * function. The callback function publishes the input signal content.
+     */
+    typedef std::tuple<std::shared_ptr<dynamicgraph::SignalBase<int> >,
+                       PublisherCallback>
+        BindedSignal;
+
+    /**
+     * @brief Construct a new RosPublish object.
+     *
+     * @param n
+     */
+    RosPublish(const std::string& n);
+
+    /**
+     * @brief Destroy the RosPublish object.
+     *
+     */
+    virtual ~RosPublish();
+
+    /**
+     * @brief Get the documentation string.
+     *
+     * @return std::string
+     */
+    virtual std::string getDocString() const;
+
+    /**
+     * @brief Display the class information.
+     *
+     * @param os
+     */
+    void display(std::ostream& os) const;
+
+    /**
+     * @brief Add a signal to publish to ROS.
+     *
+     * @tparam RosType type of the ROS message.
+     * @tparam DgType type of the Dynamic Graph signal data.
+     * @param signal name.
+     * @param topic name.
+     */
+    template <typename RosType, typename DgType>
+    void add(const std::string& signal, const std::string& topic);
+
+    /**
+     * @brief Remove a signal to publish to ROS.
+     *
+     * @param signal name.
+     */
+    void rm(const std::string& signal);
+
+    /**
+     * @brief List of all signal and topics currently published.
+     *
+     * @return std::string
+     */
+    std::string list() const;
+
+    /**
+     * @brief Remove all signal published to ROS.
+     */
+    void clear();
+
+private:
+    /**
+     * @brief Trigger signal callback method.
+     *
+     * @return int&
+     */
+    int& trigger(int&, int);
+
+    /**
+     * @brief Send the data from the input signal to the ROS topic.
+     *
+     * @tparam RosType ROS message type.
+     * @tparam DgType Dynamic graph signal data type.
+     * @param publisher pointer to the ros publisher.
+     * @param signal signal name.
+     */
+    template <typename RosType, typename DgType>
+    void send_data(
+        std::shared_ptr<rclcpp::Publisher<
+            typename DgRosMapping<RosType, DgType>::ros_t> > publisher,
+        std::shared_ptr<typename DgRosMapping<RosType, DgType>::signal_in_t>
+            signal);
+
+private:
+    /** @brief Doc string associated to the entity. */
+    static const std::string doc_string_;
+
+    /** @brief Name of the trigger signal. */
+    static const std::string trigger_signal_name_;
+
+    /** @brief Trigger signal publishing the signal values every other
+     * iterations. */
+    dynamicgraph::SignalTimeDependent<int, int> trigger_;
+
+    /** @brief Publishing rate. Default is 50ms. */
+    rclcpp::Duration rate_nanosec_;
+
+    /** @brief ROS node pointer. */
+    RosNodePtr ros_node_;
+
+    /** @brief Named list of signals associated with it's callback functions. */
+    std::map<std::string, BindedSignal> binded_signals_;
+
+    /** @brief Last published time. */
+    rclcpp::Time last_publicated_;
+
+    /** @brief Protects the command and trigger callbacks. */
+    std::mutex mutex_;
+};
+
+/*
+ * Commands
+ */
+namespace command
+{
+namespace ros_publish
+{
+using ::dynamicgraph::command::Command;
+using ::dynamicgraph::command::Value;
+
+#define ROS_PUBLISH_MAKE_COMMAND(CMD)                          \
+    class CMD : public Command                                 \
+    {                                                          \
+    public:                                                    \
+        CMD(RosPublish& entity, const std::string& docstring); \
+        virtual Value doExecute();                             \
+    }
+
+ROS_PUBLISH_MAKE_COMMAND(Add);
+ROS_PUBLISH_MAKE_COMMAND(Clear);
+ROS_PUBLISH_MAKE_COMMAND(List);
+ROS_PUBLISH_MAKE_COMMAND(Rm);
+
+#undef ROS_PUBLISH_MAKE_COMMAND
+
+}  // namespace ros_publish
+}  // end of namespace command.
+
+}  // namespace dynamic_graph_bridge
+
+#include "ros_publish.hxx"
diff --git a/ros2/src/ros_publish.hxx b/ros2/src/ros_publish.hxx
new file mode 100644
index 0000000000000000000000000000000000000000..8e1422cd84d5921442bc595282c99ed68839b2df
--- /dev/null
+++ b/ros2/src/ros_publish.hxx
@@ -0,0 +1,59 @@
+/**
+ * @file
+ * @license BSD 3-clause
+ * @copyright Copyright (c) 2020, New York University and Max Planck
+ * Gesellschaft
+ *
+ * @brief Implements the template method of the RosPublish class.
+ */
+
+#pragma once
+
+#include "dynamic_graph_bridge/ros_entities/dg_ros_mapping.hpp"
+
+namespace dynamic_graph_bridge
+{
+template <typename RosType, typename DgType>
+void RosPublish::send_data(
+    std::shared_ptr<rclcpp::Publisher<
+        typename DgRosMapping<RosType, DgType>::ros_t> > publisher,
+    std::shared_ptr<typename DgRosMapping<RosType, DgType>::signal_in_t> signal)
+{
+    typename DgRosMapping<RosType, DgType>::ros_t msg;
+    DgRosMapping<RosType, DgType>::dg_to_ros(signal->accessCopy(), msg);
+    publisher->publish(msg);
+}
+
+template <typename RosType, typename DgType>
+void RosPublish::add(const std::string& signal, const std::string& topic)
+{
+    using ros_t = typename DgRosMapping<RosType, DgType>::ros_t;
+    using signal_in_t = typename DgRosMapping<RosType, DgType>::signal_in_t;
+
+    // Initialize the bindedSignal object.
+    BindedSignal binded_signal;
+
+    // Initialize the publisher.
+    std::shared_ptr<rclcpp::Publisher<ros_t> > pub_ptr =
+        ros_node_->create_publisher<ros_t>(topic, 10);
+
+    // Initialize the signal.
+    std::shared_ptr<signal_in_t> signal_ptr = std::make_shared<signal_in_t>(
+        nullptr,  // no explicit dependence
+        make_signal_string(*this,
+                           true,
+                           DgRosMapping<RosType, DgType>::signal_type_name,
+                           signal));
+    std::get<0>(binded_signal) = signal_ptr;
+    DgRosMapping<RosType, DgType>::set_default(signal_ptr);
+    signalRegistration(*std::get<0>(binded_signal));
+
+    // Initialize the callback.
+    PublisherCallback callback = std::bind(
+        &RosPublish::send_data<RosType, DgType>, this, pub_ptr, signal_ptr);
+    std::get<1>(binded_signal) = callback;
+
+    binded_signals_[signal] = binded_signal;
+}
+
+}  // namespace dynamic_graph_bridge
diff --git a/ros2/src/ros_python_interpreter_client.cpp b/ros2/src/ros_python_interpreter_client.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..487001698661ca0aac29bb6b9037a8c3f776e513
--- /dev/null
+++ b/ros2/src/ros_python_interpreter_client.cpp
@@ -0,0 +1,157 @@
+/**
+ * @file
+ * @license BSD 3-clause
+ * @copyright Copyright (c) 2020, New York University and Max Planck
+ * Gesellschaft
+ *
+ * @brief Defines a C++ interface for the ros-service of the dynamic-graph
+ * python interpreter. (Available in python through bindings.)
+ */
+
+#include "dynamic_graph_bridge/ros_python_interpreter_client.hpp"
+
+#include <boost/algorithm/string.hpp>
+#include <fstream>
+
+namespace dynamic_graph_bridge
+{
+RosPythonInterpreterClient::RosPythonInterpreterClient()
+{
+    ros_node_name_ = "ros_python_interpreter_client";
+    ros_node_ = get_ros_node(ros_node_name_);
+
+    // Create a client for the single python command service of the
+    // DynamicGraphManager.
+    run_command_service_name_ = "/dynamic_graph_manager/run_python_command";
+    run_command_request_ = std::make_shared<RunPythonCommandSrvType::Request>();
+    connect_to_rosservice_run_python_command();
+
+    // Create a client for the python file reading service of the
+    // DynamicGraphManager.
+    run_script_service_name_ = "/dynamic_graph_manager/run_python_file";
+    run_file_request_ = std::make_shared<RunPythonFileSrvType::Request>();
+    connect_to_rosservice_run_python_script();
+    timeout_connection_s_ = DurationSec(1);
+}
+
+std::string RosPythonInterpreterClient::run_python_command(
+    const std::string& code_string)
+{
+    std::string return_string = "";
+
+    // If the code is empty or just a line break, return an empty string.
+    if (code_string == "" || code_string == "\n")
+    {
+        return return_string;
+    }
+
+    try
+    {
+        if (!command_client_->wait_for_service(timeout_connection_s_))
+        {
+            RCLCPP_INFO(rclcpp::get_logger("RosPythonInterpreterClient"),
+                        "Connection to remote server lost. Reconnecting...");
+            connect_to_rosservice_run_python_command(timeout_connection_s_);
+            return return_string;
+        }
+
+        run_command_request_->input = code_string;
+
+        auto response =
+            command_client_->async_send_request(run_command_request_);
+        // Wait for the result.
+        while (rclcpp::ok() &&
+               rclcpp::spin_until_future_complete(
+                   ros_node_, response, std::chrono::seconds(1)) !=
+                   rclcpp::executor::FutureReturnCode::SUCCESS)
+        {
+            RCLCPP_ERROR(rclcpp::get_logger("rclcpp"),
+                         "Error while parsing command, retrying...");
+        }
+
+        // Get the standard output (print).
+        return_string += response.get()->standardoutput;
+
+        // Get the error.
+        return_string += response.get()->standarderror;
+
+        // Get the Result and print it is any.
+        if (response.get()->result != "None")
+        {
+            return_string += response.get()->result;
+        }
+    }
+    catch (const std::exception& ex)
+    {
+        RCLCPP_INFO(rclcpp::get_logger("RosPythonInterpreterClient"),
+                    ex.what());
+        connect_to_rosservice_run_python_command(timeout_connection_s_);
+    }
+    catch (...)
+    {
+        RCLCPP_INFO(rclcpp::get_logger("RosPythonInterpreterClient"),
+                    "Error caught, maybe the connection to remote server is "
+                    "lost. Reconnecting...");
+        connect_to_rosservice_run_python_command(timeout_connection_s_);
+    }
+    return return_string;
+}  // namespace dynamic_graph_bridge
+
+std::string RosPythonInterpreterClient::run_python_script(
+    const std::string& filename)
+{
+    std::string return_string = "";
+
+    std::ifstream file_if(filename.c_str());
+    if (!file_if.good())
+    {
+        RCLCPP_INFO(rclcpp::get_logger("RosPythonInterpreterClient"),
+                    "Provided file does not exist: %s",
+                    filename.c_str());
+        return return_string;
+    }
+
+    try
+    {
+        if (!script_client_->wait_for_service(timeout_connection_s_))
+        {
+            RCLCPP_INFO(rclcpp::get_logger("RosPythonInterpreterClient"),
+                        "Connection to remote server lost. Reconnecting...");
+            connect_to_rosservice_run_python_script(timeout_connection_s_);
+            return return_string;
+        }
+
+        run_file_request_->input = filename;
+
+        auto response = script_client_->async_send_request(run_file_request_);
+
+        if (rclcpp::spin_until_future_complete(ros_node_, response) ==
+            rclcpp::executor::FutureReturnCode::SUCCESS)
+        {
+            // Get the error.
+            return_string += response.get()->result;
+
+            // Get the Result and print it is any.
+            return_string += response.get()->result;
+            if (!boost::algorithm::ends_with(return_string, "\n"))
+            {
+                return_string += "\n";
+            }
+        }
+        else
+        {
+            // We had an issue calling the service.
+            RCLCPP_INFO(rclcpp::get_logger("RosPythonInterpreterClient"),
+                        "Error while parsing scripts.");
+        }
+    }
+    catch (...)
+    {
+        RCLCPP_INFO(rclcpp::get_logger("RosPythonInterpreterClient"),
+                    "Connection to remote server lost. Reconnecting...");
+        connect_to_rosservice_run_python_script(timeout_connection_s_);
+    }
+    return return_string;
+}
+
+}  // namespace dynamic_graph_bridge
\ No newline at end of file
diff --git a/ros2/src/ros_python_interpreter_server.cpp b/ros2/src/ros_python_interpreter_server.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..aa7ddb4b9963f30486eceeec8e95276c85363af3
--- /dev/null
+++ b/ros2/src/ros_python_interpreter_server.cpp
@@ -0,0 +1,96 @@
+/**
+ * @file ros_interpreter.cpp
+ * @author Maximilien Naveau (maximilien.naveau@gmail.com)
+ * @license License BSD-3-Clause
+ * @copyright Copyright (c) 2019, New York University and Max Planck
+ * Gesellschaft.
+ * @date 2019-05-22
+ */
+
+#include "dynamic_graph_bridge/ros_python_interpreter_server.hpp"
+
+#include <boost/algorithm/string/predicate.hpp>
+#include <functional>
+#include <memory>
+
+namespace dynamic_graph_bridge
+{
+static const int queueSize = 5;
+
+RosPythonInterpreterServer::RosPythonInterpreterServer()
+    : interpreter_(),
+      ros_node_(get_ros_node("python_interpreter")),
+      run_python_command_srv_(nullptr),
+      run_python_file_srv_(nullptr)
+{
+    ros_add_node_to_executor("python_interpreter");
+}
+
+RosPythonInterpreterServer::~RosPythonInterpreterServer()
+{
+}
+
+void RosPythonInterpreterServer::start_ros_service()
+{
+    run_python_command_callback_t runCommandCb =
+        std::bind(&RosPythonInterpreterServer::runCommandCallback,
+                  this,
+                  std::placeholders::_1,
+                  std::placeholders::_2);
+    run_python_command_srv_ =
+        ros_node_->create_service<RunPythonCommandSrvType>("run_python_command",
+                                                           runCommandCb);
+
+    run_python_file_callback_t runPythonFileCb =
+        std::bind(&RosPythonInterpreterServer::runPythonFileCallback,
+                  this,
+                  std::placeholders::_1,
+                  std::placeholders::_2);
+    run_python_file_srv_ = ros_node_->create_service<RunPythonFileSrvType>(
+        "run_python_file", runPythonFileCb);
+}
+
+void RosPythonInterpreterServer::runCommandCallback(
+    RunPythonCommandRequestPtr req, RunPythonCommandResponsePtr res)
+{
+    std::stringstream buffer;
+    std::streambuf* old = std::cout.rdbuf(buffer.rdbuf());
+
+    run_python_command(
+        req->input, res->result, res->standardoutput, res->standarderror);
+
+    if (!buffer.str().empty())
+    {
+        if (!boost::algorithm::ends_with(res->standardoutput, "\n") &&
+            !res->standardoutput.empty())
+        {
+            res->standardoutput += "\n";
+        }
+        res->standardoutput += buffer.str();
+    }
+    std::cout.rdbuf(old);
+
+    std::cout << res->standardoutput << std::endl;
+}
+
+void RosPythonInterpreterServer::runPythonFileCallback(
+    RunPythonFileRequestPtr req, RunPythonFileResponsePtr res)
+{
+    run_python_file(req->input, res->result);
+}
+
+void RosPythonInterpreterServer::run_python_command(const std::string& command,
+                                                    std::string& result,
+                                                    std::string& out,
+                                                    std::string& err)
+{
+    interpreter_.python(command, result, out, err);
+}
+
+void RosPythonInterpreterServer::run_python_file(const std::string ifilename,
+                                                 std::string& result)
+{
+    interpreter_.runPythonFile(ifilename, result);
+}
+
+}  // namespace dynamic_graph_bridge
diff --git a/ros2/src/ros_sot_loader.cpp b/ros2/src/ros_sot_loader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/ros2/src/ros_subscribe-python-module-py.cc b/ros2/src/ros_subscribe-python-module-py.cc
new file mode 100644
index 0000000000000000000000000000000000000000..dd02bf58baa17f86841cadfdaeecf56bd6abe0c4
--- /dev/null
+++ b/ros2/src/ros_subscribe-python-module-py.cc
@@ -0,0 +1,19 @@
+#include <dynamic-graph/python/module.hh>
+#include "ros_subscribe.hh"
+
+namespace dg = dynamicgraph;
+
+BOOST_PYTHON_MODULE(wrap)
+{
+  bp::import("dynamic_graph");
+
+  dg::python::exposeEntity<dg::RosSubscribe, bp::bases<dg::Entity>,
+                           dg::python::AddCommands>()
+      .def("clear", &dg::RosSubscribe::clear,
+           "Remove all signals reading data from a ROS topic")
+      .def("rm", &dg::RosSubscribe::rm,
+           "Remove a signal reading data from a ROS topic",
+           bp::args("signal_name"))
+      .def("list", &dg::RosSubscribe::list,
+           "List signals reading data from a ROS topic");
+}
diff --git a/ros2/src/ros_subscribe.cpp b/ros2/src/ros_subscribe.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bf0220003ec2dca66bc0a6e9238b2562634f225d
--- /dev/null
+++ b/ros2/src/ros_subscribe.cpp
@@ -0,0 +1,252 @@
+/**
+ * @file ros_subscribe.cpp
+ * @author Maximilien Naveau (maximilien.naveau@gmail.com)
+ * @license License BSD-3-Clause
+ * @copyright Copyright (c) 2019, New York University and Max Planck
+ * Gesellschaft.
+ * @date 2019-05-22
+ */
+
+#include "dynamic_graph_bridge/ros_entities/ros_subscribe.hpp"
+
+#include <dynamic-graph/factory.h>
+
+#include "dynamic_graph_bridge/dynamic_graph_manager.hpp"
+
+namespace dynamic_graph_bridge
+{
+/*
+ * RosSubscribe
+ */
+DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(RosSubscribe, "RosSubscribe");
+
+const std::string RosSubscribe::doc_string_(
+    "Subscribe to a ROS topics and convert it into a dynamic-graph signals.\n"
+    "\n"
+    "  Use command \"add\" to subscribe to a new signal.\n");
+
+RosSubscribe::RosSubscribe(const std::string& n) : dynamicgraph::Entity(n)
+{
+    ros_node_ = get_ros_node(DG_ROS_NODE_NAME);
+    ros_add_node_to_executor(DG_ROS_NODE_NAME);
+    ros_spin_non_blocking();
+    binded_signals_.clear();
+    std::string doc_string =
+        "\n"
+        "  Add a signal reading data from a ROS topic.\n"
+        "\n"
+        "  Input:\n"
+        "    - type: string among:\n";
+    for (unsigned int i = 0; i < DgRosTypes::type_list.size(); ++i)
+    {
+        doc_string += "        - " + DgRosTypes::type_list[i] + "\n";
+    }
+    doc_string +=
+        "    - signal: the signal name in dynamic-graph,\n"
+        "    - topic:  the topic name in ROS.\n"
+        "\n";
+    addCommand("add", new command::ros_subscribe::Add(*this, doc_string));
+    doc_string =
+        "\n"
+        "  Remove a signal reading data from a ROS topic\n"
+        "\n"
+        "  Input:\n"
+        "    - name of the signal to remove (see method list for the list of "
+        "signals).\n"
+        "\n";
+    addCommand("rm", new command::ros_subscribe::Rm(*this, doc_string));
+    doc_string =
+        "\n"
+        "  Remove all signals reading data from a ROS topic\n"
+        "\n"
+        "  No input:\n"
+        "\n";
+    addCommand("clear", new command::ros_subscribe::Clear(*this, doc_string));
+    doc_string =
+        "\n"
+        "  List signals reading data from a ROS topic\n"
+        "\n"
+        "  No input:\n"
+        "\n";
+    addCommand("list", new command::ros_subscribe::List(*this, doc_string));
+}
+
+RosSubscribe::~RosSubscribe()
+{
+    clear();
+}
+
+void RosSubscribe::display(std::ostream& os) const
+{
+    os << CLASS_NAME << std::endl;
+}
+
+void RosSubscribe::rm(const std::string& signal)
+{
+    std::string signalTs = signal + "Timestamp";
+
+    signalDeregistration(signal);
+    binded_signals_.erase(signal);
+
+    if (binded_signals_.find(signalTs) != binded_signals_.end())
+    {
+        signalDeregistration(signalTs);
+        binded_signals_.erase(signalTs);
+    }
+}
+
+std::string RosSubscribe::list()
+{
+    std::string result("[");
+    for (std::map<std::string, BindedSignal>::const_iterator it =
+             binded_signals_.begin();
+         it != binded_signals_.end();
+         it++)
+    {
+        result += "'" + it->first + "',";
+    }
+    result += "]";
+    return result;
+}
+
+void RosSubscribe::clear()
+{
+    std::map<std::string, BindedSignal>::iterator it = binded_signals_.begin();
+    for (; it != binded_signals_.end();)
+    {
+        rm(it->first);
+        it = binded_signals_.begin();
+    }
+}
+
+std::string RosSubscribe::getDocString() const
+{
+    return doc_string_;
+}
+
+/*
+ * Commands
+ */
+
+namespace command
+{
+namespace ros_subscribe
+{
+Clear::Clear(RosSubscribe& entity, const std::string& doc_string)
+    : Command(entity, std::vector<Value::Type>(), doc_string)
+{
+}
+
+Value Clear::doExecute()
+{
+    RosSubscribe& entity = static_cast<RosSubscribe&>(owner());
+
+    entity.clear();
+    return Value();
+}
+
+List::List(RosSubscribe& entity, const std::string& doc_string)
+    : Command(entity, std::vector<Value::Type>(), doc_string)
+{
+}
+
+Value List::doExecute()
+{
+    RosSubscribe& entity = static_cast<RosSubscribe&>(owner());
+    return Value(entity.list());
+}
+
+Add::Add(RosSubscribe& entity, const std::string& doc_string)
+    : Command(
+          entity,
+          boost::assign::list_of(Value::STRING)(Value::STRING)(Value::STRING),
+          doc_string)
+{
+}
+
+Value Add::doExecute()
+{
+    RosSubscribe& entity = static_cast<RosSubscribe&>(owner());
+    std::vector<Value> values = getParameterValues();
+
+    const std::string& type = values[0].value();
+    const std::string& signal_name = values[1].value();
+    const std::string& topic_name = values[2].value();
+
+    if (type == DgRosTypes::get_double())
+    {
+        entity.add<std_msgs::msg::Float64, double>(signal_name, topic_name);
+    }
+    else if (type == DgRosTypes::get_unsigned())
+    {
+        entity.add<std_msgs::msg::UInt32, unsigned int>(signal_name,
+                                                        topic_name);
+    }
+    else if (type == DgRosTypes::get_matrix())
+    {
+        entity.add<RosMatrix, DgMatrix>(signal_name, topic_name);
+    }
+    else if (type == DgRosTypes::get_vector())
+    {
+        entity.add<RosVector, DgVector>(signal_name, topic_name);
+    }
+    else if (type == DgRosTypes::get_vector3())
+    {
+        entity.add<geometry_msgs::msg::Vector3, DgVector>(signal_name,
+                                                          topic_name);
+    }
+    else if (type == DgRosTypes::get_vector3_stamped())
+    {
+        entity.add<geometry_msgs::msg::Vector3Stamped, DgVector>(signal_name,
+                                                                 topic_name);
+    }
+    else if (type == DgRosTypes::get_matrix_homogeneous())
+    {
+        entity.add<geometry_msgs::msg::Transform, MatrixHomogeneous>(
+            signal_name, topic_name);
+    }
+    else if (type == DgRosTypes::get_matrix_homogeneous_stamped())
+    {
+        entity.add<geometry_msgs::msg::TransformStamped, MatrixHomogeneous>(
+            signal_name, topic_name);
+    }
+    else if (type == DgRosTypes::get_twist())
+    {
+        entity.add<geometry_msgs::msg::Twist, DgVector>(signal_name,
+                                                        topic_name);
+    }
+    else if (type == DgRosTypes::get_twist_stamped())
+    {
+        entity.add<geometry_msgs::msg::TwistStamped, DgVector>(signal_name,
+                                                               topic_name);
+    }
+    else
+    {
+        std::cerr << "RosSubscribe(" << entity.getName()
+                  << ")::add(): bad type given (" << type << ")."
+                  << " Possible choice is among:";
+        for (unsigned int i = 0; i < DgRosTypes::type_list.size(); ++i)
+        {
+            std::cerr << "    - " << DgRosTypes::type_list[i] << std::endl;
+        }
+    }
+    return Value();
+}
+
+Rm::Rm(RosSubscribe& entity, const std::string& doc_string)
+    : Command(entity, boost::assign::list_of(Value::STRING), doc_string)
+{
+}
+
+Value Rm::doExecute()
+{
+    RosSubscribe& entity = static_cast<RosSubscribe&>(owner());
+    std::vector<Value> values = getParameterValues();
+    const std::string& signal = values[0].value();
+    entity.rm(signal);
+    return Value();
+}
+}  // namespace ros_subscribe
+}  // end of namespace command.
+
+}  // namespace dynamic_graph_bridge
diff --git a/ros2/src/ros_subscribe.hpp b/ros2/src/ros_subscribe.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a4e40c0b43aa7f149be7097ebf4fff9c037bdc5e
--- /dev/null
+++ b/ros2/src/ros_subscribe.hpp
@@ -0,0 +1,157 @@
+/**
+ * @file
+ * @license BSD 3-clause
+ * @copyright Copyright (c) 2020, New York University and Max Planck
+ * Gesellschaft
+ *
+ * @brief Entity that subscribe to rostopic and forward the data to the dynamic
+ * graph trough a signal.
+ */
+
+#pragma once
+
+#include <dynamic-graph/command.h>
+#include <dynamic-graph/entity.h>
+#include <dynamic-graph/signal-ptr.h>
+#include <dynamic-graph/signal-time-dependent.h>
+
+#include <map>
+#include <mutex>
+
+#include "dynamic_graph_bridge/ros_entities/dg_ros_mapping.hpp"
+
+namespace dynamic_graph_bridge
+{
+/**
+ * @brief  Publish ROS information in the dynamic-graph.
+ */
+class RosSubscribe : public dynamicgraph::Entity
+{
+    DYNAMIC_GRAPH_ENTITY_DECL();
+
+public:
+    /**
+     * @brief Tuple composed by the generated input signal and its callback
+     * function. The callback function publishes the input signal content.
+     */
+    typedef std::tuple<std::shared_ptr<dynamicgraph::SignalBase<int> >,
+                       std::shared_ptr<dynamicgraph::SignalBase<int> >,
+                       rclcpp::SubscriptionBase::SharedPtr>
+        BindedSignal;
+
+    /**
+     * @brief Construct a new Ros Subscribe object
+     *
+     * @param name entity name.
+     */
+    RosSubscribe(const std::string& name);
+
+    /**
+     * @brief Destroy the Ros Subscribe object.
+     */
+    virtual ~RosSubscribe();
+
+    /**
+     * @brief Get Doc String.
+     *
+     * @return std::string
+     */
+    virtual std::string getDocString() const;
+
+    /**
+     * @brief Display information about the entity.
+     *
+     * @param os
+     */
+    void display(std::ostream& os) const;
+
+    /**
+     * @brief Subscribe to a topic and add a signal containing the topic data.
+     *
+     * @tparam RosType
+     * @tparam DgType
+     * @param signal_name
+     * @param topic_name
+     */
+    template <typename RosType, typename DgType>
+    void add(const std::string& signal_name, const std::string& topic_name);
+
+    /**
+     * @brief Unsubscribe to a topic and remove the signal.
+     *
+     * @param signal
+     */
+    void rm(const std::string& signal);
+
+    /**
+     * @brief List of all subscribed topic and singals.
+     *
+     * @return std::string
+     */
+    std::string list();
+
+    /**
+     * @brief Unsubscribe to all topics and remove all signals.
+     *
+     */
+    void clear();
+
+private:
+    /**
+     * @brief This callback feeds the data signal upon reception of a ROS
+     * message.
+     *
+     * @tparam RosType
+     * @tparam DgType
+     * @param signal pointer to the dynamic graph signal.
+     * @param data ROS data to copy from.
+     */
+    template <typename RosType, typename DgType>
+    void callback(
+        std::shared_ptr<typename DgRosMapping<RosType, DgType>::signal_out_t>
+            signal_out,
+        std::shared_ptr<
+            typename DgRosMapping<RosType, DgType>::signal_timestamp_out_t>
+            signal_timestamp_out,
+        const std::shared_ptr<typename DgRosMapping<RosType, DgType>::ros_t>
+            ros_data);
+
+private:
+    /** @brief Doc string associated to the entity. */
+    static const std::string doc_string_;
+
+    /** @brief ROS node pointer. */
+    RosNodePtr ros_node_;
+
+    /** @brief Named list of signals associated with it's callback functions. */
+    std::map<std::string, BindedSignal> binded_signals_;
+};
+
+namespace command
+{
+namespace ros_subscribe
+{
+using ::dynamicgraph::command::Command;
+using ::dynamicgraph::command::Value;
+
+#define ROS_SUBSCRIBE_MAKE_COMMAND(CMD)                           \
+    class CMD : public Command                                    \
+    {                                                             \
+    public:                                                       \
+        CMD(RosSubscribe& entity, const std::string& doc_string); \
+        virtual Value doExecute();                                \
+    }
+
+ROS_SUBSCRIBE_MAKE_COMMAND(Add);
+ROS_SUBSCRIBE_MAKE_COMMAND(Clear);
+ROS_SUBSCRIBE_MAKE_COMMAND(List);
+ROS_SUBSCRIBE_MAKE_COMMAND(Rm);
+
+#undef ROS_SUBSCRIBE_MAKE_COMMAND
+
+}  // namespace ros_subscribe
+}  // end of namespace command.
+
+}  // namespace dynamic_graph_bridge
+
+#include "ros_subscribe.hxx"
diff --git a/ros2/src/ros_subscribe.hxx b/ros2/src/ros_subscribe.hxx
new file mode 100644
index 0000000000000000000000000000000000000000..ccde69d910fdd09cb27d7a89527fd5bdeeb6b17e
--- /dev/null
+++ b/ros2/src/ros_subscribe.hxx
@@ -0,0 +1,112 @@
+/**
+ * @file ros_subscribe.hxx
+ * @author Maximilien Naveau (maximilien.naveau@gmail.com)
+ * @license License BSD-3-Clause
+ * @copyright Copyright (c) 2019, New York University and Max Planck
+ * Gesellschaft.
+ * @date 2019-05-22
+ */
+
+#pragma once
+
+#include <message_filters/message_traits.h>
+
+#include "dynamic_graph_bridge/ros_entities/dg_ros_mapping.hpp"
+
+namespace dynamic_graph_bridge
+{
+template <typename RosType, typename DgType>
+void RosSubscribe::callback(
+    std::shared_ptr<typename DgRosMapping<RosType, DgType>::signal_out_t>
+        signal_out,
+    std::shared_ptr<
+        typename DgRosMapping<RosType, DgType>::signal_timestamp_out_t>
+        signal_timestamp_out,
+    const std::shared_ptr<typename DgRosMapping<RosType, DgType>::ros_t>
+        ros_data)
+{
+    // Some convenient shortcut.
+    using ros_t = typename DgRosMapping<RosType, DgType>::ros_t;
+    using dg_t = typename DgRosMapping<RosType, DgType>::dg_t;
+
+    // Create a dynamic graph object to copy the information in. Not real time
+    // safe?
+    dg_t value;
+    // Convert the ROS topic into a dynamic graph type.
+    DgRosMapping<RosType, DgType>::ros_to_dg(*ros_data, value);
+    // Update the signal.
+    signal_out->setConstant(value);
+    // If he ROS message has a header then copy the header into the timestamp
+    // signal
+    if (signal_timestamp_out)
+    {
+        signal_timestamp_out->setConstant(
+            DgRosMapping<RosType, DgType>::from_ros_time(
+                message_filters::message_traits::TimeStamp<ros_t>::value(
+                    *ros_data)));
+    }
+}
+
+template <typename RosType, typename DgType>
+void RosSubscribe::add(const std::string& signal_name,
+                       const std::string& topic_name)
+{
+    using dg_t = typename DgRosMapping<RosType, DgType>::dg_t;
+    using ros_t = typename DgRosMapping<RosType, DgType>::ros_t;
+    using signal_out_t = typename DgRosMapping<RosType, DgType>::signal_out_t;
+    using signal_timestamp_out_t =
+        typename DgRosMapping<RosType, DgType>::signal_timestamp_out_t;
+
+    if (binded_signals_.find(signal_name) != binded_signals_.end())
+    {
+        std::cout << "Signal already created, nothing to be done." << std::endl;
+        return;
+    }
+
+    // Initialize the binded_signal object.
+    RosSubscribe::BindedSignal binded_signal;
+
+    // Initialize the signal.
+    std::string full_signal_name =
+        this->getClassName() + "(" + this->getName() + ")::" + signal_name;
+    std::shared_ptr<signal_out_t> signal_ptr =
+        std::make_shared<signal_out_t>(full_signal_name);
+    DgRosMapping<RosType, DgType>::set_default(signal_ptr);
+    signal_ptr->setDependencyType(
+        dynamicgraph::TimeDependency<int>::ALWAYS_READY);
+    std::get<0>(binded_signal) = signal_ptr;
+    this->signalRegistration(*std::get<0>(binded_signal));
+
+    // Initialize the time stamp signal if needed.
+    std::shared_ptr<signal_timestamp_out_t> signal_timestamp_ptr = nullptr;
+    if (message_filters::message_traits::HasHeader<ros_t>())
+    {
+        std::string full_time_stamp_signal_name =
+            this->getClassName() + "(" + this->getName() + ")::" + signal_name +
+            "_timestamp";
+        signal_timestamp_ptr = std::make_shared<signal_timestamp_out_t>(
+            full_time_stamp_signal_name);
+        signal_timestamp_ptr->setConstant(
+            DgRosMapping<RosType, DgType>::epoch_time());
+        signal_timestamp_ptr->setDependencyType(
+            dynamicgraph::TimeDependency<int>::ALWAYS_READY);
+        this->signalRegistration(*signal_timestamp_ptr);
+    }
+    std::get<1>(binded_signal) = signal_timestamp_ptr;
+
+    // Initialize the subscriber.
+    std::function<void(const std::shared_ptr<ros_t>)> callback =
+        std::bind(&RosSubscribe::callback<ros_t, dg_t>,
+                  this,
+                  signal_ptr,
+                  signal_timestamp_ptr,
+                  std::placeholders::_1);
+    typename rclcpp::Subscription<ros_t>::SharedPtr sub =
+        ros_node_->create_subscription<ros_t>(topic_name, 10, callback);
+    std::get<2>(binded_signal) = sub;
+
+    // Store the different pointers.
+    binded_signals_[signal_name] = binded_signal;
+}
+
+}  // namespace dynamic_graph_bridge
diff --git a/ros2/src/time_point_io.hpp b/ros2/src/time_point_io.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0827b07929a852e7d634cbe7dd4709c74af61332
--- /dev/null
+++ b/ros2/src/time_point_io.hpp
@@ -0,0 +1,58 @@
+/**
+ * @file
+ * @license BSD 3-clause
+ * @copyright Copyright (c) 2020, New York University and Max Planck
+ * Gesellschaft
+ *
+ * @brief Define the time stamp signal.
+ */
+
+#pragma once
+
+#include <dynamic-graph/signal-caster.h>
+
+#include <chrono>
+
+namespace dynamic_graph_bridge
+{
+/** @brief Time stamp type. */
+typedef std::chrono::time_point<std::chrono::high_resolution_clock> timestamp_t;
+
+}  // namespace dynamic_graph_bridge
+
+namespace dynamicgraph
+{
+/**
+ * @brief out stream the time stamp data.
+ *
+ * @param os
+ * @param time_stamp
+ * @return std::ostream&
+ */
+inline std::ostream &operator<<(
+    std::ostream &os, const dynamic_graph_bridge::timestamp_t &time_stamp)
+{
+    std::chrono::time_point<std::chrono::high_resolution_clock,
+                            std::chrono::milliseconds>
+        time_stamp_nanosec =
+            std::chrono::time_point_cast<std::chrono::milliseconds>(time_stamp);
+    os << time_stamp_nanosec.time_since_epoch().count();
+    return os;
+}
+
+/**
+ * @brief Structure used to serialize/deserialize the time stamp.
+ *
+ * @tparam
+ */
+template <>
+struct signal_io<dynamic_graph_bridge::timestamp_t>
+    : signal_io_base<dynamic_graph_bridge::timestamp_t>
+{
+    inline static dynamic_graph_bridge::timestamp_t cast(std::istringstream &)
+    {
+        throw std::logic_error("this cast is not implemented.");
+    }
+};
+
+}  // namespace dynamicgraph
diff --git a/ros2/tests/CMakeLists.txt b/ros2/tests/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..82f89d52f9633e6af8b7aff20882c76931f520ef
--- /dev/null
+++ b/ros2/tests/CMakeLists.txt
@@ -0,0 +1,52 @@
+# Copyright (C) 2021 LAAS-CNRS.
+#
+# Author: Maxmilien Naveau
+#
+
+if(BUILD_TESTING)
+  find_package(ament_cmake_gmock REQUIRED)
+  find_package(ament_lint_auto REQUIRED)
+  _ament_cmake_gmock_find_gmock()
+  find_package(launch_testing_ament_cmake)
+  ament_lint_auto_find_test_dependencies()
+
+  # Library for sot_external_interface
+  add_library(impl_test_sot_external_interface SHARED
+    tests/impl_test_sot_external_interface)
+
+  target_link_libraries(impl_test_sot_external_interface PUBLIC sot-core::sot-core)
+
+  # Executable for SotLoaderBasic test
+  add_executable(test_sot_loader_basic
+    tests/test_sot_loader_basic.cpp
+  )
+  target_include_directories(test_sot_loader_basic PUBLIC include  "${GMOCK_INCLUDE_DIRS}")
+  target_link_libraries(test_sot_loader_basic sot_loader "${GMOCK_LIBRARIES}" )
+
+  add_launch_test(tests/launching_test_sot_loader_basic.py)
+
+  # Test for class SotLoader
+  add_executable(test_sot_loader
+    tests/test_sot_loader.cpp
+  )
+  target_include_directories(test_sot_loader PUBLIC include "${GMOCK_INCLUDE_DIRS}")
+  target_link_libraries(test_sot_loader sot_loader "${GMOCK_LIBRARIES}")
+
+  add_launch_test(tests/launching_test_sot_loader.py)
+
+  # Install tests
+  install(TARGETS test_sot_loader_basic
+    test_sot_loader
+    DESTINATION lib/${PROJECT_NAME}
+    )
+
+  # Install library for tests
+  install(TARGETS impl_test_sot_external_interface
+    DESTINATION lib
+    )
+
+  install(DIRECTORY launch urdf
+    DESTINATION share/${PROJECT_NAME}
+    )
+
+endif()
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
deleted file mode 100644
index 9396cbf0720bcbf595b8bf0c55fac59d40fa9462..0000000000000000000000000000000000000000
--- a/src/CMakeLists.txt
+++ /dev/null
@@ -1,68 +0,0 @@
-SET(plugins
-  ros_publish
-  ros_subscribe
-  ros_queued_subscribe
-  ros_tf_listener
-  ros_time
-  )
-
-FOREACH(plugin ${plugins})
-  GET_FILENAME_COMPONENT(LIBRARY_NAME ${plugin} NAME)
-  ADD_LIBRARY(${LIBRARY_NAME} SHARED ${plugin}.cpp ${plugin}.hh)
-
-  IF(SUFFIX_SO_VERSION)
-    SET_TARGET_PROPERTIES(${LIBRARY_NAME} PROPERTIES SOVERSION ${PROJECT_VERSION})
-  ENDIF(SUFFIX_SO_VERSION)
-
-  TARGET_LINK_LIBRARIES(${LIBRARY_NAME} ${${LIBRARY_NAME}_deps} ${catkin_LIBRARIES} ros_bridge
-    dynamic_graph_bridge_msgs::dynamic_graph_bridge_msgs)
-
-  IF(NOT INSTALL_PYTHON_INTERFACE_ONLY)
-    INSTALL(TARGETS ${LIBRARY_NAME} EXPORT ${TARGETS_EXPORT_NAME}
-      DESTINATION ${DYNAMIC_GRAPH_PLUGINDIR})
-  ENDIF(NOT INSTALL_PYTHON_INTERFACE_ONLY)
-
-  IF(BUILD_PYTHON_INTERFACE)
-    STRING(REPLACE - _ PYTHON_LIBRARY_NAME ${LIBRARY_NAME})
-    if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${plugin}-python-module-py.cc")
-      DYNAMIC_GRAPH_PYTHON_MODULE("ros/${PYTHON_LIBRARY_NAME}"
-        ${LIBRARY_NAME} ${PROJECT_NAME}-${PYTHON_LIBRARY_NAME}-wrap
-        SOURCE_PYTHON_MODULE "${CMAKE_CURRENT_SOURCE_DIR}/${plugin}-python-module-py.cc")
-    elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${plugin}-python.hh")
-      DYNAMIC_GRAPH_PYTHON_MODULE("ros/${PYTHON_LIBRARY_NAME}"
-        ${LIBRARY_NAME} ${PROJECT_NAME}-${PYTHON_LIBRARY_NAME}-wrap
-        MODULE_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/${plugin}-python.hh")
-    endif()
-  ENDIF(BUILD_PYTHON_INTERFACE)
-ENDFOREACH(plugin)
-
-target_link_libraries(ros_publish ros_bridge)
-
-IF(BUILD_PYTHON_INTERFACE)
-  PYTHON_INSTALL_ON_SITE("dynamic_graph/ros" "__init__.py")
-  PYTHON_INSTALL_ON_SITE("dynamic_graph/ros" "ros.py")
-  PYTHON_INSTALL_ON_SITE("dynamic_graph/ros" "dgcompleter.py")
-
-  # ros_interperter library.
-  add_library(ros_interpreter ros_interpreter.cpp)
-  TARGET_LINK_LIBRARIES(ros_interpreter ros_bridge ${catkin_LIBRARIES}
-    dynamic-graph-python::dynamic-graph-python
-    dynamic_graph_bridge_msgs::dynamic_graph_bridge_msgs)
-
-  install(TARGETS ros_interpreter
-    EXPORT ${TARGETS_EXPORT_NAME}
-    DESTINATION lib)
-ENDIF(BUILD_PYTHON_INTERFACE)
-
-# Stand alone embedded intepreter with a robot controller.
-add_executable(geometric_simu geometric_simu.cpp sot_loader.cpp sot_loader_basic.cpp)
-target_link_libraries(geometric_simu Boost::program_options ${CMAKE_DL_LIBS} ${catkin_LIBRARIES} ros_bridge
-  dynamic_graph_bridge_msgs::dynamic_graph_bridge_msgs)
-install(TARGETS geometric_simu
-  DESTINATION lib/${PROJECT_NAME})
-
-# Sot loader library
-add_library(sot_loader sot_loader.cpp sot_loader_basic.cpp)
-target_link_libraries(sot_loader Boost::program_options ${catkin_LIBRARIES} ros_bridge
-  dynamic_graph_bridge_msgs::dynamic_graph_bridge_msgs)
-install(TARGETS sot_loader EXPORT ${TARGETS_EXPORT_NAME} DESTINATION lib)