diff --git a/TODOS b/TODOS
new file mode 100644
index 0000000000000000000000000000000000000000..2efde79ddc07f8349329f836aa510f3dc59362c2
--- /dev/null
+++ b/TODOS
@@ -0,0 +1,23 @@
+IMPORTANT
+-------------
+1. urdf
+- understand how it works (read the docs)
+- use the calibration data from the robot and put it in the urdf
+- ensure that gripper urdf makes sense
+- do test to see if the calibration is ok
+- recalibrate if necessary
+
+NICE TO HAVE
+---------------
+1. other inverse kinematics algorithms
+- standard list of them, for fun and to practise eigen and pinocchio a bit
+
+2. (ur) simulation
+- put the gripper on the robot in ursim
+- possibly fiddle to get communication with it in the sim to work
+
+FUTURE PROSPECTS, CURRENT URGENCY ZERO
+--------------------------------------
+3. hooking up with a real simulator, ex. mujoco
+
+
diff --git a/clik/.robotiq_gripper.py.swp b/clik/.robotiq_gripper.py.swp
deleted file mode 100644
index 6f387ee01160141069385d952c68d35d5a67715d..0000000000000000000000000000000000000000
Binary files a/clik/.robotiq_gripper.py.swp and /dev/null differ
diff --git a/dmp/DMP.m b/dmp/DMP.m
new file mode 100644
index 0000000000000000000000000000000000000000..176c3fdf31a3a17817d2f6b4d7b82d87eafb9e16
--- /dev/null
+++ b/dmp/DMP.m
@@ -0,0 +1,128 @@
+classdef DMP
+    properties
+        % State
+        x % [z; y; s]
+        tau
+        tauDot
+        % Settings
+        K
+        D
+        alpha_s
+        n_kernel
+        n
+        g
+        y0
+        nominal_tau
+        x0
+        mu
+        std_dev
+        w
+        demo_traj
+    end
+    
+    methods
+        function obj = DMP(dmp_params,demo_traj)
+            obj.K = dmp_params.K;
+            obj.D = dmp_params.D;
+            obj.alpha_s = dmp_params.alpha_s;
+            obj.n_kernel = dmp_params.n_kernel;
+            obj.demo_traj = demo_traj;
+            obj = obj.fit();
+        end
+        
+        function obj = init(obj)
+            obj.x = obj.x0;
+            obj.tau = obj.nominal_tau;
+            obj.tauDot = 0;
+        end
+        
+        function obj = step(obj,tauDot,dt)
+            xDot = [obj.h();obj.z();-obj.s()]/obj.tau;
+            obj.x = obj.x + xDot*dt;
+            obj.tau = obj.tau + tauDot*dt;
+            obj.tauDot = tauDot;
+        end
+        
+        function ref_pos_val = ref_pos(obj)
+            ref_pos_val = obj.y();
+        end
+        
+        function ref_pos_val = ref_vel(obj)
+            ref_pos_val = obj.z()/obj.tau;
+        end
+        
+        function ref_pos_val = ref_acc(obj)
+            ref_pos_val = (obj.h() - obj.tauDot*obj.z()) / obj.tau^2;
+        end
+                
+        function yVal = y(obj)
+            yVal = obj.x(obj.n+1:2*obj.n);
+        end
+        
+        function zVal = z(obj)
+            zVal = obj.x(1:obj.n);
+        end
+        
+        function sVal = s(obj)
+            sVal = obj.x(end);
+        end
+        
+        function hVal = h(obj)
+            psi = exp(-1./(2*obj.std_dev.^2).*(obj.s()-obj.mu).^2);
+            hVal = obj.K*(obj.g-obj.y()) - obj.D*obj.z() + obj.w*psi' ./ max(sum(psi),1e-8) .* (obj.g-obj.y0)*obj.s();
+        end
+        
+        function traj = rollout(obj,dt)
+            dmp = obj.init();
+            traj.t = 0;
+            traj.pos = dmp.y();
+            traj.vel = dmp.z()/dmp.nominal_tau;
+            traj.acc = dmp.h()/dmp.nominal_tau^2;
+            traj.s = dmp.s();
+            while norm(abs(dmp.y()-dmp.g)) > 1e-2
+                dmp = dmp.step(0,dt);
+                traj.t = [traj.t traj.t(end)+dt];
+                traj.pos = [traj.pos dmp.ref_pos()];
+                traj.vel = [traj.vel dmp.ref_vel()];
+                traj.acc = [traj.acc dmp.ref_acc()];
+                traj.s = [traj.s dmp.s()];
+            end
+        end
+       
+       function obj = fit(obj)
+
+            psi = @(s,c,d) exp(-1./(2*d.^2).*(s-c).^2); % Basis function
+            obj.n = size(obj.demo_traj.pos,1);
+            obj.y0 = obj.demo_traj.pos(:,1);
+            obj.g = obj.demo_traj.pos(:,end);
+            obj.x0 = [zeros(obj.n,1); obj.y0; 1];
+            obj.nominal_tau = obj.demo_traj.t(end);
+
+            lastKernel = 1*obj.nominal_tau; % Time of last kernel center
+            ct = (0:lastKernel/(obj.n_kernel-1):lastKernel); % Time means of basis functions
+            obj.mu = exp(-obj.alpha_s/obj.nominal_tau*ct); % Phase means of basis functions
+            obj.std_dev  = abs((diff(obj.mu)));
+            obj.std_dev  = [obj.std_dev obj.std_dev(end)]; % Standard deviation of basis functions
+
+            svec = exp(-obj.alpha_s/obj.nominal_tau*obj.demo_traj.t);
+            obj.w = zeros(obj.n,obj.n_kernel);
+            for varNr = 1:obj.n
+                if abs(obj.g(varNr)-obj.y0(varNr)) < 0.001
+                    continue;
+                end
+                fGain = svec*(obj.g(varNr)-obj.y0(varNr));
+                f_target = obj.nominal_tau^2*obj.demo_traj.acc(varNr,:) - obj.K*(obj.g(varNr)-obj.demo_traj.pos(varNr,:)) + obj.D*obj.nominal_tau*obj.demo_traj.vel(varNr,:);
+                for i = 1:obj.n_kernel
+                    Gamma_i = diag(psi(svec,obj.mu(i),obj.std_dev(i)));
+                    if fGain*Gamma_i*fGain' < 1e-8
+                        obj.w(varNr,i) = 0;
+                    else
+                        obj.w(varNr,i) = fGain*Gamma_i*f_target'/(fGain*Gamma_i*fGain');
+                    end
+                end
+            end
+       end
+        
+    end
+end
+
diff --git a/dmp/dmp_node b/dmp/dmp_node
new file mode 100755
index 0000000000000000000000000000000000000000..9a72514662eb72ffbbcc665108375321c8a1f256
--- /dev/null
+++ b/dmp/dmp_node
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+
+from motion_planning.dmp import DMP, TCVelAccConstrained, NoTC
+import numpy as np
+import rospy
+from robot_ctrl.msg import CtrlTarget
+from std_msgs.msg import Float64, String
+from motion_planning.msg import DMPState
+
+
+class DMPNode:
+    def __init__(self):
+        self.dmp_active = False
+        self.rate = None
+        self.dt = None
+        self.dmp = DMP()
+        self.tc = None
+
+        # Load target trajectory and fit DMP
+        self.load_trajectory()
+
+        # Load parameters from server
+        self.load_params()
+
+        # Setup ros topics
+        self.target_pub = rospy.Publisher("robot_ctrl/command", CtrlTarget, queue_size=1)
+        self.dmp_state = rospy.Publisher("motion_planning/dmp_state", DMPState, queue_size=1)
+        rospy.Subscriber("motion_planning/command", String, self.command_parser)
+
+        # Go into spin
+        self.spin()
+
+    def load_trajectory(self):
+        if rospy.has_param('motion_planning/trajectory_loadpath'):
+            # Set demo trajectory
+            trajectory_loadpath = rospy.get_param('motion_planning/trajectory_loadpath')
+            data = np.genfromtxt(trajectory_loadpath, delimiter=',')
+            t_demo = data[:, 0]
+            path_demo = np.array(data[:, 1:]).T
+            self.dmp.fit(path_demo, t_demo)
+            rospy.set_param("motion_planning/init_pos", np.squeeze(self.dmp.y0).tolist())
+        else:
+            rospy.logerr("Could not load trajectory. Parameter " + rospy.get_namespace() +
+                         "motion_planning/trajectory_loadpath not found")
+
+    def load_params(self):
+        # Load parameters from server
+        update_rate = rospy.get_param('motion_planning/update_rate', 125)
+        tc_type = rospy.get_param('motion_planning/tc/type', 0)
+        if rospy.has_param('motion_planning/tau0'):
+            self.dmp.tau0 = rospy.get_param('motion_planning/tau0')
+
+        # Set temporal coupling
+        if tc_type == 0:
+            self.tc = NoTC()
+        elif tc_type == 1:
+            gamma_nominal = rospy.get_param('motion_planning/tc/gamma_nominal', 1)
+            gamma_a = rospy.get_param('motion_planning/tc/gamma_a', 0.5)
+            v_max = np.array(rospy.get_param('motion_planning/tc/v_max', np.inf))
+            a_max = np.array(rospy.get_param('motion_planning/tc/a_max', np.inf))
+            eps = np.array(rospy.get_param('motion_planning/tc/eps', 0.001))
+            self.tc = TCVelAccConstrained(gamma_nominal, gamma_a, v_max, a_max, eps)
+        # Set rate for ros spin
+        self.rate = rospy.Rate(update_rate)
+        self.dt = 1.0 / update_rate
+
+    def command_parser(self, msg):
+        if msg.data == 'start':
+            self.dmp_active = True
+        elif msg.data == 'stop':
+            self.dmp_active = False
+        elif msg.data == 'reset':
+            self.dmp.reset()
+            self.dmp_active = False
+            rospy.loginfo("Reset motion_planner.")
+        elif msg.data == 'step':
+            self.dmp.step(self.dt)
+        elif msg.data == 'load_params':
+            self.load_params()
+            rospy.loginfo("Reloaded motion_planner parameters.")
+        elif msg.data == 'load_trajectory':
+            self.load_trajectory()
+            rospy.loginfo("Reloaded motion_planner trajectory.")
+        else:
+            rospy.loginfo("Invalid command string for motion planner.")
+
+    # spin -----------------------------------------------------
+    # -----------------------------------------------------------
+    def spin(self):
+        print_flag = True
+        while (not rospy.is_shutdown()):
+
+            if self.dmp_active:
+                # Step DMP
+                self.dmp.step(self.dt)
+                # Step temporal coupling
+                tau = self.dmp.tau + self.tc.update(self.dmp, self.dt) * self.dt
+                self.dmp.set_tau(tau)
+                # Send target trajectory state command
+                pub_msg = CtrlTarget()
+                pub_msg.header.stamp = rospy.Time.now()
+                pub_msg.acceleration = self.dmp.acc
+                pub_msg.velocity = self.dmp.vel
+                pub_msg.position = self.dmp.pos
+                self.target_pub.publish(pub_msg)
+            else:
+                print_flag = True
+
+            # Publish DMP state command
+            pub_msg = DMPState()
+            pub_msg.header.stamp = rospy.Time.now()
+            pub_msg.acceleration = self.dmp.acc
+            pub_msg.velocity = self.dmp.vel
+            pub_msg.position = self.dmp.pos
+            pub_msg.theta = self.dmp.theta
+            pub_msg.s = self.dmp.s()
+            pub_msg.tau = self.dmp.tau
+            self.dmp_state.publish(pub_msg)
+
+            # Notify when DMP trajectory is finished
+            if print_flag and self.dmp.theta > 1:
+                rospy.loginfo("DMP trajectory finished.")
+                print_flag = False
+
+            # Sleep
+            self.rate.sleep()
+
+
+# --------------------------------------------------------------------
+# Here is the main entry point
+if __name__ == '__main__':
+    try:
+        # Init the node:
+        rospy.init_node('DMPNode')
+
+        # Initializing and continue running the main class:
+        DMPNode()
+
+    except rospy.ROSInterruptException:
+        pass
diff --git a/dmp/matlab/DMP.m b/dmp/matlab/DMP.m
new file mode 100644
index 0000000000000000000000000000000000000000..176c3fdf31a3a17817d2f6b4d7b82d87eafb9e16
--- /dev/null
+++ b/dmp/matlab/DMP.m
@@ -0,0 +1,128 @@
+classdef DMP
+    properties
+        % State
+        x % [z; y; s]
+        tau
+        tauDot
+        % Settings
+        K
+        D
+        alpha_s
+        n_kernel
+        n
+        g
+        y0
+        nominal_tau
+        x0
+        mu
+        std_dev
+        w
+        demo_traj
+    end
+    
+    methods
+        function obj = DMP(dmp_params,demo_traj)
+            obj.K = dmp_params.K;
+            obj.D = dmp_params.D;
+            obj.alpha_s = dmp_params.alpha_s;
+            obj.n_kernel = dmp_params.n_kernel;
+            obj.demo_traj = demo_traj;
+            obj = obj.fit();
+        end
+        
+        function obj = init(obj)
+            obj.x = obj.x0;
+            obj.tau = obj.nominal_tau;
+            obj.tauDot = 0;
+        end
+        
+        function obj = step(obj,tauDot,dt)
+            xDot = [obj.h();obj.z();-obj.s()]/obj.tau;
+            obj.x = obj.x + xDot*dt;
+            obj.tau = obj.tau + tauDot*dt;
+            obj.tauDot = tauDot;
+        end
+        
+        function ref_pos_val = ref_pos(obj)
+            ref_pos_val = obj.y();
+        end
+        
+        function ref_pos_val = ref_vel(obj)
+            ref_pos_val = obj.z()/obj.tau;
+        end
+        
+        function ref_pos_val = ref_acc(obj)
+            ref_pos_val = (obj.h() - obj.tauDot*obj.z()) / obj.tau^2;
+        end
+                
+        function yVal = y(obj)
+            yVal = obj.x(obj.n+1:2*obj.n);
+        end
+        
+        function zVal = z(obj)
+            zVal = obj.x(1:obj.n);
+        end
+        
+        function sVal = s(obj)
+            sVal = obj.x(end);
+        end
+        
+        function hVal = h(obj)
+            psi = exp(-1./(2*obj.std_dev.^2).*(obj.s()-obj.mu).^2);
+            hVal = obj.K*(obj.g-obj.y()) - obj.D*obj.z() + obj.w*psi' ./ max(sum(psi),1e-8) .* (obj.g-obj.y0)*obj.s();
+        end
+        
+        function traj = rollout(obj,dt)
+            dmp = obj.init();
+            traj.t = 0;
+            traj.pos = dmp.y();
+            traj.vel = dmp.z()/dmp.nominal_tau;
+            traj.acc = dmp.h()/dmp.nominal_tau^2;
+            traj.s = dmp.s();
+            while norm(abs(dmp.y()-dmp.g)) > 1e-2
+                dmp = dmp.step(0,dt);
+                traj.t = [traj.t traj.t(end)+dt];
+                traj.pos = [traj.pos dmp.ref_pos()];
+                traj.vel = [traj.vel dmp.ref_vel()];
+                traj.acc = [traj.acc dmp.ref_acc()];
+                traj.s = [traj.s dmp.s()];
+            end
+        end
+       
+       function obj = fit(obj)
+
+            psi = @(s,c,d) exp(-1./(2*d.^2).*(s-c).^2); % Basis function
+            obj.n = size(obj.demo_traj.pos,1);
+            obj.y0 = obj.demo_traj.pos(:,1);
+            obj.g = obj.demo_traj.pos(:,end);
+            obj.x0 = [zeros(obj.n,1); obj.y0; 1];
+            obj.nominal_tau = obj.demo_traj.t(end);
+
+            lastKernel = 1*obj.nominal_tau; % Time of last kernel center
+            ct = (0:lastKernel/(obj.n_kernel-1):lastKernel); % Time means of basis functions
+            obj.mu = exp(-obj.alpha_s/obj.nominal_tau*ct); % Phase means of basis functions
+            obj.std_dev  = abs((diff(obj.mu)));
+            obj.std_dev  = [obj.std_dev obj.std_dev(end)]; % Standard deviation of basis functions
+
+            svec = exp(-obj.alpha_s/obj.nominal_tau*obj.demo_traj.t);
+            obj.w = zeros(obj.n,obj.n_kernel);
+            for varNr = 1:obj.n
+                if abs(obj.g(varNr)-obj.y0(varNr)) < 0.001
+                    continue;
+                end
+                fGain = svec*(obj.g(varNr)-obj.y0(varNr));
+                f_target = obj.nominal_tau^2*obj.demo_traj.acc(varNr,:) - obj.K*(obj.g(varNr)-obj.demo_traj.pos(varNr,:)) + obj.D*obj.nominal_tau*obj.demo_traj.vel(varNr,:);
+                for i = 1:obj.n_kernel
+                    Gamma_i = diag(psi(svec,obj.mu(i),obj.std_dev(i)));
+                    if fGain*Gamma_i*fGain' < 1e-8
+                        obj.w(varNr,i) = 0;
+                    else
+                        obj.w(varNr,i) = fGain*Gamma_i*f_target'/(fGain*Gamma_i*fGain');
+                    end
+                end
+            end
+       end
+        
+    end
+end
+
diff --git a/dmp/matlab/NoTemporalCoupling.m b/dmp/matlab/NoTemporalCoupling.m
new file mode 100644
index 0000000000000000000000000000000000000000..bec7d3781a42d3f5d516cd0834a7c5135ba6c64e
--- /dev/null
+++ b/dmp/matlab/NoTemporalCoupling.m
@@ -0,0 +1,19 @@
+classdef NoTemporalCoupling
+    properties
+       v_max
+       a_max
+    end
+    
+    methods
+        
+        function obj = NoTemporalCoupling(params)
+            obj.v_max = params.v_max;
+            obj.a_max = params.a_max;
+        end
+        
+        function tau_dot_val = tau_dot(obj,dmp,dt)
+            tau_dot_val = 0;
+        end
+    end
+end
+
diff --git a/dmp/matlab/TemporalCoupling.m b/dmp/matlab/TemporalCoupling.m
new file mode 100644
index 0000000000000000000000000000000000000000..68caf4490d56dcf9971b60130d4e318611790013
--- /dev/null
+++ b/dmp/matlab/TemporalCoupling.m
@@ -0,0 +1,109 @@
+classdef TemporalCoupling
+    properties
+        % Settings
+        v_max
+        a_max
+        nominal_tau
+        gamma_nominal
+        gamma_a
+        eps
+    end
+    
+    methods
+        function obj = TemporalCoupling(params)
+            obj.nominal_tau = params.nominal_tau;
+            obj.v_max = params.v_max;
+            obj.a_max = params.a_max;
+            obj.gamma_nominal = params.gamma_nominal;
+            obj.gamma_a = params.gamma_a;
+            obj.eps = params.eps;
+        end
+      
+        function tau_dot_val = tau_dot(obj,dmp,dt)
+            % DMP prediction step
+            dmp_next = dmp.step(0,dt);
+            
+            % Formulate matrices
+            [A,B,C,D] = obj.tc_mtrcs(dmp);
+            [A_next,~,C_next,~] = obj.tc_mtrcs(dmp_next);
+
+            % Compute bounds
+            tau_dot_min_a = obj.tau_dot_min_a(A,B,C,dmp.tau);
+            tau_dot_max_a = obj.tau_dot_max_a(A,B,C,dmp.tau);
+            tau_dot_min_v = obj.tau_dot_min_v(A_next,D,dmp.tau,dt);
+            tau_dot_min_f = obj.tau_dot_min_f(A_next,B,C_next,dmp.tau,dt);
+            tau_dot_min_nominal = obj.tau_dot_min_nominal(dmp.tau,dt);
+            
+            % Base update law
+            tau_dot_val = obj.gamma_nominal*(obj.nominal_tau-dmp.tau) + dmp.tau*obj.sigma(dmp);
+            
+            % Saturate
+            tau_dot_min = max([tau_dot_min_a,tau_dot_min_v,tau_dot_min_f,tau_dot_min_nominal]);
+            if tau_dot_val > tau_dot_max_a
+                tau_dot_val = tau_dot_max_a;
+            end
+            if tau_dot_val < tau_dot_min
+                tau_dot_val = tau_dot_min;
+            end
+        end
+        
+        function [A,B,C,D] = tc_mtrcs(obj,dmp)
+            A = [-dmp.z(); 
+                dmp.z()];
+            B = [-obj.a_max;
+                 -obj.a_max];
+            C = [dmp.h();
+                 -dmp.h()];
+            D = [-obj.v_max;
+                 -obj.v_max];
+        end
+        
+        function minVal = tau_dot_min_a(obj,A,B,C,tau)
+            i = A < 0;
+            minVal = max(-(B(i)*tau^2+C(i))./A(i));
+        end
+        
+        function maxVal = tau_dot_max_a(obj,A,B,C,tau)
+            i = A > 0;
+            maxVal = min(-(B(i)*tau^2+C(i))./A(i));
+        end
+        
+        function minVal = tau_dot_min_f(obj,A,B,C,tau,dt)
+            Ais = A(A<0);
+            Ajs = A(A>0);
+            Bis = B(A<0);
+            Bjs = B(A>0);
+            Cis = C(A<0);
+            Cjs = C(A>0);
+            tauNextMin = -inf;
+            for i=1:length(Ais)
+                for j = 1:length(Ajs)
+                    num = Cis(i)*abs(Ajs(j))+Cjs(j)*abs(Ais(i));
+                    den = abs(Bis(i)*Ajs(j))+abs(Bjs(j)*Ais(i));
+                    if num > 0
+                        if sqrt(num/den) > tauNextMin
+                            tauNextMin = sqrt(num/den);
+                        end
+                    end
+                end
+            end
+            minVal = (tauNextMin-tau)/dt;
+        end
+        
+        function minVal = tau_dot_min_v(obj,A,D,tau,dt)
+            tauNextMax = max(-A./D);
+            minVal = (tauNextMax-tau)/dt;
+        end
+        
+        function minVal = tau_dot_min_nominal(obj,tau,dt)
+            minVal = (obj.nominal_tau-tau)/dt;
+        end
+                        
+        function sigmaVal = sigma(obj,dmp)
+            a_normalized = dmp.h()./(dmp.tau^2*obj.a_max);          
+            sigmaVal = obj.gamma_a*sum(a_normalized.^2./max(1-a_normalized.^2,obj.gamma_a*obj.eps));
+        end
+
+    end
+end
+
diff --git a/dmp/matlab/TemporalCouplingNoPotentials.m b/dmp/matlab/TemporalCouplingNoPotentials.m
new file mode 100644
index 0000000000000000000000000000000000000000..de4002e41b9af40e0a5ae456f72192501ec2ed5b
--- /dev/null
+++ b/dmp/matlab/TemporalCouplingNoPotentials.m
@@ -0,0 +1,100 @@
+classdef TemporalCouplingNoPotentials
+    properties
+        % Settings
+        v_max
+        a_max
+        nominal_tau
+        gamma_nominal
+    end
+    
+    methods
+        function obj = TemporalCouplingNoPotentials(params)
+            obj.nominal_tau = params.nominal_tau;
+            obj.v_max = params.v_max;
+            obj.a_max = params.a_max;
+            obj.gamma_nominal = params.gamma_nominal;
+        end
+      
+        function tau_dot_val = tau_dot(obj,dmp,dt)
+            % DMP prediction step
+            dmp_next = dmp.step(0,dt);
+            
+            % Formulate matrices
+            [A,B,C,D] = obj.tc_mtrcs(dmp);
+            [A_next,~,C_next,~] = obj.tc_mtrcs(dmp_next);
+
+            % Compute bounds
+            tau_dot_min_a = obj.tau_dot_min_a(A,B,C,dmp.tau);
+            tau_dot_max_a = obj.tau_dot_max_a(A,B,C,dmp.tau);
+            tau_dot_min_v = obj.tau_dot_min_v(A_next,D,dmp.tau,dt);
+            tau_dot_min_f = obj.tau_dot_min_f(A_next,B,C_next,dmp.tau,dt);
+            tau_dot_min_nominal = obj.tau_dot_min_nominal(dmp.tau,dt);
+            
+            % Base update law
+            tau_dot_val = obj.gamma_nominal*(obj.nominal_tau-dmp.tau);
+            
+            % Saturate
+            tau_dot_min = max([tau_dot_min_a,tau_dot_min_v,tau_dot_min_f,tau_dot_min_nominal]);
+            if tau_dot_val > tau_dot_max_a
+                tau_dot_val = tau_dot_max_a;
+            end
+            if tau_dot_val < tau_dot_min
+                tau_dot_val = tau_dot_min;
+            end
+        end
+        
+        function [A,B,C,D] = tc_mtrcs(obj,dmp)
+            A = [-dmp.z(); 
+                dmp.z()];
+            B = [-obj.a_max;
+                 -obj.a_max];
+            C = [dmp.h();
+                 -dmp.h()];
+            D = [-obj.v_max;
+                 -obj.v_max];
+        end
+        
+        function minVal = tau_dot_min_a(obj,A,B,C,tau)
+            i = A < 0;
+            minVal = max(-(B(i)*tau^2+C(i))./A(i));
+        end
+        
+        function maxVal = tau_dot_max_a(obj,A,B,C,tau)
+            i = A > 0;
+            maxVal = min(-(B(i)*tau^2+C(i))./A(i));
+        end
+        
+        function minVal = tau_dot_min_f(obj,A,B,C,tau,dt)
+            Ais = A(A<0);
+            Ajs = A(A>0);
+            Bis = B(A<0);
+            Bjs = B(A>0);
+            Cis = C(A<0);
+            Cjs = C(A>0);
+            tauNextMin = -inf;
+            for i=1:length(Ais)
+                for j = 1:length(Ajs)
+                    num = Cis(i)*abs(Ajs(j))+Cjs(j)*abs(Ais(i));
+                    den = abs(Bis(i)*Ajs(j))+abs(Bjs(j)*Ais(i));
+                    if num > 0
+                        if sqrt(num/den) > tauNextMin
+                            tauNextMin = sqrt(num/den);
+                        end
+                    end
+                end
+            end
+            minVal = (tauNextMin-tau)/dt;
+        end
+        
+        function minVal = tau_dot_min_v(obj,A,D,tau,dt)
+            tauNextMax = max(-A./D);
+            minVal = (tauNextMax-tau)/dt;
+        end
+        
+        function minVal = tau_dot_min_nominal(obj,tau,dt)
+            minVal = (obj.nominal_tau-tau)/dt;
+        end
+
+    end
+end
+
diff --git a/dmp/matlab/main.m b/dmp/matlab/main.m
new file mode 100644
index 0000000000000000000000000000000000000000..56e64005f7aca3133ae5da4ab1ab475155a1512f
--- /dev/null
+++ b/dmp/matlab/main.m
@@ -0,0 +1,55 @@
+clearvars
+clc
+close all 
+
+% Create demonstration trajectory
+load('trajectories/g')
+% load('trajectories/omega')
+% load('trajectories/z')
+% load('trajectories/s')
+% load('trajectories/psi')
+
+% Nominal trajectory functions
+dmp_params.D = 20;
+dmp_params.K = dmp_params.D^2/4;
+dmp_params.n_kernel = 100;
+dmp_params.alpha_s = 1;
+dmp = DMP(dmp_params,demo_traj);
+
+% Simulation setup
+sim_params.dt = 1/1000;
+sim_params.T_max = 100;
+sim_params.kv = 10;
+sim_params.kp = sim_params.kv^2/4;
+
+nominalTraj = dmp.rollout(sim_params.dt);
+sim_params.a_max = 0.5*[max(abs(nominalTraj.acc(1,:))); max(abs(nominalTraj.acc(2,:)))];
+sim_params.v_max = inf*[1 1]';
+sim_params.s_v_max_online = 0.65;
+sim_params.v_max_online = [inf;0.15];
+% sim_params.v_max_online = inf*[1 1]';
+
+% Scaling parameters
+tc_params.nominal_tau = dmp.nominal_tau;
+tc_params.eps = 1e-3;
+tc_params.gamma_nominal = 1;
+tc_params.gamma_a = 0.5;
+tc_params.a_max = sim_params.a_max; 
+tc_params.v_max = sim_params.v_max;
+
+% Create temporal coupling objects
+tc = {};
+tc{1} = TemporalCoupling(tc_params);
+tc{2} = NoTemporalCoupling(tc_params);
+tc{3} = TemporalCouplingNoPotentials(tc_params);
+
+% Simulate
+nSim = length(tc);
+res = cell(length(tc),1);
+for d = 1:nSim
+    disp(['Running simulation ' num2str(d) '/' num2str(length(tc)) '...']);
+    res{d} = run_simulation(dmp,tc{d},sim_params);   
+end
+
+% Plot result
+plot_result
diff --git a/dmp/matlab/plot_result.m b/dmp/matlab/plot_result.m
new file mode 100644
index 0000000000000000000000000000000000000000..50571b3a4c01af9ad8eaf0b0360eddfb3ba15d90
--- /dev/null
+++ b/dmp/matlab/plot_result.m
@@ -0,0 +1,110 @@
+close all
+
+
+figure('Name','Velocity')
+
+subplot(2,1,1)
+plot(res{1}.s,res{1}.ref_vel(1,:),'b-','LineWidth',1.5), hold on
+plot(res{2}.s,res{2}.ref_vel(1,:),'k--','LineWidth',1.5)
+plot(res{3}.s,res{3}.ref_vel(1,:),'m-.','LineWidth',1.5)
+plot([0 sim_params.s_v_max_online],[sim_params.v_max_online(1) sim_params.v_max_online(1)],'r:','LineWidth',1)
+plot([0 sim_params.s_v_max_online],-[sim_params.v_max_online(1) sim_params.v_max_online(1)],'r:','LineWidth',1)
+yticks([])
+xticks([round(min([res{1}.s res{2}.s res{3}.s]),2) sim_params.s_v_max_online 0.9 1])
+xlim([min([res{1}.s res{2}.s res{3}.s]) 1])
+xlabel('$s$', 'Interpreter','latex','Fontsize',30)
+ylim([min([res{2}.ref_vel(1,:) res{2}.ref_vel(2,:)]) max([res{2}.ref_vel(1,:) res{2}.ref_vel(2,:)])])
+ylabel('$\dot{y}_1$', 'Interpreter','latex','Fontsize',30)
+set(gca,'XDir','reverse')
+set(gca,'FontSize',16)
+
+subplot(2,1,2)
+plot(res{1}.s,res{1}.ref_vel(2,:),'b-','LineWidth',1.5), hold on
+plot(res{2}.s,res{2}.ref_vel(2,:),'k--','LineWidth',1.5)
+plot(res{3}.s,res{3}.ref_vel(2,:),'m-.','LineWidth',1.5)
+plot([0 sim_params.s_v_max_online],[sim_params.v_max_online(2) sim_params.v_max_online(2)],'r:','LineWidth',1)
+plot([0 sim_params.s_v_max_online],-[sim_params.v_max_online(2) sim_params.v_max_online(2)],'r:','LineWidth',1)
+yticks([-sim_params.v_max_online(2) 0 sim_params.v_max_online(2)])
+set(gca, 'YTickLabel', {'-v_{max}','0','v_{max}'},'FontSize',16);
+xticks([round(min([res{1}.s res{2}.s res{3}.s]),2) sim_params.s_v_max_online 0.9 1])
+xlim([min([res{1}.s res{2}.s res{3}.s]) 1])
+xlabel('$s$', 'Interpreter','latex','Fontsize',30)
+ylim([min([res{2}.ref_vel(1,:) res{2}.ref_vel(2,:)]) max([res{2}.ref_vel(1,:) res{2}.ref_vel(2,:)])])
+ylabel('$\dot{y}_2$', 'Interpreter','latex','Fontsize',30)
+set(gca,'XDir','reverse')
+
+figure('Name','Acceleration')
+subplot(2,1,1)
+plot(res{1}.s,res{1}.ref_acc(1,:),'b-','LineWidth',1.5), hold on
+plot(res{2}.s,res{2}.ref_acc(1,:),'k--','LineWidth',1.5)
+plot(res{3}.s,res{3}.ref_acc(1,:),'m-.','LineWidth',1.5)
+plot([res{3}.s(1) res{3}.s(end)],[sim_params.a_max(1) sim_params.a_max(1)],'r:','LineWidth',1)
+plot([res{3}.s(1) res{3}.s(end)],-[sim_params.a_max(1) sim_params.a_max(1)],'r:','LineWidth',1)
+plot([res{1}.s(1) res{1}.s(end)],[sim_params.a_max(1) sim_params.a_max(1)],'r:','LineWidth',1)
+plot([res{1}.s(1) res{1}.s(end)],-[sim_params.a_max(1) sim_params.a_max(1)],'r:','LineWidth',1)
+xticks([round(min([res{1}.s res{2}.s res{3}.s]),2) sim_params.s_v_max_online 0.9 1])
+yticks([-sim_params.a_max(1) 0 sim_params.a_max(1)])
+set(gca, 'YTickLabel', {'-a_{max}','0','a_{max}'},'FontSize',16);
+xlim([min([res{1}.s res{2}.s res{3}.s]) 1])
+xlabel('$s$', 'Interpreter','latex','Fontsize',30)
+ylim([min([res{2}.ref_acc(1,:) res{2}.ref_acc(2,:)]) max([res{2}.ref_acc(1,:) res{2}.ref_acc(2,:)])])
+ylabel('$\ddot{y}_1$', 'Interpreter','latex','Fontsize',30)
+set(gca,'XDir','reverse')
+
+subplot(2,1,2)
+plot(res{1}.s,res{1}.ref_acc(2,:),'b-','LineWidth',1.5), hold on
+plot(res{2}.s,res{2}.ref_acc(2,:),'k--','LineWidth',1.5)
+plot(res{3}.s,res{3}.ref_acc(2,:),'m-.','LineWidth',1.5)
+plot([res{3}.s(1) res{3}.s(end)],[sim_params.a_max(2) sim_params.a_max(2)],'r:','LineWidth',1)
+plot([res{3}.s(1) res{3}.s(end)],-[sim_params.a_max(2) sim_params.a_max(2)],'r:','LineWidth',1)
+plot([res{1}.s(1) res{1}.s(end)],[sim_params.a_max(2) sim_params.a_max(2)],'r:','LineWidth',1)
+plot([res{1}.s(1) res{1}.s(end)],-[sim_params.a_max(2) sim_params.a_max(2)],'r:','LineWidth',1)
+xticks([round(min([res{1}.s res{2}.s res{3}.s]),2) sim_params.s_v_max_online 0.9 1])
+yticks([-sim_params.a_max(2) 0 sim_params.a_max(2)])
+set(gca, 'YTickLabel', {'-a_{max}','0','a_{max}'},'FontSize',16);
+xlim([min([res{1}.s res{2}.s res{3}.s]) 1])
+xlabel('$s$', 'Interpreter','latex','Fontsize',30)
+ylim([min([res{2}.ref_acc(1,:) res{2}.ref_acc(2,:)]) max([res{2}.ref_acc(1,:) res{2}.ref_acc(2,:)])])
+ylabel('$\ddot{y}_2$', 'Interpreter','latex','Fontsize',30)
+set(gca,'XDir','reverse')
+
+% Path
+figure('Name','Path')
+clf
+tmp = 200;
+plot(res{1}.ref_pos(1,1:tmp:end),res{1}.ref_pos(2,1:tmp:end),'g*','LineWidth',8), hold on
+plot(res{1}.sys_pos(1,:),res{1}.sys_pos(2,:),'b-','LineWidth',2.5)
+plot(res{2}.sys_pos(1,:),res{2}.sys_pos(2,:),'k--','LineWidth',2.5)
+plot(res{3}.sys_pos(1,:),res{3}.sys_pos(2,:),'m-.','LineWidth',2.5)
+xlabel('$\xi_{1}$', 'Interpreter','latex','Fontsize',30)
+ylabel('$\xi_{2}$', 'Interpreter','latex','Fontsize',30)
+xticks([])
+yticks([])
+
+% Tau
+figure('Name','Tau')
+plot(res{1}.s,res{1}.tau,'b','LineWidth',2.5), hold on
+plot(res{2}.s,res{2}.tau,'k--','LineWidth',2.5)
+plot(res{3}.s,res{3}.tau,'m-.','LineWidth',2.5)
+xticks([round(min([res{1}.s res{2}.s res{3}.s]),2) sim_params.s_v_max_online 0.9 1])
+yticks([])
+set(gca,'FontSize',16)
+xlim([min([res{1}.s res{2}.s res{3}.s]) 1])
+ylim([0.9*dmp.nominal_tau 1.05*max(res{1}.tau)])
+xlabel('$s$', 'Interpreter','latex','Fontsize',30)
+ylabel('$\tau$', 'Interpreter','latex','Fontsize',30)
+set(gca,'XDir','reverse')
+
+
+% s
+figure('Name','s')
+plot(res{1}.t,res{1}.s,'b','LineWidth',2.5), hold on
+plot(res{2}.t,res{2}.s,'k--','LineWidth',2.5)
+plot(res{3}.t,res{3}.s,'m-.','LineWidth',2.5)
+yticks([round(min([res{1}.s res{2}.s res{3}.s]),2) sim_params.s_v_max_online 0.9 1])
+set(gca,'FontSize',20)
+xlim([0 1.05*max([res{1}.t(end) res{2}.t(end) res{3}.t(end)])])
+ylim([0.9*res{1}.s(end) 1.05])
+xlabel('$t$', 'Interpreter','latex','Fontsize',40)
+ylabel('$s$', 'Interpreter','latex','Fontsize',40)
+
diff --git a/dmp/matlab/run_simulation.m b/dmp/matlab/run_simulation.m
new file mode 100644
index 0000000000000000000000000000000000000000..1ce873af8f74df9e810f47bae4d78018667bc008
--- /dev/null
+++ b/dmp/matlab/run_simulation.m
@@ -0,0 +1,65 @@
+function res = run_simulation(dmp,tmp_couple,params)
+
+% Parameters
+dt = params.dt;
+T_max = params.T_max;
+kp = params.kp;
+kv = params.kv;
+a_max = params.a_max;
+v_max = params.v_max;
+s_v_max_online = params.s_v_max_online;
+v_max_online = params.v_max_online;
+
+% Initialize
+dmp = dmp.init();
+t = 0;
+k = 1;
+sys.pos = dmp.ref_pos();
+sys.vel = 0*sys.pos;
+sys.acc = 0*sys.pos;
+
+while t < T_max
+    % Store values
+    res.t(k) = t;
+    res.s(k) = dmp.s();
+    res.ref_pos(:,k) = dmp.ref_pos();
+    res.ref_vel(:,k) = dmp.ref_vel();
+    res.ref_acc(:,k) = dmp.ref_acc();
+    res.sys_pos(:,k) = sys.pos;
+    res.sys_vel(:,k) = sys.vel;
+    res.sys_acc(:,k) = sys.acc;
+    res.tau(k) = dmp.tau;
+
+    % Final position convergence condition
+    if norm(dmp.ref_pos()-dmp.g) < 1e-2
+        break;
+    end
+
+    % Perform one time step
+    k = k + 1;
+    t = t + dt;
+    
+    % Add velocity limit online
+    if dmp.s() < s_v_max_online
+        v_max = v_max_online;
+        tmp_couple.v_max= v_max_online;
+    end
+
+    % Step trajectory generator
+    tau_dot = tmp_couple.tau_dot(dmp,dt);
+    dmp = dmp.step(tau_dot,dt); 
+
+    % Controller
+    sys_acc_ctrl = dmp.ref_acc() + kv*(dmp.ref_vel()-sys.vel) + kp*(dmp.ref_pos()-sys.pos);
+    % Saturate acceleration
+    sys_acc_ctrl = min(max(sys_acc_ctrl,-a_max),a_max);
+    % Velocity integration
+    vel_prev = sys.vel;
+    sys.vel = sys.vel + sys_acc_ctrl*dt;
+    % Saturate velocity
+    sys.vel = min(max(sys.vel,-v_max),v_max);
+    sys.acc = (sys.vel-vel_prev)/dt;
+    % Position integration
+    sys.pos = sys.pos + sys.vel*dt;
+
+end
\ No newline at end of file
diff --git a/dmp/matlab/trajectories/g.mat b/dmp/matlab/trajectories/g.mat
new file mode 100644
index 0000000000000000000000000000000000000000..e03f71a1b5d2900da911de5751cec75588386db4
Binary files /dev/null and b/dmp/matlab/trajectories/g.mat differ
diff --git a/dmp/matlab/trajectories/omega.mat b/dmp/matlab/trajectories/omega.mat
new file mode 100644
index 0000000000000000000000000000000000000000..8cd3b2b1561142fbc2ee4b9bd768e1773333c6bd
Binary files /dev/null and b/dmp/matlab/trajectories/omega.mat differ
diff --git a/dmp/matlab/trajectories/psi.mat b/dmp/matlab/trajectories/psi.mat
new file mode 100644
index 0000000000000000000000000000000000000000..c1b6372952d1262d5ad2bc6ac09f37ceafd74776
Binary files /dev/null and b/dmp/matlab/trajectories/psi.mat differ
diff --git a/dmp/matlab/trajectories/s.mat b/dmp/matlab/trajectories/s.mat
new file mode 100644
index 0000000000000000000000000000000000000000..6102e05dd231ec6bbc5abd5191e89a5242db05b5
Binary files /dev/null and b/dmp/matlab/trajectories/s.mat differ
diff --git a/dmp/matlab/trajectories/z.mat b/dmp/matlab/trajectories/z.mat
new file mode 100644
index 0000000000000000000000000000000000000000..09243cdc8e4d974bfd3bc1abade837cd672076b5
Binary files /dev/null and b/dmp/matlab/trajectories/z.mat differ
diff --git a/dmp/motion_planning/__init__.py b/dmp/motion_planning/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/dmp/motion_planning/dmp/__init__.py b/dmp/motion_planning/dmp/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..40b5f425576ed7037e884202289aa719420a699b
--- /dev/null
+++ b/dmp/motion_planning/dmp/__init__.py
@@ -0,0 +1,2 @@
+from dmp import DMP
+from temporal_coupling import TCVelAccConstrained, NoTC
\ No newline at end of file
diff --git a/dmp/motion_planning/dmp/__init__.pyc b/dmp/motion_planning/dmp/__init__.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e776f2856a3618cc12f701c89327b4429c25b01a
Binary files /dev/null and b/dmp/motion_planning/dmp/__init__.pyc differ
diff --git a/dmp/motion_planning/dmp/dmp.py b/dmp/motion_planning/dmp/dmp.py
new file mode 100644
index 0000000000000000000000000000000000000000..958441d0a9fc01045e880ce39a92679d66a032bc
--- /dev/null
+++ b/dmp/motion_planning/dmp/dmp.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python
+
+import numpy as np
+
+
+class DMP:
+    def __init__(self, k=100, d=20, a_s=1, n_bfs=100):
+        # parameters
+        self.k = k
+        self.d = d
+        self.a_s = a_s
+        self.n_bfs = n_bfs
+
+        # for obstacle avoidance
+        self.g_obs = 1000.
+        self.b_obs = 20. / np.pi
+        self.a_obs = 0.2
+
+        # trajectory parameters
+        self.n = 0
+        self.y0 = None
+        self.tau0 = None
+        self.g = None
+        self.tau = None
+
+        # initialize basis functions for LWR
+        self.w = None
+        self.centers = None
+        self.widths = None
+
+        # state
+        self.x = None
+        self.theta = None
+        self.pos = None
+        self.vel = None
+        self.acc = None
+
+        # desired path
+        self.path = None
+
+    def reset(self):
+        self.x = np.vstack((np.zeros((self.n, 1)), self.y0, 1.))
+        self.tau = self.tau0
+        self.theta = 0
+        self.pos = self.y0
+        self.vel = 0 * self.y0
+        self.acc = 0 * self.y0
+
+    def z(self, x=None):
+        if x is None:
+            x = self.x
+        return x[0:self.n]
+
+    def y(self, x=None):
+        if x is None:
+            x = self.x
+        return x[self.n:2 * self.n]
+
+    def s(self, x=None):
+        if x is None:
+            x = self.x
+        return x[2 * self.n]
+
+    def set_goal(self, g):
+        self.g = g
+
+    def set_tau(self, tau):
+        self.tau = tau
+
+    def psi(self, s, i=None):
+        if i is not None and len(s) == 1:
+            return np.exp(-1 / (2 * self.widths[i] ** 2) * (s - self.centers[i]) ** 2)
+        if i is None:
+            return np.exp(-1 / (2 * self.widths ** 2) * (s - self.centers) ** 2)
+
+    def h(self, x=None):
+        if x is None:
+            x = self.x
+        psi = self.psi(self.s(x)).reshape((self.n_bfs, 1))
+        v = (self.w.dot(psi)) / np.maximum(np.sum(psi), 1e-8) * (self.g - self.y0) * self.s(x)
+        h = self.k * (self.g - self.y(x)) - self.d * self.z(x) + v
+        return h
+
+    def f(self, x=None):
+        if x is None:
+            x = self.x
+        return np.vstack((self.h(x), self.z(x), -self.a_s * self.s(x)))
+
+    def obstacle_avoidance(self):
+        p = np.zeros(self.pos.shape)
+
+        for obstacle in self.obstacles:
+            # calculate vector to object relative to body
+            o = np.squeeze(obstacle)
+            x = np.squeeze(self.pos)
+            v = np.squeeze(self.vel)
+            # if we're moving
+            if np.linalg.norm(self.vel) > 1e-8 and np.linalg.norm(o - x) < self.a_obs:
+                # print("Dist: " + str(np.linalg.norm(o - x)) + "at position: " + str(x))
+                phi = np.arccos( np.dot(o - x, v) / (np.linalg.norm(o - x) * np.linalg.norm(v)) )
+                dphi = self.g_obs * phi * np.exp(-self.b_obs * abs(phi))
+
+                r = np.cross(o - x, v)
+                r = r / np.linalg.norm(r)
+                R = np.array([[0,-r[2],r[1]], [r[2],0,r[0]], [-r[1],r[0],0]]) + np.outer(r,r)
+                pval = np.nan_to_num(np.dot(R, v) * dphi)
+
+                # check to see if the distance to the obstacle is further than
+                # the distance to the target, if it is, ignore the obstacle
+                if np.linalg.norm(o - x) > np.linalg.norm(self.g - self.pos):
+                    pval = p * 0.
+
+                p += pval.reshape(self.pos.shape)
+        return p
+
+    def step(self, dt):
+        # Update state
+        self.x = self.x + self.f() / self.tau * dt
+        self.theta = self.theta + 1 / self.tau * dt
+
+        # Extract trajectory state
+        vel_prev = self.vel
+        self.pos = self.y()
+        self.vel = self.z() / self.tau
+        self.acc = (self.vel - vel_prev) / dt
+
+    def fit(self, y_demo, t_demo):
+        # Set target trajectory parameters
+        t_demo = t_demo.reshape(1, len(t_demo))
+        self.n = y_demo.shape[0]
+        self.path = y_demo
+        self.y0 = y_demo[:, 0].reshape((self.n, 1))
+        self.g = y_demo[:, -1].reshape((self.n, 1))
+        self.tau0 = t_demo[0, -1]
+
+        # Set basis functions
+        t_centers = np.linspace(0, self.tau0, self.n_bfs, endpoint=True)
+        self.centers = np.exp(-self.a_s / self.tau0 * t_centers)
+        widths = np.abs((np.diff(self.centers)))
+        self.widths = np.concatenate((widths, [widths[-1]]))
+
+        # Calculate derivatives
+        yd_demo = (y_demo[:, 1:] - y_demo[:, :-1]) / (t_demo[0, 1:] - t_demo[0, :-1])
+        yd_demo = np.concatenate((yd_demo, np.zeros((self.n, 1))), axis=1)
+        ydd_demo = (yd_demo[:, 1:] - yd_demo[:, :-1]) / (t_demo[0, 1:] - t_demo[0, :-1])
+        ydd_demo = np.concatenate((ydd_demo, np.zeros((self.n, 1))), axis=1)
+
+        # Compute weights
+        s_seq = np.exp(-self.a_s / self.tau0 * t_demo)
+        self.w = np.zeros((self.n, self.n_bfs))
+        for i in range(self.n):
+            if abs(self.g[i] - self.y0[i]) < 1e-5:
+                continue
+            f_gain = s_seq * (self.g[i] - self.y0[i])
+            f_target = self.tau0 ** 2 * ydd_demo[i, :] - self.k * (
+                        self.g[i] - y_demo[i, :]) + self.d * self.tau0 * yd_demo[i, :]
+            for j in range(self.n_bfs):
+                psi_j = self.psi(s_seq, j)
+                num = f_gain.dot((psi_j * f_target).T)
+                den = f_gain.dot((psi_j * f_gain).T)
+                if abs(den) < 1e-6:
+                    continue
+                self.w[i, j] = num / den
+
+        # Reset state
+        self.reset()
diff --git a/dmp/motion_planning/dmp/dmp.pyc b/dmp/motion_planning/dmp/dmp.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1bedeaf35b653fa33fa47689814842914482a17d
Binary files /dev/null and b/dmp/motion_planning/dmp/dmp.pyc differ
diff --git a/dmp/motion_planning/dmp/temporal_coupling.py b/dmp/motion_planning/dmp/temporal_coupling.py
new file mode 100644
index 0000000000000000000000000000000000000000..5d9107a02500449d00e5644d64f6291c46a9290b
--- /dev/null
+++ b/dmp/motion_planning/dmp/temporal_coupling.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+
+import numpy as np
+
+
+class NoTC:
+    def update(self, dmp, dt):
+        return 0
+
+
+class TCVelAccConstrained:
+
+    def __init__(self, gamma_nominal, gamma_a, v_max, a_max, eps=0.001):
+        self.gamma_nominal = gamma_nominal
+        self.gamma_a = gamma_a
+        self.eps = eps
+        self.v_max = v_max.reshape((len(v_max), 1))
+        self.a_max = a_max.reshape((len(a_max), 1))
+
+    def generate_matrices(self, dmp, dt):
+        A = np.vstack((-dmp.z(), dmp.z()))
+        B = np.vstack((-self.a_max, -self.a_max))
+        C = np.vstack((dmp.h(), -dmp.h()))
+        D = np.vstack((-self.v_max, -self.v_max))
+        x_next = dmp.x + dmp.f(dmp.x) / dmp.tau * dt
+        A_next = np.vstack((-dmp.z(x_next), dmp.z(x_next)))
+        C_next = np.vstack((dmp.h(x_next), -dmp.h(x_next)))
+        return A, B, C, D, A_next, C_next
+
+    def update(self, dmp, dt):
+
+        A, B, C, D, A_next, C_next = self.generate_matrices(dmp, dt)
+
+        # Acceleration bounds
+        i = np.squeeze(A < 0)
+        if i.any():
+            taud_min_a = np.max(- (B[i] * dmp.tau ** 2 + C[i]) / A[i])
+        else:
+            taud_min_a = -np.inf
+        i = np.squeeze(A > 0)
+        if i.any():
+            taud_max_a = np.min(- (B[i] * dmp.tau ** 2 + C[i]) / A[i])
+        else:
+            taud_max_a = np.inf
+        # Velocity bounds
+        i = range(len(A_next))
+        tau_min_v = np.max(-A_next[i] / D[i])
+        taud_min_v = (tau_min_v - dmp.tau) / dt
+        # Feasibility bounds
+        ii = np.arange(len(A_next))[np.squeeze(A_next < 0)]
+        jj = np.arange(len(A_next))[np.squeeze(A_next > 0)]
+        tau_min_f = -np.inf
+        for i in ii:
+            for j in jj:
+                num = C_next[i] * abs(A_next[j]) + C_next[j] * abs(A_next[i])
+                if num > 0:
+                    den = abs(B[i] * A_next[j]) + abs(B[j] * A_next[i])
+                    tmp = np.sqrt(num / den)
+                    if tmp > tau_min_f:
+                        tau_min_f = tmp
+        taud_min_f = (tau_min_f - dmp.tau) / dt
+        # Nominal bound
+        taud_min_nominal = (dmp.tau0 - dmp.tau) / dt
+
+        taud_min = np.max((taud_min_a, taud_min_v, taud_min_f, taud_min_nominal))
+
+        # Base update law
+        ydd_bar = dmp.h() / (dmp.tau**2 * self.a_max)
+        if self.gamma_a > 0:
+            pot_a = self.gamma_a * np.sum(ydd_bar ** 2 / np.maximum(1 - ydd_bar ** 2, self.gamma_a * self.eps * np.ones((len(ydd_bar), 1))))
+        else:
+            pot_a = 0
+        #pot_a = self.gamma_a * np.amax(ydd_bar ** 2 / np.maximum(1 - ydd_bar ** 2, self.gamma_a * self.eps * np.ones((len(ydd_bar), 1))))
+        taud = self.gamma_nominal * (dmp.tau0 - dmp.tau) + dmp.tau * pot_a
+
+        # Saturate
+        taud = np.min((taud, taud_max_a))
+        taud = np.max((taud, taud_min))
+
+        return taud
diff --git a/dmp/motion_planning/dmp/temporal_coupling.pyc b/dmp/motion_planning/dmp/temporal_coupling.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ad105c2dfe090b880329d78c3dd0cb0fe173a9ed
Binary files /dev/null and b/dmp/motion_planning/dmp/temporal_coupling.pyc differ
diff --git a/dmp/motion_planning/online_traj_scaling/__init__.py b/dmp/motion_planning/online_traj_scaling/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..1d156231bbd0cb1a221023cdddc65337b30630c1
--- /dev/null
+++ b/dmp/motion_planning/online_traj_scaling/__init__.py
@@ -0,0 +1,2 @@
+from gmr_oa import GMRwOA
+from trajectory_generator import TrajectoryGenerator
\ No newline at end of file
diff --git a/dmp/motion_planning/online_traj_scaling/__init__.pyc b/dmp/motion_planning/online_traj_scaling/__init__.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..12e3377806349a16333dbb0e3992de92b9d20efc
Binary files /dev/null and b/dmp/motion_planning/online_traj_scaling/__init__.pyc differ
diff --git a/dmp/motion_planning/online_traj_scaling/__pycache__/gmr_oa.cpython-36.pyc b/dmp/motion_planning/online_traj_scaling/__pycache__/gmr_oa.cpython-36.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1833879cf8567e520fb4534cbd3be33e2a81c347
Binary files /dev/null and b/dmp/motion_planning/online_traj_scaling/__pycache__/gmr_oa.cpython-36.pyc differ
diff --git a/dmp/motion_planning/online_traj_scaling/example.yaml b/dmp/motion_planning/online_traj_scaling/example.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..94f5fb3ed096e87b1e50054613968d9c736e02fe
--- /dev/null
+++ b/dmp/motion_planning/online_traj_scaling/example.yaml
@@ -0,0 +1,38 @@
+update_rate: 125
+x0: [-29.1, 114.9]
+s_end: 3.5
+priors: [0.2599, 0.1352, 0.1344, 0.1377, 0.0550, 0.1664, 0.1113]
+mu: [[-112.6856, 54.1569, -88.7499, -154.9200], [74.9928, -98.9324, 122.6443, 182.4869],
+    [22.6435, 1.4977, -102.7541, 2.7533], [-22.5173, -123.9775,  299.0837,  -48.8174],
+    [-64.5564, 98.1626, -160.4187, -170.3178], [78.6112, -17.0895, -101.3953, 115.8752],
+    [-123.0283, -63.0123, 174.2271, -279.1635]]
+sigma: [[[0.6009,  0.0300, -0.0491,  1.0150],
+       [0.0300,  1.9033, -3.1190,  1.1773],
+       [-0.0491, -3.1190,  5.9745, -2.1668],
+       [1.0150,  1.1773, -2.1668,  3.1809]],
+       [[0.6290,  0.1268, -1.2774,  1.5296],
+        [0.1268,  0.9079, -2.3844,  0.3074],
+        [-1.2774, -2.3844,  8.2566, -3.0188],
+        [1.5296,  0.3074, -3.0188,  3.7767]],
+        [[0.2605, -0.0328, -0.6769, 0.3306],
+         [-0.0328, 0.0282, -0.1585, -0.1858],
+         [-0.6769, -0.1585, 7.9287, 1.6320],
+         [0.3306, -0.1858, 1.6320, 1.7752]],
+        [[1.7232, -0.7104, 0.3933, 3.7694],
+         [-0.7104, 0.7734, -1.2591, -1.5555],
+         [0.3933, -1.2591, 3.6391, 0.7968],
+         [3.7694, -1.5555, 0.7968, 8.5589]],
+        [[1.094, -0.079, -0.568, 1.331],
+           [-0.079, 2.376, -4.876, -2.423],
+           [-0.568, -4.876, 15.627, 9.517],
+           [1.331, -2.423, 9.517, 44.624]],
+        [[0.4217, -0.3304, 0.2178, 1.2149],
+         [-0.3304, 0.4037, -0.6332, -1.3119],
+         [0.2178, -0.6332, 2.2057, 2.3334],
+         [1.2149, -1.3119, 2.3334, 4.9441]],
+        [[0.5734, -0.6797, 1.3006, 1.320],
+         [-0.6797, 1.4485, -2.9368, -1.5774],
+         [1.3006, -2.9368, 6.0104, 2.9347],
+         [1.3200, -1.5774, 2.9347, 4.7359]]]
+o_c: [-100, -70]
+o_r: 30
\ No newline at end of file
diff --git a/dmp/motion_planning/online_traj_scaling/gmr_oa.py b/dmp/motion_planning/online_traj_scaling/gmr_oa.py
new file mode 100644
index 0000000000000000000000000000000000000000..cc49b5a1cb4da2f07d6c385defd0c55b688587a0
--- /dev/null
+++ b/dmp/motion_planning/online_traj_scaling/gmr_oa.py
@@ -0,0 +1,363 @@
+#!/usr/bin/env python
+
+import numpy as np
+
+
+class GMRwOA:
+    def __init__(self, params):
+        self.x0 = np.array(params['x0'])
+        self.s_end = params['s_end']
+        self.n = self.x0.size
+        self.o_c = np.array(params['o_c'])
+        self.o_r = params['o_r']
+        self.priors = np.array(params['priors'])
+        self.mu = np.array(params['mu'])
+        self.sigma = np.array(params['sigma'])
+        self.nKernels = self.priors.size
+        self.A = np.zeros((self.nKernels, self.n, self.n))
+        self.b = np.zeros((self.nKernels, self.n))
+        for w in range(self.nKernels):
+            self.A[w, :, :] = self.sigma[w, self.n:, :self.n].dot(np.linalg.inv(
+                self.sigma[w, :self.n, :self.n]))
+            self.b[w, :] = self.mu[w, self.n:] - self.A[w, :, :].dot(self.mu[w, :self.n])
+
+    def f(self, x):
+        weights = self.weights(x)
+        f = np.zeros(self.n)
+        gmr_f = sum(weights[w] * (self.A[w, :, :].dot(x) + self.b[w, :]) for w in range(self.nKernels))
+        return self.modulation_matrix(x).dot(gmr_f)
+
+    def g(self, x):
+        return x
+
+    def gx(self, x):
+        return np.eye(self.n)
+
+    def dx_gxf(self, x):
+        x1 = x[0]
+        x2 = x[1]
+        t2 = x2 + 7.0e1
+        t3 = x1 + 1.0e2
+        t4 = t2 ** 2
+        t5 = t3 ** 2
+        t6 = x2 - 9.816261394778176e1
+        t7 = x1 * 1.530596366426007e-5
+        t8 = x2 * 2.109513339111852e-4
+        t9 = t7 + t8 - 1.971943673320373e-2
+        t10 = x1 + 6.455638083061622e1
+        t11 = x1 * 4.582396934010209e-4
+        t12 = x2 * 1.530596366426007e-5
+        t13 = t11 + t12 + 2.807982275662759e-2
+        t79 = t6 * t9
+        t80 = t10 * t13
+        t14 = -t79 - t80
+        t15 = np.exp(t14)
+        t16 = x2 - 5.415693532998247e1
+        t17 = x1 * 1.312704257151209e-5
+        t82 = x2 * 2.629035561972274e-4
+        t18 = t17 - t82 + 1.571727929602906e-2
+        t19 = t16 * t18
+        t20 = x1 + 1.126855799373714e2
+        t21 = x1 * 8.327024557111857e-4
+        t83 = x2 * 1.312704257151209e-5
+        t22 = t21 - t83 + 9.454447953270757e-2
+        t84 = t20 * t22
+        t23 = t19 - t84
+        t24 = np.exp(t23)
+        t25 = x1 + 2.251733280467149e1
+        t26 = x1 * 4.670158568124115e-4
+        t27 = x2 * 4.289836618923725e-4
+        t28 = t26 + t27 + 6.370025953155209e-2
+        t29 = x2 + 1.239774676360322e2
+        t30 = x1 * 4.289836618923725e-4
+        t31 = x2 * 1.040569631086783e-3
+        t32 = t30 + t31 + 1.386667556436968e-1
+        t88 = t25 * t28
+        t89 = t29 * t32
+        t33 = -t88 - t89
+        t34 = np.exp(t33)
+        t35 = t34 * 2.408872289627689e-5
+        t36 = x1 - 7.499276410192803e1
+        t37 = x2 * 1.142541742241694e-4
+        t90 = x1 * 8.178935231312593e-4
+        t38 = t37 - t90 + 7.263953274615121e-2
+        t39 = t36 * t38
+        t40 = x2 + 9.893237408811206e1
+        t41 = x2 * 5.666798935371871e-4
+        t91 = x1 * 1.142541742241694e-4
+        t42 = t41 - t91 + 6.463122355088623e-2
+        t92 = t40 * t42
+        t43 = t39 - t92
+        t44 = np.exp(t43)
+        t45 = t44 * 2.888145048134885e-5
+        t46 = x1 - 2.264354107101735e1
+        t47 = x1 * 2.247790700044474e-3
+        t48 = x2 * 2.608028701302809e-3
+        t49 = t47 + t48 - 5.480387720544926e-2
+        t50 = x2 - 1.497658429905395
+        t51 = x1 * 2.608028701302809e-3
+        t52 = x2 * 2.072560326248954e-2
+        t53 = t51 + t52 - 9.00948794532844e-2
+        t93 = t46 * t49
+        t94 = t50 * t53
+        t54 = -t93 - t94
+        t55 = np.exp(t54)
+        t56 = t55 * 2.698593356722665e-4
+        t57 = x2 + 6.301228183938932e1
+        t58 = x1 * 9.222652594971037e-4
+        t59 = x2 * 7.779669674794524e-4
+        t60 = t58 + t59 + 1.624861712161579e-1
+        t61 = x1 + 1.230282678775932e2
+        t62 = x1 * 1.965364578835002e-3
+        t63 = x2 * 9.222652594971037e-4
+        t64 = t62 + t63 + 2.999094383441548e-1
+        t95 = t57 * t60
+        t96 = t61 * t64
+        t65 = -t95 - t96
+        t66 = np.exp(t65)
+        t67 = t66 * 2.919147494282987e-5
+        t68 = x1 - 7.861117292542697e1
+        t69 = x1 * 3.302595736312175e-3
+        t70 = x2 * 2.702662948139369e-3
+        t71 = t69 + t70 - 2.134336703875113e-1
+        t72 = x2 + 1.708953540592262e1
+        t73 = x1 * 2.702662948139369e-3
+        t74 = x2 * 3.450285534628542e-3
+        t75 = t73 + t74 - 1.534957275707511e-1
+        t97 = t68 * t71
+        t98 = t72 * t75
+        t76 = -t97 - t98
+        t77 = np.exp(t76)
+        t78 = t77 * 1.071251714048381e-4
+        t81 = t15 * 5.43860953025742e-6
+        t85 = t24 * 3.869452814178776e-5
+        t86 = t35 + t45 + t56 + t67 + t78 + t81 + t85
+        t87 = 1.0 / t86
+        t99 = x1 * 6.605191472624351e-3
+        t100 = x2 * 5.405325896278738e-3
+        t101 = t99 + t100 - 4.268673407750226e-1
+        t102 = x1 * 3.869851041803628
+        t103 = x2 * 1.010037993543203e1
+        t104 = t102 + t103
+        t105 = x1 * 4.495581400088948e-3
+        t106 = x2 * 5.216057402605618e-3
+        t107 = t105 + t106 - 1.096077544108985e-1
+        t108 = x2 * 2.285083484483388e-4
+        t117 = x1 * 1.635787046262519e-3
+        t109 = t108 - t117 + 1.452790654923024e-1
+        t110 = x1 * 1.665404911422371e-3
+        t115 = x2 * 2.625408514302419e-5
+        t111 = t110 - t115 + 1.890889590654151e-1
+        t112 = x1 * 1.983731639577469
+        t113 = x2 * 3.191903357349043
+        t114 = t112 + t113 - 1.4210854715202e-14
+        t116 = t24 * t111 * 3.869452814178776e-5
+        t118 = t77 * t101 * 1.071251714048381e-4
+        t119 = x1 * 9.164793868020419e-4
+        t120 = x2 * 3.061192732852015e-5
+        t121 = t119 + t120 + 5.615964551325517e-2
+        t122 = t15 * t121 * 5.43860953025742e-6
+        t123 = x1 * 9.34031713624823e-4
+        t124 = x2 * 8.57967323784745e-4
+        t125 = t123 + t124 + 1.274005190631042e-1
+        t126 = t34 * t125 * 2.408872289627689e-5
+        t127 = t55 * t107 * 2.698593356722665e-4
+        t128 = x1 * 3.930729157670005e-3
+        t129 = x2 * 1.844530518994207e-3
+        t130 = t128 + t129 + 5.998188766883095e-1
+        t131 = t66 * t130 * 2.919147494282987e-5
+        t136 = t44 * t109 * 2.888145048134885e-5
+        t132 = t116 + t118 + t122 + t126 + t127 + t131 - t136
+        t133 = 1.0 / t86 ** 2
+        t134 = x1 * 3.231732335122654e-5
+        t154 = x2 * 1.638686742732473
+        t135 = t134 - t154
+        t137 = x1 * 1.54461351435013
+        t138 = x2 * 2.410526413045497
+        t139 = t137 + t138
+        t140 = x1 * 7.128956258032981e-1
+        t141 = x2 * 2.282924141766298
+        t142 = t140 + t141
+        t143 = x1 * 3.04539679230562e-1
+        t144 = x2 * 2.17037228002446
+        t145 = t143 + t144 - 2.842170943040401e-14
+        t146 = x1 * 6.694733262807462e-1
+        t147 = x2 * 2.074491355757708
+        t148 = t146 + t147
+        t149 = x1 * 2.0
+        t150 = t149 + 2.0e2
+        t151 = t4 + t5
+        t152 = 1.0 / t151 ** 2
+        t183 = t3 * t150
+        t153 = t4 + t5 - t183
+        t155 = x1 * 1.145820509435398
+        t157 = x2 * 9.81512008356454e-1
+        t156 = t155 - t157
+        t158 = x1 * 5.169583816001215e-1
+        t166 = x2 * 5.977666165428746
+        t159 = t158 - t166 + 4.440892098500626e-16
+        t160 = x1 * 1.659508447689607
+        t161 = x2 * 5.924016783798807e-1
+        t162 = t160 + t161
+        t163 = x1 * 2.279092938141525
+        t165 = x2 * 1.950918964167032e-2
+        t164 = t163 - t165
+        t167 = x2 * 2.48561120484202
+        t175 = x1 * 9.336740956565702e-1
+        t168 = t167 - t175 + 2.842170943040401e-14
+        t169 = x1 * 2.43188361814004
+        t174 = x2 * 1.144763805707237e-3
+        t170 = t169 - t174
+        t171 = x2 * 3.289247523618103e-3
+        t173 = x1 * 2.186101706496526
+        t172 = t171 - t173 + 7.105427357601002e-14
+        t176 = 1.0 / t151 ** 3
+        t177 = t15 * t87 * t156 * 5.43860953025742e-6
+        t178 = t55 * t87 * t159 * 2.698593356722665e-4
+        t179 = t24 * t87 * t162 * 3.869452814178776e-5
+        t180 = t66 * t87 * t164 * 2.919147494282987e-5
+        t181 = t44 * t87 * t170 * 2.888145048134885e-5
+        t224 = t77 * t87 * t168 * 1.071251714048381e-4
+        t225 = t34 * t87 * t172 * 2.408872289627689e-5
+        t182 = t177 + t178 + t179 + t180 + t181 - t224 - t225
+        t184 = t152 * t153 * 9.0e2
+        t185 = t184 + 1.0
+        t186 = x1 * 1.844530518994207e-3
+        t187 = x2 * 1.555933934958905e-3
+        t188 = t186 + t187 + 3.249723424323159e-1
+        t189 = x1 * 5.216057402605618e-3
+        t190 = x2 * 4.145120652497908e-2
+        t191 = t189 + t190 - 1.801897589065688e-1
+        t192 = t66 * t188 * 2.919147494282987e-5
+        t193 = x1 * 5.405325896278738e-3
+        t194 = x2 * 6.900571069257084e-3
+        t195 = t193 + t194 - 3.069914551415021e-1
+        t196 = t77 * t195 * 1.071251714048381e-4
+        t197 = x1 * 2.625408514302419e-5
+        t212 = x2 * 5.258071123944548e-4
+        t198 = t197 - t212 + 3.143455859205812e-2
+        t199 = x2 * 1.133359787074374e-3
+        t214 = x1 * 2.285083484483388e-4
+        t200 = t199 - t214 + 1.292624471017725e-1
+        t201 = t44 * t200 * 2.888145048134885e-5
+        t202 = x1 * 8.57967323784745e-4
+        t203 = x2 * 2.081139262173565e-3
+        t204 = t202 + t203 + 2.773335112873937e-1
+        t205 = t34 * t204 * 2.408872289627689e-5
+        t206 = t55 * t191 * 2.698593356722665e-4
+        t207 = x1 * 3.061192732852015e-5
+        t208 = x2 * 4.219026678223704e-4
+        t209 = t207 + t208 - 3.943887346640746e-2
+        t210 = t15 * t209 * 5.43860953025742e-6
+        t213 = t24 * t198 * 3.869452814178776e-5
+        t211 = t192 + t196 + t201 + t205 + t206 + t210 - t213
+        t215 = x2 * 2.0
+        t216 = t215 + 1.4e2
+        t217 = t55 * t87 * t104 * 2.698593356722665e-4
+        t218 = t77 * t87 * t114 * 1.071251714048381e-4
+        t219 = t44 * t87 * t139 * 2.888145048134885e-5
+        t220 = t34 * t87 * t142 * 2.408872289627689e-5
+        t221 = t66 * t87 * t145 * 2.919147494282987e-5
+        t222 = t15 * t87 * t148 * 5.43860953025742e-6
+        t244 = t24 * t87 * t135 * 3.869452814178776e-5
+        t223 = t217 + t218 + t219 + t220 + t221 + t222 - t244
+        t226 = t150 * t152 * 9.0e2
+        t260 = t2 * t216
+        t227 = t4 + t5 - t260
+        t228 = t15 * t87 * 6.231670342579768e-6
+        t229 = t24 * t87 * 6.421389633066001e-5
+        t230 = t34 * t87 * 5.266039823087284e-5
+        t231 = t44 * t87 * 7.023632629371505e-5
+        t232 = t55 * t87 * 1.395060454288188e-4
+        t233 = t66 * t87 * 6.653008439613883e-5
+        t234 = t77 * t87 * 1.000199975334673e-4
+        t235 = t15 * t132 * t133 * t156 * 5.43860953025742e-6
+        t236 = t55 * t132 * t133 * t159 * 2.698593356722665e-4
+        t237 = t24 * t132 * t133 * t162 * 3.869452814178776e-5
+        t238 = t66 * t132 * t133 * t164 * 2.919147494282987e-5
+        t239 = t44 * t87 * t109 * t170 * 2.888145048134885e-5
+        t240 = t34 * t87 * t125 * t172 * 2.408872289627689e-5
+        t241 = t44 * t132 * t133 * t170 * 2.888145048134885e-5
+        t242 = t77 * t87 * t101 * t168 * 1.071251714048381e-4
+        t243 = t228 + t229 + t230 + t231 + t232 + t233 + t234 + t235 + t236 + t237 + t238 + t239 + t240 + t241 + t242 - t15 * t87 * t121 * t156 * 5.43860953025742e-6 - t24 * t87 * t111 * t162 * 3.869452814178776e-5 - t55 * t87 * t107 * t159 * 2.698593356722665e-4 - t66 * t87 * t130 * t164 * 2.919147494282987e-5 - t34 * t132 * t133 * t172 * 2.408872289627689e-5 - t77 * t132 * t133 * t168 * 1.071251714048381e-4
+        t245 = t15 * t87 * 3.641004012563601e-6
+        t246 = t34 * t87 * 1.717274518394355e-5
+        t247 = t44 * t87 * 4.46106787275255e-5
+        t248 = t55 * t87 * 1.044315431291755e-3
+        t249 = t66 * t87 * 8.889962415356397e-6
+        t250 = t77 * t87 * 2.125075919109369e-4
+        t251 = t55 * t104 * t132 * t133 * 2.698593356722665e-4
+        t252 = t44 * t87 * t109 * t139 * 2.888145048134885e-5
+        t253 = t24 * t87 * t111 * t135 * 3.869452814178776e-5
+        t254 = t77 * t114 * t132 * t133 * 1.071251714048381e-4
+        t255 = t44 * t132 * t133 * t139 * 2.888145048134885e-5
+        t256 = t34 * t132 * t133 * t142 * 2.408872289627689e-5
+        t257 = t66 * t132 * t133 * t145 * 2.919147494282987e-5
+        t258 = t15 * t132 * t133 * t148 * 5.43860953025742e-6
+        t259 = t245 + t246 + t247 + t248 + t249 + t250 + t251 + t252 + t253 + t254 + t255 + t256 + t257 + t258 - t24 * t87 * 1.25050357788129e-9 - t55 * t87 * t104 * t107 * 2.698593356722665e-4 - t15 * t87 * t121 * t148 * 5.43860953025742e-6 - t77 * t87 * t101 * t114 * 1.071251714048381e-4 - t34 * t87 * t125 * t142 * 2.408872289627689e-5 - t24 * t132 * t133 * t135 * 3.869452814178776e-5 - t66 * t87 * t130 * t145 * 2.919147494282987e-5
+        t261 = t152 * t227 * 9.0e2
+        t262 = t261 + 1.0
+        t263 = t15 * t87 * 5.338060562709511e-6
+        t264 = t34 * t87 * 7.923377213370146e-8
+        t265 = t44 * t87 * 3.306243916737403e-8
+        t266 = t55 * t87 * 1.613129020273186e-3
+        t267 = t66 * t87 * 5.695020205797351e-7
+        t268 = t77 * t87 * 2.662715263644876e-4
+        t269 = t55 * t87 * t159 * t191 * 2.698593356722665e-4
+        t270 = t34 * t133 * t172 * t211 * 2.408872289627689e-5
+        t271 = t66 * t87 * t164 * t188 * 2.919147494282987e-5
+        t272 = t15 * t87 * t156 * t209 * 5.43860953025742e-6
+        t273 = t44 * t87 * t170 * t200 * 2.888145048134885e-5
+        t274 = t77 * t133 * t168 * t211 * 1.071251714048381e-4
+        t275 = t263 + t264 + t265 + t266 + t267 + t268 + t269 + t270 + t271 + t272 + t273 + t274 - t24 * t87 * 2.292270341531259e-5 - t24 * t87 * t162 * t198 * 3.869452814178776e-5 - t34 * t87 * t172 * t204 * 2.408872289627689e-5 - t15 * t133 * t156 * t211 * 5.43860953025742e-6 - t77 * t87 * t168 * t195 * 1.071251714048381e-4 - t24 * t133 * t162 * t211 * 3.869452814178776e-5 - t44 * t133 * t170 * t211 * 2.888145048134885e-5 - t55 * t133 * t159 * t211 * 2.698593356722665e-4 - t66 * t133 * t164 * t211 * 2.919147494282987e-5
+        t276 = t152 * t216 * 9.0e2
+        t277 = t15 * t87 * 1.128234845786051e-5
+        t278 = t24 * t87 * 6.340821028223617e-5
+        t279 = t34 * t87 * 5.49927270442291e-5
+        t280 = t44 * t87 * 6.9619499232357e-5
+        t281 = t55 * t87 * 2.725681819413176e-3
+        t282 = t66 * t87 * 6.335636802894656e-5
+        t283 = t77 * t87 * 3.419331942636945e-4
+        t284 = t77 * t114 * t133 * t211 * 1.071251714048381e-4
+        t285 = t44 * t133 * t139 * t211 * 2.888145048134885e-5
+        t286 = t34 * t133 * t142 * t211 * 2.408872289627689e-5
+        t287 = t66 * t133 * t145 * t211 * 2.919147494282987e-5
+        t288 = t15 * t133 * t148 * t211 * 5.43860953025742e-6
+        t289 = t55 * t104 * t133 * t211 * 2.698593356722665e-4
+        t290 = t277 + t278 + t279 + t280 + t281 + t282 + t283 + t284 + t285 + t286 + t287 + t288 + t289 - t55 * t87 * t104 * t191 * 2.698593356722665e-4 - t24 * t87 * t135 * t198 * 3.869452814178776e-5 - t15 * t87 * t148 * t209 * 5.43860953025742e-6 - t34 * t87 * t142 * t204 * 2.408872289627689e-5 - t44 * t87 * t139 * t200 * 2.888145048134885e-5 - t77 * t87 * t114 * t195 * 1.071251714048381e-4 - t66 * t87 * t145 * t188 * 2.919147494282987e-5 - t24 * t133 * t135 * t211 * 3.869452814178776e-5
+        return np.reshape([-t185 * t259 + t223 * (
+                t226 + t150 * t153 * t176 * 1.8e3) - t2 * t152 * t182 * 1.8e3 - t2 * t150 * t152 * t243 * 9.0e2 + t2 * t150 ** 2 * t176 * t182 * 1.8e3,
+                           t243 * t262 + t182 * (
+                                   t226 - t150 * t176 * t227 * 1.8e3) + t152 * t216 * t223 * 9.0e2 + t3 * t152 * t216 * t259 * 9.0e2 - t3 * t150 * t176 * t216 * t223 * 1.8e3,
+                           -t185 * t290 - t223 * (
+                                   t276 - t153 * t176 * t216 * 1.8e3) - t150 * t152 * t182 * 9.0e2 + t2 * t150 * t152 * t275 * 9.0e2 + t2 * t150 * t176 * t182 * t216 * 1.8e3,
+                           -t262 * t275 - t182 * (
+                                   t276 + t176 * t216 * t227 * 1.8e3) + t3 * t152 * t223 * 1.8e3 + t3 * t152 * t216 * t290 * 9.0e2 - t3 * t176 * t216 ** 2 * t223 * 1.8e3],
+                          [2, 2], 'F')
+
+    def weights(self, x):
+        num = np.zeros(self.nKernels)
+        for w in range(self.nKernels):
+            num[w] = self.priors[w] * self.mvn_pdf(x, self.mu[w, :self.n], self.sigma[w, :self.n, :self.n])
+        den = num.sum()
+        return num / den
+
+    @staticmethod
+    def mvn_pdf(x, mu, sigma):
+        n = x.size
+        return 1 / np.sqrt((2 * np.pi) ** n * np.linalg.det(sigma)) * np.exp(
+            -0.5 * (x - mu).transpose().dot(np.linalg.inv(sigma).dot(x - mu)))
+
+    def modulation_matrix(self, x):
+        xd = x - self.o_c
+        return np.eye(self.n) + (self.o_r / xd.transpose().dot(xd))**2 * (xd.transpose().dot(xd) * np.eye(self.n) -
+                                                                          2 * np.outer(xd, xd))
+
+    def gamma(self, x):
+        return sum((np.linalg.norm(x[i] - self.o_c[i]) / self.o_r) ** 2 for i in range(self.n))
+
+    def lambda_r(self, x):
+        return 1 - 1 / self.gamma(x)
+
+    def lambda_e(self, x):
+        return 1 + 1 / self.gamma(x)
diff --git a/dmp/motion_planning/online_traj_scaling/gmr_oa.pyc b/dmp/motion_planning/online_traj_scaling/gmr_oa.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..248b7e889920da02a0f108bf4358457600deb468
Binary files /dev/null and b/dmp/motion_planning/online_traj_scaling/gmr_oa.pyc differ
diff --git a/dmp/motion_planning/online_traj_scaling/trajectory_generator.py b/dmp/motion_planning/online_traj_scaling/trajectory_generator.py
new file mode 100755
index 0000000000000000000000000000000000000000..899b8af111b59b9f2ed1b4e117a0b3adf47a77c2
--- /dev/null
+++ b/dmp/motion_planning/online_traj_scaling/trajectory_generator.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+
+import matplotlib.pyplot as plt
+import yaml
+from gmr_oa import GMRwOA
+import numpy as np
+
+class TrajectoryGenerator:
+    def __init__(self, dyn_sys):
+        # parameters
+        self.dyn_sys = dyn_sys
+        # state
+        self.x = None
+        self.s = None
+        self.ds = None
+        self.sat_flag = None
+        # Output state
+        self.pos = None
+        self.vel = None
+        self.acc = None
+        # desired path
+        self.path = None
+
+        self.reset()
+
+    def reset(self):
+        self.x = self.dyn_sys.x0
+        self.s = 0
+        self.ds = 1
+        self.sat_flag = 0
+        self.pos = self.dyn_sys.g(self.x)
+        self.vel = self.dyn_sys.gx(self.x).dot(self.dyn_sys.f(self.x))
+        self.acc = self.dyn_sys.dx_gxf(self.x).dot(self.dyn_sys.f(self.x))
+
+    def step(self, dt):
+        # Derivative
+        dx = self.dyn_sys.f(self.x) * self.ds
+        dds, self.sat_flag = self.traj_scaling()
+
+        # Integrate
+        self.x += dx * dt
+        self.s += self.ds * dt
+        self.ds += dds * dt
+
+        # Update reference
+        self.pos = self.dyn_sys.g(self.x)
+        self.vel = self.dyn_sys.gx(self.x).dot(self.dyn_sys.f(self.x))
+        self.acc = self.dyn_sys.gx(self.x).dot(self.dyn_sys.f(self.x)) * dds + self.dyn_sys.dx_gxf(
+            self.x).dot(self.dyn_sys.f(self.x)) * self.ds ** 2
+
+    def roll_out(self, dt, T = None):
+        self.reset()
+        pos = np.array([self.pos])
+        vel = np.array([self.vel])
+        acc = np.array([self.acc])
+        t = np.array([0])
+        s = np.array([0])
+        # for k in range(1, round(T/dt)+1):
+        k = 0
+        while True:
+            k += 1
+            self.step(dt)
+            t = np.append(t, k*dt)
+            s = np.append(s, self.s)
+            pos = np.append(pos, np.array([self.pos]), axis=0)
+            vel = np.append(vel, np.array([self.vel]), axis=0)
+            acc = np.append(acc, np.array([self.acc]), axis=0)
+            if T and k*dt > T:
+                break
+            if not T and self.s > self.dyn_sys.s_end:
+                break
+        return t, s, pos, vel, acc
+
+    def traj_scaling(self):
+        dds = 0
+        sat_flag = 0
+
+        return dds, sat_flag
+
+if __name__ == "__main__":
+    with open("example.yaml", 'r') as stream:
+        try:
+            params = yaml.safe_load(stream)
+            params['sigma'] = [[[el * 1e3 for el in row] for row in col] for col in params['sigma']]
+            gmr = GMRwOA(params)
+            tg = TrajectoryGenerator(gmr)
+            t, s, pos, vel, acc = tg.roll_out(0.01)
+            plt.plot(0.0032*pos[:, 0], 0.0026*pos[:, 1] + 0.7)
+            # plt.plot(s, pos[:, 0])
+            # plt.plot(s, pos[:, 1])
+            plt.show()
+        except yaml.YAMLError as exc:
+            print(exc)
diff --git a/dmp/motion_planning/online_traj_scaling/trajectory_generator.pyc b/dmp/motion_planning/online_traj_scaling/trajectory_generator.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c1df99f5686f4e652cb2f5d7683dfb0f5585c66d
Binary files /dev/null and b/dmp/motion_planning/online_traj_scaling/trajectory_generator.pyc differ
diff --git a/dmp/msg/DMPState.msg b/dmp/msg/DMPState.msg
new file mode 100644
index 0000000000000000000000000000000000000000..aec661340a80f5bc98105bb4e8a50638a52729e2
--- /dev/null
+++ b/dmp/msg/DMPState.msg
@@ -0,0 +1,8 @@
+Header header
+float64[] position
+float64[] velocity
+float64[] acceleration
+float64 theta
+float64 s
+float64 tau
+
diff --git a/dmp/msg/TrajGenState.msg b/dmp/msg/TrajGenState.msg
new file mode 100644
index 0000000000000000000000000000000000000000..936c4e96b4b84285eea5f00aecc71e992f24b4d0
--- /dev/null
+++ b/dmp/msg/TrajGenState.msg
@@ -0,0 +1,6 @@
+Header header
+float64[] position
+float64[] velocity
+float64[] acceleration
+float64 s
+float64 s_dot
diff --git a/dmp/todos.md b/dmp/todos.md
index ec74f5a845c41a79b87614cf508e8e7400ab7a78..6ac3bb831992623388fb33de998b165b22caa598 100644
--- a/dmp/todos.md
+++ b/dmp/todos.md
@@ -4,7 +4,7 @@ and it's matlab
 
 # calculating the dmp from the trajectory
 is in 
