diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 89bf431327f6864850c98cad85943178e0d07bdb..a577ac878d84933093ebfd33b1a9a586a827f378 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -70,6 +70,7 @@ INSTALL(FILES
   ${CMAKE_CURRENT_SOURCE_DIR}/dynamic_graph/sot/dynamics/__init__.py
   ${CMAKE_CURRENT_SOURCE_DIR}/dynamic_graph/sot/dynamics/humanoid_robot.py
   ${CMAKE_CURRENT_SOURCE_DIR}/dynamic_graph/sot/dynamics/parser.py
+  ${CMAKE_CURRENT_SOURCE_DIR}/dynamic_graph/sot/dynamics/solver.py
   DESTINATION ${PYTHON_SITELIB}/dynamic_graph/sot/dynamics
   )
 
diff --git a/src/dynamic_graph/sot/dynamics/solver.py b/src/dynamic_graph/sot/dynamics/solver.py
new file mode 100644
index 0000000000000000000000000000000000000000..23ff078ee5d3518d72d3f158104f7cd47932812e
--- /dev/null
+++ b/src/dynamic_graph/sot/dynamics/solver.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright 2011, Florent Lamiraux, Thomas Moulard, JRL, CNRS/AIST
+#
+# This file is part of dynamic-graph.
+# dynamic-graph is free software: you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation, either version 3 of
+# the License, or (at your option) any later version.
+#
+# dynamic-graph is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Lesser Public License for more details.  You should have
+# received a copy of the GNU Lesser General Public License along with
+# dynamic-graph. If not, see <http://www.gnu.org/licenses/>.
+
+from dynamic_graph import plug
+from dynamic_graph.sot.core import SOT
+
+class Solver:
+    robot = None
+    sot = None
+
+    def __init__(self, robot):
+        self.robot = robot
+        self.sot = SOT('solver')
+        self.sot.signal('damping').value = 1e-6
+        self.sot.setNumberDofs(self.robot.dimension)
+
+        if robot.device:
+            plug(self.sot.signal('control'), robot.device.signal('control'))
+            plug(self.robot.device.state,
+                 self.robot.dynamic.position)
diff --git a/unitTesting/python/tools.py b/src/dynamic_graph/sot/dynamics/tools.py
similarity index 91%
rename from unitTesting/python/tools.py
rename to src/dynamic_graph/sot/dynamics/tools.py
index 4a4f1c8be5b09f4026b6232acc312ae7267e4df0..32ce0c6cb47f44d39559437594069e0c967b5616 100755
--- a/unitTesting/python/tools.py
+++ b/src/dynamic_graph/sot/dynamics/tools.py
@@ -21,6 +21,7 @@ from optparse import OptionParser
 from dynamic_graph import plug
 from dynamic_graph.sot.core import SOT
 from dynamic_graph.sot.dynamics.hrp2 import Hrp2Laas, Hrp2Jrl
+from dynamic_graph.sot.dynamics.solver import Solver
 
 
 # Robotviewer is optional
@@ -140,26 +141,6 @@ def checkFinalConfiguration(position, finalPosition):
                                      zip(position, finalPosition)))
         sys.exit(1)
 
-##################
-# Helper classes #
-##################
-
-class Solver:
-    robot = None
-    sot = None
-
-    def __init__(self, robot):
-        self.robot = robot
-        self.sot = SOT('solver')
-        self.sot.signal('damping').value = 1e-6
-        self.sot.setNumberDofs(self.robot.dimension)
-
-        if robot.device:
-            plug(self.sot.signal('control'), robot.device.signal('control'))
-            plug(self.robot.device.state,
-                 self.robot.dynamic.position)
-
-
 ##################
 # Initialization #
 ##################