diff --git a/.gitignore b/.gitignore
index 1c85d0e33ee62df4e08b1e05901d206de3b1e866..ddedb264f45361a21416cacc301bd5a7402e3a37 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 .idea
 cmake-build-*
+doc
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9327b375e6b3d4899e5868a6ec30a7ab76b33af9..6cd8b5e22797bb46c68543302c4510e31cb494ab 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -335,10 +335,10 @@ target_link_libraries(${PROJECT_NAME}_scene_controller
 #############
 
 ## Add gtest based cpp test target and link libraries
-# catkin_add_gtest(${PROJECT_NAME}-test test/test_ccf.cpp)
-# if(TARGET ${PROJECT_NAME}-test)
-#   target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
-# endif()
+catkin_add_gtest(${PROJECT_NAME}-NodeUtil-test test/test_NodeUtil.cpp)
+if(TARGET ${PROJECT_NAME}-NodeUtil-test)
+  target_link_libraries(${PROJECT_NAME}-NodeUtil-test ${catkin_LIBRARIES} )
+endif()
 
 ## Add folders to be run by python nosetests
 # catkin_add_nosetests(test)
diff --git a/README.md b/README.md
index bbd4d3cc2c19814ddd48745d1a8f705d44701372..9578719d8317abf6a037903360df2ab4085d0dc4 100644
--- a/README.md
+++ b/README.md
@@ -20,15 +20,28 @@ for internal and external testing.
   ```
   $ source devel/setup.bash
   ```
-- Get the path to this package
+- Generate the documentation
   ```
-  $ rospack find ccf
+  $ rosdoc_lite `rospack find ccf`
   ```
-- Generate the documentation
+- You can view the generated files in you browser by opening the generated `index.html`
   ```
-  $ rosdoc_lite <PATH_TO_PACKAGE>
+  xdg-open `rospack find ccf`/doc/html/index.html
   ```
-- You can view the generated files in you browser by opening the generated index.html via CLion in your browser.  
+## Running the Tests
+
+1. Build the package (this is not done automatically by the following commands)
+  ```bash
+  catkin build
+  ```
+2. Build the tests
+   ```bash
+   catkin build --make-args tests
+   ```
+3. Run the tests
+   ```bash
+   rostest -t ccf test_NodeUtil.test
+   ```
 
 ## CGV Dummy Controller Demonstrator
 
@@ -72,8 +85,8 @@ This demonstrator contains two mock-up nodes that can serve as stand-ins for fut
 #### Configuration
 
 - configure the scene (*not* required when using the dummy controller):
-  ```
-  rostopic pub -1 /scene_config/collision_objects std_msgs/String -f `rospack find ccf`/config_full.yaml
+  ```bash
+  rostopic pub -1 /scene_config std_msgs/String "\"$(roscat ccf config_scene.yaml)\""
   ```
 
 #### Execution
diff --git a/config/config.yaml b/config/config.yaml
index e706283aee5eebd754dbad620b1dca4ec338bd26..97af7cc5fff92078f36a216b2c48870529fbb16c 100644
--- a/config/config.yaml
+++ b/config/config.yaml
@@ -1,8 +1,7 @@
 connector_node_ros_cgv:
   cgv_address: "tcp://*:6576"
-scene_controller:
-  max_grasp_approach_velocity: 0.2
-  max_grasp_approach_acceleration: 0.2
-  max_grasp_transition_velocity: 0.2
-  max_grasp_transition_acceleration: 0.2
-  tud_grasp_force: 12.5
+max_grasp_approach_velocity: 0.2
+max_grasp_approach_acceleration: 0.2
+max_grasp_transition_velocity: 0.2
+max_grasp_transition_acceleration: 0.2
+tud_grasp_force: 12.5
diff --git a/config/config_pick_place_scene.json b/config/config_pick_place_scene.json
deleted file mode 100644
index ddefea7c5a933d27f7028a8cba1a4ce8b336de09..0000000000000000000000000000000000000000
--- a/config/config_pick_place_scene.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{ "objects": [
-  { "id": "tablePillar1","pos": { "x": 0.77,"y": 0.77,"z": 0.325 },"size": { "length": 0.06,"width": 0.06,"height": 0.65 },"orientation": { "w": 1 },"color": { "r": 255,"g": 222,"b": 173 } },
-  { "id": "tablePillar2","pos": { "x": -0.77,"y": -0.77,"z": 0.325 },"size": { "length": 0.06,"width": 0.06,"height": 0.65 },"orientation": { "w": 1 },"color": { "r": 255,"g": 222,"b": 173 } },
-  { "id": "tablePillar3","pos": { "x": -0.77,"y": 0.77,"z": 0.325 },"size": { "length": 0.06,"width": 0.06,"height": 0.65 },"orientation": { "w": 1 },"color": { "r": 255,"g": 222,"b": 173 } },
-  { "id": "tablePillar4","pos": { "x": 0.77,"y": -0.77,"z": 0.325 },"size": { "length": 0.06,"width": 0.06,"height": 0.65 },"orientation": { "w": 1 },"color": { "r": 255,"g": 222,"b": 173 } },
-  { "id": "table","pos": { "z": 0.7 },"size": { "length": 1.6,"width": 1.6,"height": 0.1 },"orientation": { "w": 1 },"color": { "r": 255,"g": 222,"b": 173 } },
-  { "id": "binBlue","type": "DROP_OFF_LOCATION","pos": { "x": -0.34,"y": 0.49,"z": 0.8325 },"size": { "length": 0.21,"width": 0.3,"height": 0.165 },"orientation": { "w": 1 },"color": { "b": 1 } },
-  { "id": "binRed","type": "DROP_OFF_LOCATION","pos": { "x": 0.06,"y": 0.49,"z": 0.8325 },"size": { "length": 0.21,"width": 0.3,"height": 0.165 },"orientation": { "w": 1 },"color": { "r": 1 } },
-  { "id": "binGreen","type": "DROP_OFF_LOCATION","pos": { "x": 0.46,"y": 0.49,"z": 0.8325 },"size": { "length": 0.21,"width": 0.3,"height": 0.165 },"orientation": { "w": 1 },"color": { "g": 1 } },
-  { "id": "objectRed1","type": "BOX","pos": { "x": 0.5,"y": -0.1,"z": 0.8105 },"size": { "length": 0.031,"width": 0.062,"height": 0.121 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "r": 1 } },
-  { "id": "objectRed2","type": "BOX","pos": { "x": 0.25,"y": -0.2,"z": 0.8105 },"size": { "length": 0.031,"width": 0.062,"height": 0.121 },"orientation": { "w": 1 },"color": { "r": 1 } },
-  { "id": "objectRed3","type": "BOX","pos": { "x": -0.4,"z": 0.819 },"size": { "length": 0.031,"width": 0.031,"height": 0.138 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "r": 1 } },
-  { "id": "objectGreen1","type": "BOX","pos": { "x": 0.45,"y": -0.3,"z": 0.8105 },"size": {"length":0.031,"width":0.062,"height":0.121},"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "g": 1 } },
-  { "id": "objectGreen2","type": "BOX","pos": { "x": -0.45,"y": -0.2,"z": 0.8105 },"size": {"length":0.031,"width":0.031,"height":0.138},"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "g": 1 } },
-  { "id": "objectGreen3","type": "BOX","pos": { "x": 0.1,"y": -0.3,"z": 0.819 },"size": {"length":0.031,"width":0.062,"height":0.121},"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "g": 1 } },
-  { "id": "objectBlue1","type": "BOX","pos": { "x": 0.25,"y": -0.4,"z": 0.8105 },"size": { "length": 0.031,"width": 0.062,"height": 0.121 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "b": 1 } },
-  { "id": "objectBlue2","type": "BOX","pos": { "x": -0.3,"y": -0.3,"z": 0.8105 },"size": { "length": 0.031,"width": 0.062,"height": 0.121 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "b": 1 } },
-  { "id": "objectBlue3","type": "BOX","pos": { "x": 0.4,"z": 0.819 },"size": { "length": 0.031,"width": 0.031,"height": 0.138 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "b": 1 } },
-  { "id": "arm","type": "ARM","pos": { "z": 0.75 },"size": { },"orientation": { "w": 1 },"color": { "r": 1.00,"g": 1.00,"b": 1.00 } }
-] }
diff --git a/config/config_scene.yaml b/config/config_scene.yaml
index 9f09d081b7d6caa749305865649366b180d27286..2620d0c0e5242d87d6dfbdc8d2c6e4b39d6e6c18 100644
--- a/config/config_scene.yaml
+++ b/config/config_scene.yaml
@@ -1,20 +1,20 @@
-{ "objects": [
-  { "id": "tablePillar1","pos": { "x": 0.77,"y": 0.77,"z": 0.325 },"size": { "length": 0.06,"width": 0.06,"height": 0.65 },"orientation": { "w": 1 },"color": { "r": 255,"g": 222,"b": 173 } },
-  { "id": "tablePillar2","pos": { "x": -0.77,"y": -0.77,"z": 0.325 },"size": { "length": 0.06,"width": 0.06,"height": 0.65 },"orientation": { "w": 1 },"color": { "r": 255,"g": 222,"b": 173 } },
-  { "id": "tablePillar3","pos": { "x": -0.77,"y": 0.77,"z": 0.325 },"size": { "length": 0.06,"width": 0.06,"height": 0.65 },"orientation": { "w": 1 },"color": { "r": 255,"g": 222,"b": 173 } },
-  { "id": "tablePillar4","pos": { "x": 0.77,"y": -0.77,"z": 0.325 },"size": { "length": 0.06,"width": 0.06,"height": 0.65 },"orientation": { "w": 1 },"color": { "r": 255,"g": 222,"b": 173 } },
-  { "id": "table","pos": { "z": 0.7 },"size": { "length": 1.6,"width": 1.6,"height": 0.1 },"orientation": { "w": 1 },"color": { "r": 255,"g": 222,"b": 173 } },
-  { "id": "binBlue","type": "BIN","pos": { "x": -0.34,"y": 0.49,"z": 0.8325 },"size": { "length": 0.21,"width": 0.3,"height": 0.165 },"orientation": { "w": 1 },"color": { "b": 1 } },
-  { "id": "binRed","type": "BIN","pos": { "x": 0.06,"y": 0.49,"z": 0.8325 },"size": { "length": 0.21,"width": 0.3,"height": 0.165 },"orientation": { "w": 1 },"color": { "r": 1 } },
-  { "id": "binGreen","type": "BIN","pos": { "x": 0.46,"y": 0.49,"z": 0.8325 },"size": { "length": 0.21,"width": 0.3,"height": 0.165 },"orientation": { "w": 1 },"color": { "g": 1 } },
-  { "id": "objectRed1","type": "BOX","pos": { "x": 0.5,"y": -0.1,"z": 0.8105 },"size": { "length": 0.031,"width": 0.062,"height": 0.121 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "r": 1 } },
-  { "id": "objectRed2","type": "BOX","pos": { "x": 0.25,"y": -0.2,"z": 0.8105 },"size": { "length": 0.031,"width": 0.062,"height": 0.121 },"orientation": { "w": 1 },"color": { "r": 1 } },
-  { "id": "objectRed3","type": "BOX","pos": { "x": -0.4,"z": 0.819 },"size": { "length": 0.031,"width": 0.031,"height": 0.138 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "r": 1 } },
-  { "id": "objectGreen1","type": "BOX","pos": { "x": 0.45,"y": -0.3,"z": 0.8105 },"size": {"length":0.031,"width":0.062,"height":0.121},"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "g": 1 } },
-  { "id": "objectGreen2","type": "BOX","pos": { "x": -0.45,"y": -0.2,"z": 0.8105 },"size": {"length":0.031,"width":0.031,"height":0.138},"orientation": { "z": 1,"w": 0.92388 },"color": { "g": 1 } },
-  { "id": "objectGreen3","type": "BOX","pos": { "x": 0.1,"y": -0.3,"z": 0.819 },"size": {"length":0.031,"width":0.062,"height":0.121},"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "g": 1 } },
-  { "id": "objectBlue1","type": "BOX","pos": { "x": 0.25,"y": -0.4,"z": 0.8105 },"size": { "length": 0.031,"width": 0.062,"height": 0.121 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "b": 1 } },
-  { "id": "objectBlue2","type": "BOX","pos": { "x": -0.3,"y": -0.3,"z": 0.8105 },"size": { "length": 0.031,"width": 0.062,"height": 0.121 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "b": 1 } },
-  { "id": "objectBlue3","type": "BOX","pos": { "x": 0.4,"z": 0.819 },"size": { "length": 0.031,"width": 0.031,"height": 0.138 },"orientation": { "z": 0.382683,"w": 0.92388 },"color": { "b": 1 } },
-  { "id": "arm","type": "ARM","pos": { "z": 0.75 },"size": { },"orientation": { "w": 1 },"color": { "r": 1.00,"g": 1.00,"b": 1.00 } }
+{ 'objects': [
+  { 'id': 'tablePillar1','pos': { 'x': 0.77,'y': 0.77,'z': 0.325 },'size': { 'length': 0.06,'width': 0.06,'height': 0.65 },'orientation': { 'w': 1 },'color': { 'r': 255,'g': 222,'b': 173 } },
+  { 'id': 'tablePillar2','pos': { 'x': -0.77,'y': -0.77,'z': 0.325 },'size': { 'length': 0.06,'width': 0.06,'height': 0.65 },'orientation': { 'w': 1 },'color': { 'r': 255,'g': 222,'b': 173 } },
+  { 'id': 'tablePillar3','pos': { 'x': -0.77,'y': 0.77,'z': 0.325 },'size': { 'length': 0.06,'width': 0.06,'height': 0.65 },'orientation': { 'w': 1 },'color': { 'r': 255,'g': 222,'b': 173 } },
+  { 'id': 'tablePillar4','pos': { 'x': 0.77,'y': -0.77,'z': 0.325 },'size': { 'length': 0.06,'width': 0.06,'height': 0.65 },'orientation': { 'w': 1 },'color': { 'r': 255,'g': 222,'b': 173 } },
+  { 'id': 'table','pos': { 'z': 0.7 },'size': { 'length': 1.6,'width': 1.6,'height': 0.1 },'orientation': { 'w': 1 },'color': { 'r': 255,'g': 222,'b': 173 } },
+  { 'id': 'binBlue','type': 'BIN','pos': { 'x': -0.34,'y': 0.49,'z': 0.8325 },'size': { 'length': 0.21,'width': 0.3,'height': 0.165 },'orientation': { 'w': 1 },'color': { 'b': 1 } },
+  { 'id': 'binRed','type': 'BIN','pos': { 'x': 0.06,'y': 0.49,'z': 0.8325 },'size': { 'length': 0.21,'width': 0.3,'height': 0.165 },'orientation': { 'w': 1 },'color': { 'r': 1 } },
+  { 'id': 'binGreen','type': 'BIN','pos': { 'x': 0.46,'y': 0.49,'z': 0.8325 },'size': { 'length': 0.21,'width': 0.3,'height': 0.165 },'orientation': { 'w': 1 },'color': { 'g': 1 } },
+  { 'id': 'objectRed1','type': 'BOX','pos': { 'x': 0.5,'y': -0.1,'z': 0.8105 },'size': { 'length': 0.031,'width': 0.062,'height': 0.121 },'orientation': { 'z': 0.382683,'w': 0.92388 },'color': { 'r': 1 } },
+  { 'id': 'objectRed2','type': 'BOX','pos': { 'x': 0.25,'y': -0.2,'z': 0.8105 },'size': { 'length': 0.031,'width': 0.062,'height': 0.121 },'orientation': { 'w': 1 },'color': { 'r': 1 } },
+  { 'id': 'objectRed3','type': 'BOX','pos': { 'x': -0.4,'z': 0.819 },'size': { 'length': 0.031,'width': 0.031,'height': 0.138 },'orientation': { 'z': 0.382683,'w': 0.92388 },'color': { 'r': 1 } },
+  { 'id': 'objectGreen1','type': 'BOX','pos': { 'x': 0.45,'y': -0.3,'z': 0.8105 },'size': {'length':0.031,'width':0.062,'height':0.121},'orientation': { 'z': 0.382683,'w': 0.92388 },'color': { 'g': 1 } },
+  { 'id': 'objectGreen2','type': 'BOX','pos': { 'x': -0.45,'y': -0.2,'z': 0.8105 },'size': {'length':0.031,'width':0.031,'height':0.138},'orientation': { 'z': 1,'w': 0.92388 },'color': { 'g': 1 } },
+  { 'id': 'objectGreen3','type': 'BOX','pos': { 'x': 0.1,'y': -0.3,'z': 0.819 },'size': {'length':0.031,'width':0.062,'height':0.121},'orientation': { 'z': 0.382683,'w': 0.92388 },'color': { 'g': 1 } },
+  { 'id': 'objectBlue1','type': 'BOX','pos': { 'x': 0.25,'y': -0.4,'z': 0.8105 },'size': { 'length': 0.031,'width': 0.062,'height': 0.121 },'orientation': { 'z': 0.382683,'w': 0.92388 },'color': { 'b': 1 } },
+  { 'id': 'objectBlue2','type': 'BOX','pos': { 'x': -0.3,'y': -0.3,'z': 0.8105 },'size': { 'length': 0.031,'width': 0.062,'height': 0.121 },'orientation': { 'z': 0.382683,'w': 0.92388 },'color': { 'b': 1 } },
+  { 'id': 'objectBlue3','type': 'BOX','pos': { 'x': 0.4,'z': 0.819 },'size': { 'length': 0.031,'width': 0.031,'height': 0.138 },'orientation': { 'z': 0.382683,'w': 0.92388 },'color': { 'b': 1 } },
+  { 'id': 'arm','type': 'ARM','pos': { 'z': 0.75 },'size': { },'orientation': { 'w': 1 },'color': { 'r': 1.00,'g': 1.00,'b': 1.00 } }
 ] }
diff --git a/config_full.yaml b/config_full.yaml
deleted file mode 100644
index 6cf18beb1b027d1e3f8c69522e01178c2858d2b0..0000000000000000000000000000000000000000
--- a/config_full.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-  "{'objects':[
-{'id':'objectRed1','type':'BOX','pos':{'x':0.5,'y':-0.1,'z':0.8105},'size':{'length':0.031,'width':0.062,'height':0.121},'orientation':{'x': 0, 'y': 0, 'z': 0.382683, 'w': 0.92388},'color':{'r':1.00,'g':0.00,'b':0.00}},
-{'id':'objectRed2','type':'BOX','pos':{'x':0.25,'y':-0.2,'z':0.8105},'size':{'length':0.031,'width':0.062,'height':0.121},'orientation':{'x': 0, 'y': 0, 'z': 0, 'w': 1.0},'color':{'r':1.00,'g':0.00,'b':0.00}},
-{'id':'objectRed3','type':'BOX','pos':{'x':-0.4,'y':0.0,'z':0.819},'size':{'length':0.031,'width':0.031,'height':0.138},'orientation':{'x': 0, 'y': 0, 'z': 0.382683, 'w': 0.92388},'color':{'r':1.00,'g':0.00,'b':0.00}},
-{'id':'objectGreen1','type':'BOX','pos':{'x':0.45,'y':-0.3,'z':0.8105},'size':{'length':0.031,'width':0.062,'height':0.121},'orientation':{'x': 0, 'y': 0, 'z': 0.382683, 'w': 0.92388},'color':{'r':0.00,'g':1.00,'b':0.00}},
-{'id':'objectGreen2','type':'BOX','pos':{'x':-0.45,'y':-0.2,'z':0.819},'size':{'length':0.031,'width':0.031,'height':0.138},'orientation':{'x': 0, 'y': 0, 'z': 1.0, 'w': 0.92388},'color':{'r':0.00,'g':1.00,'b':0.00}},
-{'id':'objectGreen3','type':'BOX','pos':{'x':0.1,'y':-0.3,'z':0.8105},'size':{'length':0.031,'width':0.062,'height':0.121},'orientation':{'x': 0, 'y': 0, 'z': 0.382683, 'w': 0.92388},'color':{'r':0.00,'g':1.00,'b':0.00}},
-{'id':'objectBlue1','type':'BOX','pos':{'x':0.25,'y':-0.4,'z':0.8105},'size':{'length':0.031,'width':0.062,'height':0.121},'orientation':{'x': 0, 'y': 0, 'z': 0.382683, 'w': 0.92388},'color':{'r':0.00,'g':0.00,'b':1.00}},
-{'id':'objectBlue2','type':'BOX','pos':{'x':-0.3,'y':-0.3,'z':0.8105},'size':{'length':0.031,'width':0.062,'height':0.121},'orientation':{'x': 0, 'y': 0, 'z': 0.382683, 'w': 0.92388},'color':{'r':0.00,'g':0.00,'b':1.00}},
-{'id':'objectBlue3','type':'BOX','pos':{'x':0.4,'y':0.0,'z':0.819},'size':{'length':0.031,'width':0.031,'height':0.138},'orientation':{'x': 0, 'y': 0, 'z': 0.382683, 'w': 0.92388},'color':{'r':0.00,'g':0.00,'b':1.00}},
-{'id':'tablePillar1','type':'UNKNOWN','pos':{'x':0.77,'y':0.77,'z':0.325},'size':{'length':0.06,'width':0.06,'height':0.65},'orientation':{'x':0.00,'y':0.00,'z':0.00,'w':1.00},'color':{'r':0.839,'g':0.839,'b':0.839}},
-{'id':'tablePillar2','type':'UNKNOWN','pos':{'x':-0.77,'y':-0.77,'z':0.325},'size':{'length':0.06,'width':0.06,'height':0.65},'orientation':{'x':0.00,'y':0.00,'z':0.00,'w':1.00},'color':{'r':0.839,'g':0.839,'b':0.839}},
-{'id':'tablePillar3','type':'UNKNOWN','pos':{'x':-0.77,'y':0.77,'z':0.325},'size':{'length':0.06,'width':0.06,'height':0.65},'orientation':{'x':0.00,'y':0.00,'z':0.00,'w':1.00},'color':{'r':0.839,'g':0.839,'b':0.839}},
-{'id':'tablePillar4','type':'UNKNOWN','pos':{'x':0.77,'y':-0.77,'z':0.325},'size':{'length':0.06,'width':0.06,'height':0.65},'orientation':{'x':0.00,'y':0.00,'z':0.00,'w':1.00},'color':{'r':0.839,'g':0.839,'b':0.839}},
-{'id':'table','type':'UNKNOWN','pos':{'x':0.00,'y':0.00,'z':0.7},'size':{'length':1.60,'width':1.60,'height':0.10},'orientation':{'x':0.00,'y':0.00,'z':0.00,'w':1.00},'color':{'r':0.839,'g':0.839,'b':0.839}},
-{'id':'binBlue','type':'BIN','pos':{'x':-0.34,'y':0.49,'z':0.8325},'size':{'length':0.21,'width':0.30,'height':0.165},'orientation':{'w':1},'color':{'r':0.00,'g':0.00,'b':1.00}},
-{'id':'binRed','type':'BIN','pos':{'x': 0.06,'y':0.49,'z':0.8325},'size':{'length':0.21,'width':0.30,'height':0.165},'orientation':{'w':1},'color':{'r': 1.00,'g':0.00,'b':0.00}},
-{'id':'binGreen','type':'BIN','pos':{'x': 0.46,'y':0.49,'z':0.8325},'size':{'length':0.21,'width':0.30,'height':0.165},'orientation':{'w':1},'color':{'r':0.00,'g':1.00,'b':0.00}},
-{'id':'arm','type':'ARM','pos':{'x': 0,'y': 0,'z':0.75},'size':{'length':0.0,'width':0.0,'height':0.0},'orientation':{'w':1},'color':{'r':0.00,'g':0.00,'b':0.00}}
-]}"
diff --git a/include/ccf/util/NodeUtil.h b/include/ccf/util/NodeUtil.h
index c6e5cc180eaa034ceba2e4767e88e8ac9abe46fc..200d33ef873f8272393bdfd2271ff34a4ed5e699 100644
--- a/include/ccf/util/NodeUtil.h
+++ b/include/ccf/util/NodeUtil.h
@@ -2,20 +2,40 @@
 // Created by jm on 07/05/2021.
 //
 
-#ifndef CGV_CONNECTOR_WORKSPACE_NODEUTIL_H
-#define CGV_CONNECTOR_WORKSPACE_NODEUTIL_H
+#ifndef CCF_NODEUTIL_H
+#define CCF_NODEUTIL_H
 
 #include <ros/ros.h>
 
+#include <sstream>
+
 namespace CetiRosToolbox {
 
     /// Gets a parameter from the parameter server. If the parameter does not exist, the fallback is used. If no fallback
     /// value is specified, an empty string is returned.
+    ///
+    /// If the parameter is \a not on the parameter server, a warning is issued at \c ROS_WARN.
+    ///
+    /// Usually, when using the method, the template parameter can be omitted if a fallback value is provided. This does
+    /// \a not work when providing \c const \c char* as fallback (i.e., string constants). In this case, the template
+    /// parameter must be provided:
+    /// \code{.cpp}
+    /// auto intValue1 = getParameter<int>(n, "foo"); // no fallback means no automatic matching
+    /// auto intValue2 = getParameter(n, "foo", 42); // the compiler matches T with int, this is okay
+    /// auto stringValue = getParameter<std::string>(n, "bar", "fourtytwo"); // const char* requires the std::string template parameter
+    /// \endcode
+    /// \tparam T a type supported by the parameter server.
+    /// The parameter server supports \c std::string double \c float \c int \c bool
+    /// and \c std::vector and \std::map of these types.
+    /// Additionally, also \c XmlRpc::XmlRpcValue is supported, though not as a vector or map.
     /// \param n the NodeHandle, in the namespace of which the parameter is queried
     /// \param key the name of the parameter
     /// \param fallback the default value
-    /// \return the parameter (if it exists), otherwise the fallback value (if it exists), otherwise an empty string
-    std::string getParameter(const ros::NodeHandle &n, const std::string &key, std::string fallback = "") {
+    /// \return the parameter (if it exists), otherwise the fallback value (if it exists), otherwise the default
+    ///         instance of the respective object
+    /// \warning Currently, this is a header-only library, but this might change in the future
+    template<class T>
+    T getParameter(const ros::NodeHandle &n, const std::string &key, T fallback = T()) {
         if (!n.getParam(key, fallback)) {
             ROS_WARN_STREAM("[" << ros::this_node::getName() << "] Could not get string value for "
                                 << n.getNamespace() << "/" << key
@@ -23,6 +43,110 @@ namespace CetiRosToolbox {
         }
         return fallback;
     }
+
+    /** @cond */ // the specializations are required to print the warning correctly
+    template<>
+    XmlRpc::XmlRpcValue getParameter(const ros::NodeHandle &n, const std::string &key, XmlRpc::XmlRpcValue fallback) {
+        if (!n.getParam(key, fallback)) {
+            ROS_WARN_STREAM("[" << ros::this_node::getName() << "] Could not get string value for "
+                                << n.getNamespace() << "/" << key
+                                << " from param server, using default '" << fallback.toXml() << "'.");
+        }
+        return fallback;
+    }
+    template<>
+    std::vector<std::string> getParameter(const ros::NodeHandle &n, const std::string &key, std::vector<std::string> fallback) {
+        if (!n.getParam(key, fallback)) {
+            std::ostringstream vector;
+            std::copy(fallback.begin(), fallback.end(), std::ostream_iterator<std::string>(vector, " "));
+            ROS_WARN_STREAM("[" << ros::this_node::getName() << "] Could not get string value for "
+                                << n.getNamespace() << "/" << key
+                                                           << " from param server, using default [ " << vector.str() << "].");
+        }
+        return fallback;
+    }
+    template<>
+    std::vector<double> getParameter(const ros::NodeHandle &n, const std::string &key, std::vector<double> fallback) {
+        if (!n.getParam(key, fallback)) {
+            ROS_WARN_STREAM("[" << ros::this_node::getName() << "] Could not get string value for "
+                                << n.getNamespace() << "/" << key
+                                << " from param server, using default empty vector.");
+        }
+        return fallback;
+    }
+    template<>
+    std::vector<float> getParameter(const ros::NodeHandle &n, const std::string &key, std::vector<float> fallback) {
+        if (!n.getParam(key, fallback)) {
+            ROS_WARN_STREAM("[" << ros::this_node::getName() << "] Could not get string value for "
+                                << n.getNamespace() << "/" << key
+                                << " from param server, using default empty vector.");
+        }
+        return fallback;
+    }
+    template<>
+    std::vector<int> getParameter(const ros::NodeHandle &n, const std::string &key, std::vector<int> fallback) {
+        if (!n.getParam(key, fallback)) {
+            ROS_WARN_STREAM("[" << ros::this_node::getName() << "] Could not get string value for "
+                                << n.getNamespace() << "/" << key
+                                << " from param server, using default empty vector.");
+        }
+        return fallback;
+    }
+    template<>
+    std::vector<bool> getParameter(const ros::NodeHandle &n, const std::string &key, std::vector<bool> fallback) {
+        if (!n.getParam(key, fallback)) {
+            ROS_WARN_STREAM("[" << ros::this_node::getName() << "] Could not get string value for "
+                                << n.getNamespace() << "/" << key
+                                << " from param server, using default empty vector.");
+        }
+        return fallback;
+    }
+    template<>
+    std::map<std::string, std::string> getParameter(const ros::NodeHandle &n, const std::string &key, std::map<std::string, std::string> fallback) {
+        if (!n.getParam(key, fallback)) {
+            ROS_WARN_STREAM("[" << ros::this_node::getName() << "] Could not get string value for "
+                                << n.getNamespace() << "/" << key
+                                << " from param server, using default empty map.");
+        }
+        return fallback;
+    }
+    template<>
+    std::map<std::string, double> getParameter(const ros::NodeHandle &n, const std::string &key, std::map<std::string, double> fallback) {
+        if (!n.getParam(key, fallback)) {
+            ROS_WARN_STREAM("[" << ros::this_node::getName() << "] Could not get string value for "
+                                << n.getNamespace() << "/" << key
+                                << " from param server, using default empty map.");
+        }
+        return fallback;
+    }
+    template<>
+    std::map<std::string, float> getParameter(const ros::NodeHandle &n, const std::string &key, std::map<std::string, float> fallback) {
+        if (!n.getParam(key, fallback)) {
+            ROS_WARN_STREAM("[" << ros::this_node::getName() << "] Could not get string value for "
+                                << n.getNamespace() << "/" << key
+                                << " from param server, using default empty map.");
+        }
+        return fallback;
+    }
+    template<>
+    std::map<std::string, int> getParameter(const ros::NodeHandle &n, const std::string &key, std::map<std::string, int> fallback) {
+        if (!n.getParam(key, fallback)) {
+            ROS_WARN_STREAM("[" << ros::this_node::getName() << "] Could not get string value for "
+                                << n.getNamespace() << "/" << key
+                                << " from param server, using default empty map.");
+        }
+        return fallback;
+    }
+    template<>
+    std::map<std::string, bool> getParameter(const ros::NodeHandle &n, const std::string &key, std::map<std::string, bool> fallback) {
+        if (!n.getParam(key, fallback)) {
+            ROS_WARN_STREAM("[" << ros::this_node::getName() << "] Could not get string value for "
+                                << n.getNamespace() << "/" << key
+                                << " from param server, using default empty map.");
+        }
+        return fallback;
+    }
+    /** @endcond */
 }
 
-#endif //CGV_CONNECTOR_WORKSPACE_NODEUTIL_H
+#endif //CCF_NODEUTIL_H
diff --git a/src/ccf/controller/MoveItRobotArmController.cpp b/src/ccf/controller/MoveItRobotArmController.cpp
index 64530a67792af5519156daf09fccf517aa29437a..1ba6e3af95701a0051d862b20da095bca8786db2 100644
--- a/src/ccf/controller/MoveItRobotArmController.cpp
+++ b/src/ccf/controller/MoveItRobotArmController.cpp
@@ -32,7 +32,13 @@ void MoveItRobotArmController::updateScene(ccf::SceneUpdateRequest &req) {
         } else {
             ccf::BinCheck srv;
             srv.request.id = req.ids[i];
-            bin_check_client.call(srv);
+
+            if (!bin_check_client.call(srv)) {
+                ROS_ERROR_STREAM("[MoveItRobotArmController] "
+                                 "Unable to call " << bin_check_client.getService() <<
+                                                   ". It " << (bin_check_client.exists() ? "exists" : "it does not exist")
+                                                   << ". Assuming each object is a BOX.");
+            }
 
             if (srv.response.isBin) {
                 object->set_type(Object_Type_BIN);
@@ -98,7 +104,13 @@ bool MoveItRobotArmController::pickAndDrop(Object &robot, Object &object, Object
     ccf::PickDropService srv;
     srv.request.object = object.id();
     srv.request.bin = bin.id();
-    pick_drop_client.call(srv);
+    if (!pick_drop_client.call(srv)) {
+        ROS_ERROR_STREAM("[MoveItRobotArmController] "
+                         "Unable to call " << pick_drop_client.getService() <<
+                                           ". It " << (pick_drop_client.exists() ? "exists" : "it does not exist")
+                                           << ".");
+        return false;
+    }
 
     // we explicitly do not remove the object right now, so we do not call the super method
     return true;
@@ -120,7 +132,13 @@ bool MoveItRobotArmController::pickAndPlace(Object &robot, Object &object, Objec
     srv.request.pose.position.x = location.pos().x();
     srv.request.pose.position.y = location.pos().y();
     srv.request.pose.position.z = location.pos().z();
-    pick_place_client.call(srv);
+    if (!pick_place_client.call(srv)) {
+        ROS_ERROR_STREAM("[MoveItRobotArmController] "
+                         "Unable to call " << pick_place_client.getService() <<
+                                           ". It " << (pick_place_client.exists() ? "exists" : "it does not exist")
+                                           << ".");
+        return false;
+    }
 
     // we explicitly do not move the object right now, so we do not call the super method
     return true;
@@ -129,10 +147,10 @@ bool MoveItRobotArmController::pickAndPlace(Object &robot, Object &object, Objec
 
 MoveItRobotArmController::MoveItRobotArmController(ros::NodeHandle &nodeHandle, const std::string &cellName)
         : RobotArmController(nodeHandle, cellName),
-          pick_drop_client(nodeHandle.serviceClient<ccf::PickDropService>("/pick_drop_service")),
-          pick_place_client(nodeHandle.serviceClient<ccf::PickPlaceService>("/pick_place_service")) {
+          pick_drop_client(nodeHandle.serviceClient<ccf::PickDropService>("/scene_controller/pick_drop_service")),
+          pick_place_client(nodeHandle.serviceClient<ccf::PickPlaceService>("/scene_controller/pick_place_service")) {
 
-    bin_check_client = nodeHandle.serviceClient<ccf::BinCheck>("/check_bin_service");
+    bin_check_client = nodeHandle.serviceClient<ccf::BinCheck>("/scene_controller/check_bin_service");
     get_scene_service = nodeHandle.advertiseService<ccf::SceneUpdateRequest, ccf::SceneUpdateResponse>(
             "updateCgvScene",
             [this](auto &req, auto &res) {
diff --git a/src/ccf/controller/RobotArmController.cpp b/src/ccf/controller/RobotArmController.cpp
index e3bad545e4d7825110bf428d001c0ff7c537a760..9ea39c59b97a8d89ed1d63c4403025dc7cc91d1b 100644
--- a/src/ccf/controller/RobotArmController.cpp
+++ b/src/ccf/controller/RobotArmController.cpp
@@ -93,7 +93,7 @@ RobotArmController::RobotArmController(const ros::NodeHandle &nodeHandle, const
           selectionAction([](const Selection &s) {}),
           cellName(cellName) {
 
-    selectionTopic = getParameter(nodeHandle, "topics/selection","selection");
+    selectionTopic = getParameter<std::string>(nodeHandle, "topics/selection","selection");
     initSceneTopic = getParameter(nodeHandle, "topics/initScene",cellName + "/scene/init");
     sendSceneTopic = getParameter(nodeHandle, "topics/sendScene",cellName + "/scene/update");
     commandTopic = getParameter(nodeHandle, "topics/command",cellName + "/command");
diff --git a/src/ccf/util/scene_controller_node.cpp b/src/ccf/util/scene_controller_node.cpp
index fe89962caeb17a51485cb084b2345ccf17847da4..c2654747a09f06d19a38fba703ce69c0ffd102be 100644
--- a/src/ccf/util/scene_controller_node.cpp
+++ b/src/ccf/util/scene_controller_node.cpp
@@ -40,7 +40,7 @@ namespace world_state {
     std::string current_picked_object_id;
     std::string current_bin_id;
     geometry_msgs::Point current_transform;
-    double open_amount = 0.08;
+    double open_amount = 0.078;
     bool is_initialized = false;
     bool is_table_configured = false;
     bool is_simulated_robot = false;
@@ -712,7 +712,7 @@ bool pickAndDropObjectCallback(ccf::PickDropService::Request &req,
 
 int main(int argc, char **argv) {
     ros::init(argc, argv, "scene_controller");
-    ros::NodeHandle n;
+    ros::NodeHandle n("scene_controller");
     ros::AsyncSpinner spinner(7);
     spinner.start();
 
@@ -730,7 +730,7 @@ int main(int argc, char **argv) {
 
         if (!world_state::is_simulated_robot) {
 
-            ROS_INFO_STREAM("[SCENECONTROLLER] Using setup for real robot.");
+            ROS_ERROR_STREAM("[SCENECONTROLLER] Using setup for real robot.");
 
 
             if (!ros::param::has("max_grasp_approach_velocity") ||
@@ -746,26 +746,6 @@ int main(int argc, char **argv) {
 
                 ros::param::set("max_grasp_transition_velocity", 0.05);
                 ros::param::set("max_grasp_transition_acceleration", 0.05);
-            } else {
-                double max_grasp_approach_velocity = 0;
-                double max_grasp_approach_acceleration = 0;
-                double max_grasp_transition_velocity = 0;
-                double max_grasp_transition_acceleration = 0;
-
-                ros::param::get("max_grasp_approach_velocity", max_grasp_approach_velocity);
-                ros::param::get("max_grasp_approach_acceleration", max_grasp_approach_acceleration);
-
-                ros::param::get("max_grasp_transition_velocity", max_grasp_transition_velocity);
-                ros::param::get("max_grasp_transition_acceleration", max_grasp_transition_acceleration);
-
-                ROS_INFO_STREAM(
-                        "[SCENECONTROLLER] Applied max_grasp_approach_velocity " << max_grasp_approach_velocity);
-                ROS_INFO_STREAM("[SCENECONTROLLER] Applied max_grasp_approach_acceleration "
-                                        << max_grasp_approach_acceleration);
-                ROS_INFO_STREAM(
-                        "[SCENECONTROLLER] Applied max_grasp_transition_velocity " << max_grasp_transition_velocity);
-                ROS_INFO_STREAM("[SCENECONTROLLER] Applied max_grasp_transition_acceleration "
-                                        << max_grasp_transition_acceleration);
             }
 
             if (!ros::param::has("tud_grasp_force")) {
@@ -804,7 +784,7 @@ int main(int argc, char **argv) {
                                                                    boost::bind(&manualScenePush, _1,
                                                                                boost::ref(n)));
 
-    ros::ServiceServer service = n.advertiseService("/check_bin_service", checkBin);
+    ros::ServiceServer service = n.advertiseService("check_bin_service", checkBin);
 
     ros::ServiceServer pick_drop_service = n.advertiseService<ccf::PickDropService::Request, ccf::PickDropService::Response>(
             "pick_drop_service",
diff --git a/src/dummy_cgv_controller.cpp b/src/dummy_cgv_controller.cpp
index fcd8d58ce8d92b6a85c5f73908e2e9d5b56556ce..a05133b0cfa3dcc651b910f6aaf954dce29a7db0 100644
--- a/src/dummy_cgv_controller.cpp
+++ b/src/dummy_cgv_controller.cpp
@@ -41,7 +41,7 @@ int main(int argc, char **argv) {
 
     // add an NNG connection
     std::unique_ptr<NngConnection> connection = std::make_unique<NngConnection>(cgv_address);
-    connection->setReceiveTopic(getParameter(n, "topics/selection", "selection"));
+    connection->setReceiveTopic(getParameter<std::string>(n, "topics/selection", "selection"));
     connection->setSendTopic(getParameter(n, "topics/scene", NODE_NAME + "/scene/update"));
     connector.addConnection(std::move(connection));
 
diff --git a/src/dummy_rag_controller_a.cpp b/src/dummy_rag_controller_a.cpp
index e597bbadb1532da82f87fecebd5b5082c7e34156..f1ee30c697f28ef5c183553221b0865ae6aaa5ad 100644
--- a/src/dummy_rag_controller_a.cpp
+++ b/src/dummy_rag_controller_a.cpp
@@ -37,7 +37,7 @@ int main(int argc, char **argv) {
 
     ros::NodeHandle n("ceti_connector"); // namespace
 
-    std::string cgv_address = getParameter(n, "cgv_address", "tcp://*:6576");
+    std::string cgv_address = getParameter<std::string>(n, "cgv_address", "tcp://*:6576");
 
     DummyRobotArmController connector{n, CELL_NAME};
 
@@ -46,12 +46,12 @@ int main(int argc, char **argv) {
 
     // add an NNG connection
     std::unique_ptr<NngConnection> connection = std::make_unique<NngConnection>(cgv_address);
-    connection->setReceiveTopic(getParameter(n, "topics/selection", "selection"));
+    connection->setReceiveTopic(getParameter<std::string>(n, "topics/selection", "selection"));
     connection->setSendTopic(getParameter(n, "topics/scene", CELL_NAME + "/scene/update"));
     connector.addConnection(std::move(connection));
 
     // add an MQTT connection
-    std::string mqtt_address = getParameter(n, "mqtt/mqtt_address", "tcp://localhost:1883");
+    std::string mqtt_address = getParameter<std::string>(n, "mqtt/mqtt_address", "tcp://localhost:1883");
     std::unique_ptr<MqttConnection> mqtt_connection = std::make_unique<MqttConnection>(mqtt_address, NODE_NAME);
     mqtt_connection->addTopic(CELL_NAME + "/scene/init");
     mqtt_connection->addTopic(CELL_NAME + "/command");
diff --git a/src/dummy_rag_controller_b.cpp b/src/dummy_rag_controller_b.cpp
index 6a2a6ef8b32496e15fd118f9bc387bd5633424b5..0004ef290fa7d42533c9f87b2190daa729f8bea0 100644
--- a/src/dummy_rag_controller_b.cpp
+++ b/src/dummy_rag_controller_b.cpp
@@ -36,7 +36,7 @@ int main(int argc, char **argv) {
 
     ros::NodeHandle n("ceti_connector"); // namespace
 
-    std::string cgv_address = getParameter(n, "cgv_address", "tcp://*:6576");
+    std::string cgv_address = getParameter<std::string>(n, "cgv_address", "tcp://*:6576");
 
     std::string cell_prefix = getParameter(n, "place_b_prefix", CELL_NAME);
 
@@ -47,7 +47,7 @@ int main(int argc, char **argv) {
     // connector.loadScene("/home/jm/work/git/ceti/models2021/src/ccf/config/config_pick_place_scene.json");
 
     // add an MQTT connection
-    std::string mqtt_address = getParameter(n, "mqtt/mqtt_address", "tcp://localhost:1883");
+    std::string mqtt_address = getParameter<std::string>(n, "mqtt/mqtt_address", "tcp://localhost:1883");
     std::unique_ptr<MqttConnection> mqtt_connection = std::make_unique<MqttConnection>(mqtt_address, NODE_NAME);
     mqtt_connection->addTopic(connector.getInitSceneTopic());
     mqtt_connection->addTopic(connector.getCommandTopic());
diff --git a/src/moveit_cgv_controller.cpp b/src/moveit_cgv_controller.cpp
index 019a9634e42c400240706f9f50e876f026b0ddcf..296b943d8b94300fd3279bf33ac0db95db3973a8 100644
--- a/src/moveit_cgv_controller.cpp
+++ b/src/moveit_cgv_controller.cpp
@@ -40,7 +40,7 @@ int main(int argc, char **argv) {
 
     // add an NNG connection
     std::unique_ptr<NngConnection> connection = std::make_unique<NngConnection>(cgv_address);
-    connection->setReceiveTopic(getParameter(n, "topics/selection", "selection"));
+    connection->setReceiveTopic(getParameter<std::string>(n, "topics/selection", "selection"));
     connection->setSendTopic(getParameter(n, "topics/scene", NODE_NAME + "/scene/update"));
     connector.addConnection(std::move(connection));
 
@@ -117,4 +117,4 @@ int main(int argc, char **argv) {
     ros::spin();
 
     return 0;
-}
\ No newline at end of file
+}
diff --git a/test/test_NodeUtil.cpp b/test/test_NodeUtil.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f34f46da9eb29196e3c4c798de2d9076ee2dc97b
--- /dev/null
+++ b/test/test_NodeUtil.cpp
@@ -0,0 +1,201 @@
+#include <ros/ros.h>
+
+#include <string>
+#include <map>
+#include<vector>
+
+#include "ccf/util/NodeUtil.h"
+
+#include <gtest/gtest.h>
+
+using CetiRosToolbox::getParameter;
+
+class NodeUtilTest : public ::testing::Test {
+protected:
+
+    ros::NodeHandle n;
+
+    void SetUp() override {
+        /**
+         * Register a "node_util_test" node
+         */
+        n = ros::NodeHandle("node_util_test");
+
+        n.setParam("stringKey", std::string("stringValue"));
+        n.setParam("intKey", 42);
+        n.setParam("doubleKey", 0.42);
+        n.setParam("boolKey", true);
+        n.setParam("xmlKey", XmlRpc::XmlRpcValue(42));
+        n.setParam("stringListKey", std::vector<std::string>{"a", "b", "c"});
+        n.setParam("boolListKey", std::vector<bool>{true, false, true});
+        n.setParam("intListKey", std::vector<int>{1, 2, 4});
+        n.setParam("floatListKey", std::vector<float>{0.0f, 1.0f, 0.42f});
+        n.setParam("doubleListKey", std::vector<double>{0.5, -2.0});
+        std::map<std::string, std::string> stringMap;
+        stringMap["key1"] = "value1";
+        n.setParam("stringMapKey", stringMap);
+        std::map<std::string, int> intMap;
+        intMap["key1"] = 42;
+        n.setParam("intMapKey", intMap);
+    }
+};
+
+TEST_F(NodeUtilTest, ReadNonExistingString) {
+    std::string param = "initialValue";
+    EXPECT_FALSE(n.getParam("key", param));
+    EXPECT_EQ(param, "initialValue");
+    auto result = getParameter<std::string>(n, "key");
+    ASSERT_EQ(result, "");
+}
+
+TEST_F(NodeUtilTest, ReadNonExistingStringWithFallback) {
+    std::string param = "initialValue";
+    EXPECT_FALSE(n.getParam("key", param));
+    EXPECT_EQ(param, "initialValue");
+    auto result = getParameter<std::string>(n, "key", "fallBackParam");
+    ASSERT_EQ(result, "fallBackParam");
+}
+
+TEST_F(NodeUtilTest, ReadExistingSimpleDataTypes) {
+    {
+        auto stringValue = getParameter<std::string>(n, "stringKey");
+        ASSERT_EQ(stringValue, std::string("stringValue"));
+    }
+    {
+        auto intValue = getParameter<int>(n, "intKey");
+        ASSERT_EQ(intValue, 42);
+    }
+    {
+        auto doubleValue = getParameter<double>(n, "doubleKey");
+        ASSERT_EQ(doubleValue, 0.42);
+    }
+    {
+        auto boolValue = getParameter<bool>(n, "boolKey");
+        ASSERT_EQ(boolValue, true);
+    }
+    {
+        auto xmlValue = getParameter<XmlRpc::XmlRpcValue>(n, "xmlKey");
+        // XmlRpc prints the synonymous types 'int' and 'i4' both as 'i4'
+        ASSERT_EQ(xmlValue.toXml(), "<value><i4>42</i4></value>");
+    }
+}
+
+TEST_F(NodeUtilTest, ReadExistingVectorDataTypes) {
+    {
+        auto stringListValue = getParameter<std::vector<std::string>>(n, "stringListKey");
+        std::vector<std::string> expectedStringListValue{"a", "b", "c"};
+        ASSERT_EQ(stringListValue, expectedStringListValue);
+    }
+    {
+        auto boolListValue = getParameter<std::vector<bool>>(n, "boolListKey");
+        std::vector<bool> expectedBoolListValue{true, false, true};
+        ASSERT_EQ(boolListValue, expectedBoolListValue);
+    }
+    {
+        auto intListValue = getParameter<std::vector<int>>(n, "intListKey");
+        std::vector<int> expectedIntListValue{1, 2, 4};
+        ASSERT_EQ(intListValue, expectedIntListValue);
+    }
+    {
+        auto floatListValue = getParameter<std::vector<float>>(n, "floatListKey");
+        std::vector<float> expectedFloatListValue{0.0f, 1.0f, 0.42f};
+        ASSERT_EQ(floatListValue, expectedFloatListValue);
+    }
+    {
+        auto doubleListValue = getParameter<std::vector<double>>(n, "doubleListKey");
+        std::vector<double> expectedDoubleListValue{0.5, -2.0};
+        ASSERT_EQ(doubleListValue, expectedDoubleListValue);
+    }
+}
+
+TEST_F(NodeUtilTest, ReadExistingMapDataTypes) {
+    {
+        auto stringMapValue = getParameter<std::map<std::string, std::string>>(n, "stringMapKey");
+        ASSERT_EQ(stringMapValue["key1"], "value1");
+    }
+    {
+        auto intMapValue = getParameter<std::map<std::string, int>>(n, "intMapKey");
+        ASSERT_EQ(intMapValue["key1"], 42);
+    }
+}
+
+TEST_F(NodeUtilTest, ReadExistingSimpleDataTypesWithFallback) {
+    {
+        auto stringValue = getParameter<std::string>(n, "stringKey", "fallback");
+        ASSERT_EQ(stringValue, std::string("stringValue"));
+    }
+    {
+        auto intValue = getParameter<int>(n, "intKey", -1);
+        ASSERT_EQ(intValue, 42);
+        intValue = getParameter(n, "intKey", -1);
+        ASSERT_EQ(intValue, 42);
+    }
+    {
+        auto doubleValue = getParameter<double>(n, "doubleKey", -1.0);
+        ASSERT_EQ(doubleValue, 0.42);
+        doubleValue = getParameter(n, "doubleKey", -1.0);
+        ASSERT_EQ(doubleValue, 0.42);
+    }
+    {
+        auto boolValue = getParameter<bool>(n, "boolKey", false);
+        ASSERT_EQ(boolValue, true);
+        boolValue = getParameter(n, "boolKey", false);
+        ASSERT_EQ(boolValue, true);
+    }
+    {
+        auto xmlValue = getParameter<XmlRpc::XmlRpcValue>(n, "xmlKey", XmlRpc::XmlRpcValue(23));
+        ASSERT_EQ(xmlValue.toXml(), "<value><i4>42</i4></value>");
+        xmlValue = getParameter(n, "xmlKey", XmlRpc::XmlRpcValue(23));
+        ASSERT_EQ(xmlValue.toXml(), "<value><i4>42</i4></value>");
+    }
+}
+
+TEST_F(NodeUtilTest, ReadExistingVectorDataTypesWithFallback) {
+    {
+        std::vector<std::string> expectedStringListValue{"a", "b", "c"};
+        auto stringListValue = getParameter<std::vector<std::string>>(n, "stringListKey", std::vector<std::string>{"x"});
+        ASSERT_EQ(stringListValue, expectedStringListValue);
+        stringListValue = getParameter(n, "stringListKey", std::vector<std::string>{"x"});
+        ASSERT_EQ(stringListValue, expectedStringListValue);
+    }
+    {
+        std::vector<bool> expectedBoolListValue{true, false, true};
+        auto boolListValue = getParameter<std::vector<bool>>(n, "boolListKey", std::vector<bool>{true});
+        ASSERT_EQ(boolListValue, expectedBoolListValue);
+        boolListValue = getParameter(n, "boolListKey", std::vector<bool>{true});
+        ASSERT_EQ(boolListValue, expectedBoolListValue);
+    }
+    {
+        auto intListValue = getParameter<std::vector<int>>(n, "intListKey", std::vector<int>{7});
+        std::vector<int> expectedIntListValue{1, 2, 4};
+        ASSERT_EQ(intListValue, expectedIntListValue);
+    }
+    {
+        auto floatListValue = getParameter<std::vector<float>>(n, "floatListKey", std::vector<float>{0.5f});
+        std::vector<float> expectedFloatListValue{0.0f, 1.0f, 0.42f};
+        ASSERT_EQ(floatListValue, expectedFloatListValue);
+    }
+    {
+        auto doubleListValue = getParameter<std::vector<double>>(n, "doubleListKey", std::vector<double>{0.5});
+        std::vector<double> expectedDoubleListValue{0.5, -2.0};
+        ASSERT_EQ(doubleListValue, expectedDoubleListValue);
+    }
+}
+
+TEST_F(NodeUtilTest, ReadNonExistingMapDataTypesWithFallback) {
+    {
+        auto stringMapValue = getParameter<std::map<std::string, std::string>>(n, "unknownKey", std::map<std::string,std::string>{});
+        ASSERT_EQ(stringMapValue.size(), 0);
+    }
+    {
+        auto intMapValue = getParameter<std::map<std::string, int>>(n, "unknownKey", std::map<std::string, int>{});
+        ASSERT_EQ(intMapValue["key1"], 0);
+    }
+}
+
+int main(int argc, char **argv) {
+    testing::InitGoogleTest(&argc, argv);
+    ros::init(argc, argv, "node_util_test");
+    return RUN_ALL_TESTS();
+
+}
\ No newline at end of file
diff --git a/test/test_NodeUtil.test b/test/test_NodeUtil.test
new file mode 100644
index 0000000000000000000000000000000000000000..ed5f89772cdfb75c118d0802d83867a2356523db
--- /dev/null
+++ b/test/test_NodeUtil.test
@@ -0,0 +1,3 @@
+<launch>
+    <test pkg="ccf" type="ccf-NodeUtil-test" test-name="NodeUtil_test" />
+</launch>