-TC_DMP_constrainedVelAcc/something/DMP.m
+TC_DMP_constrainedVelAcc/matlab/DMP.m
 
 # running the dmp node
 TC_DMP_constrainedVelAcc/catkin_ws/src/motion_planning/nodes/dmp_node
diff --git a/dmp/traj_scaling_node b/dmp/traj_scaling_node
new file mode 100755
index 0000000000000000000000000000000000000000..e4e6acad8e99984466b41df2e84efdcd15a7fdea
--- /dev/null
+++ b/dmp/traj_scaling_node
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+
+from motion_planning.online_traj_scaling import GMRwOA, TrajectoryGenerator
+import numpy as np
+import rospy
+from robot_ctrl.msg import CtrlTarget
+from std_msgs.msg import Float64, String
+from motion_planning.msg import TrajGenState
+
+
+class TrajGenNode:
+    def __init__(self):
+        self.active = False
+        self.rate = None
+        self.dt = None
+        self.traj_gen = None
+
+        # Load parameters from server
+        if not self.load_params():
+            rospy.logwarn("Trajectory Generator not initialized")
+
+        # Setup ros topics
+        self.target_pub = rospy.Publisher("robot_ctrl/command", CtrlTarget, queue_size=1)
+        self.state_pub = rospy.Publisher("motion_planning/state", TrajGenState, queue_size=1)
+        rospy.Subscriber("motion_planning/command", String, self.command_parser)
+
+        # Go into spin
+        self.spin()
+
+    def load_params(self):
+        parameters = ['x0', 's_end', 'priors', 'mu', 'sigma', 'o_c', 'o_r']
+        if not rospy.has_param('motion_planning/update_rate'):
+            rospy.logerr("Parameter " + rospy.get_namespace() + "motion_planning/update_rate not on parameter server.")
+            return False
+        update_rate = rospy.get_param('motion_planning/update_rate')
+        self.rate = rospy.Rate(update_rate)
+        params = {}
+        for i in range(len(parameters)):
+            if not rospy.has_param('motion_planning/' + parameters[i]):
+                rospy.logerr("Parameter " + rospy.get_namespace() + "motion_planning/" + parameters[i] + " not on parameter server.")
+                return False
+            params[parameters[i]] = rospy.get_param('motion_planning/' + parameters[i])
+        gmr = GMRwOA(params)
+        self.traj_gen = TrajectoryGenerator(gmr)
+        return True
+
+    def command_parser(self, msg):
+        if msg.data == 'start':
+            self.active = True
+        elif msg.data == 'stop':
+            self.active = False
+        elif msg.data == 'reset':
+            self.traj_gen.reset()
+            self.active = False
+            rospy.loginfo("Reset motion_planner.")
+        elif msg.data == 'step':
+            self.traj_gen.step(self.dt)
+        elif msg.data == 'load_params':
+            self.load_params()
+            rospy.loginfo("Reloaded motion_planner parameters.")
+        else:
+            rospy.loginfo("Invalid command string for motion planner.")
+
+    # spin -----------------------------------------------------
+    # -----------------------------------------------------------
+    def spin(self):
+        print_flag = True
+        while not rospy.is_shutdown():
+
+            if self.active:
+                # Step DMP
+                self.traj_gen.step(self.dt)
+                # Send target trajectory state command
+                pub_msg = CtrlTarget()
+                pub_msg.header.stamp = rospy.Time.now()
+                pub_msg.acceleration = self.traj_gen.acc
+                pub_msg.velocity = self.traj_gen.vel
+                pub_msg.position = self.traj_gen.pos
+                self.target_pub.publish(pub_msg)
+            else:
+                print_flag = True
+
+            # Publish DMP state command
+            pub_msg = TrajGenState()
+            pub_msg.header.stamp = rospy.Time.now()
+            pub_msg.acceleration = [0.0032*self.traj_gen.acc[0], 0, 0.0026*self.traj_gen.acc[1]]
+            pub_msg.velocity = [0.0032*self.traj_gen.vel[0], 0, 0.0026*self.traj_gen.vel[1]]
+            pub_msg.position = [0.0032*self.traj_gen.pos[0], 0, 0.0026*self.traj_gen.pos[1]+0.7]
+            pub_msg.s = self.traj_gen.s
+            pub_msg.s_dot = self.traj_gen.ds
+            self.state_pub.publish(pub_msg)
+
+            # Notify when DMP trajectory is finished
+            if print_flag and self.traj_gen.s > self.traj_gen.dyn_sys.s_end:
+                rospy.loginfo("Trajectory finished.")
+                print_flag = False
+
+            # Sleep
+            self.rate.sleep()
+
+
+# --------------------------------------------------------------------
+# Here is the main entry point
+if __name__ == '__main__':
+    try:
+        # Init the node:
+        rospy.init_node('TrajGenNode')
+
+        # Initializing and continue running the main class:
+        TrajGenNode()
+
+    except rospy.ROSInterruptException:
+        pass