diff --git a/matlab/iLQR_manipulator_obstacle.m b/matlab/iLQR_manipulator_obstacle.m
index cd7f986ea825a51531e0ffc5489326046f3273b7..803316391d56810959e69510bc9859c29b01b50f 100644
--- a/matlab/iLQR_manipulator_obstacle.m
+++ b/matlab/iLQR_manipulator_obstacle.m
@@ -2,7 +2,8 @@
 %% 	  (viapoints task with position+orientation including bounding boxes on f(x))
 %%
 %%    Copyright (c) 2021 Idiap Research Institute, http://www.idiap.ch/
-%%    Written by Sylvain Calinon <https://calinon.ch>
+%%    Written by Teguh Lembono <teguh.lembono@idiap.ch>, 
+%%		Sylvain Calinon <https://calinon.ch>
 %%
 %%    This file is part of RCFS.
 %%
@@ -24,7 +25,7 @@ function iLQR_manipulator_obstacle
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 param.dt = 1E-2; %Time step size
 param.nbData = 50; %Number of datapoints
-param.nbIter = 50; %Number of iterations for iLQR
+param.nbIter = 30; %Number of iterations for iLQR
 param.nbPoints = 1; %Number of viapoints
 param.nbObstacles = 2; %Number of obstacles
 param.nbVarX = 3; %State space dimension (q1,q2,q3)
@@ -35,6 +36,7 @@ param.sz2 = [.5, .8]; %Size of obstacles
 param.q = 1E2; %Tracking weight term
 param.q2 = 1E0; %Obstacle avoidance weight term
 param.r = 1E-3; %Control weight term
+param.useBatch = true; %use batch computation for collision cost
 
 param.Mu = [[3; -1; 0]]; %Viapoints (x1,x2,o)
 
@@ -64,11 +66,16 @@ Su0 = [zeros(param.nbVarX, param.nbVarX*(param.nbData-1)); tril(kron(ones(param.
 Sx0 = kron(ones(param.nbData,1), eye(param.nbVarX));
 Su = Su0(idx,:);
 
+tic;
 for n=1:param.nbIter
 	x = reshape(Su0 * u + Sx0 * x0, param.nbVarX, param.nbData); %System evolution
 	[f, J] = f_reach(x(:,tl), param); %Tracking objective
 	
-	[f2, J2, id2] = f_avoid(x, param); %Avoidance objective
+	if param.useBatch
+		[f2, J2, id2] = f_avoid2(x, param); %Avoidance objective
+	else
+		[f2, J2, id2] = f_avoid(x, param); %Avoidance objective
+	end
 	Su2 = Su0(id2,:);
 	
 	du = (Su' * J' * J * Su * param.q + Su2' * J2' * J2 * Su2 * param.q2 + R) \ ...
@@ -81,7 +88,11 @@ for n=1:param.nbIter
 		utmp = u + du * alpha;
 		xtmp = reshape(Su0 * utmp + Sx0 * x0, param.nbVarX, param.nbData);
 		ftmp = f_reach(xtmp(:,tl), param); %Tracking objective
-		ftmp2 = f_avoid(xtmp, param); %Avoidance objective
+		if param.useBatch
+			ftmp2 = f_avoid2(xtmp, param); %Avoidance objective
+		else
+			ftmp2 = f_avoid(xtmp, param); %Avoidance objective
+		end
 		cost = norm(ftmp(:))^2 * param.q + norm(ftmp2(:))^2 * param.q2 + norm(utmp)^2 * param.r;
 		if cost < cost0 || alpha < 1E-3
 			break;
@@ -89,13 +100,14 @@ for n=1:param.nbIter
 		alpha = alpha * 0.5;
 	end
 	u = u + du * alpha;
-	
+	disp(cost)
 	if norm(du * alpha) < 1E-2
 		break; %Stop iLQR when solution is reached
 	end
 end
 disp(['iLQR converged in ' num2str(n) ' iterations.']);
-
+toc
+%disp(tEnd-tStart)
 %Log data
 r.x = x;
 r.f = [];
@@ -192,6 +204,7 @@ function [f, J, id] = f_avoid(x, param)
 					f = [f; ftmp];
 					Jrob = [jkin(x(1:j,t), param.l(1:j)), zeros(param.nbVarF, param.nbVarU-j)];
 					Jtmp = -e' * param.U2(:,:,i)' * Jrob(1:2,:); %quadratic form
+
 					J = blkdiag(J, Jtmp);
 					id = [id, (t-1) * param.nbVarU + [1:param.nbVarU]'];
 				end
@@ -199,3 +212,46 @@ function [f, J, id] = f_avoid(x, param)
 		end
 	end
 end
+
+%%%%%%%%%%%%%%%%%%%%%%
+%Forward kinematics for all robot articulations in batch
+function f = fkin0batch(x, L)
+	T = tril(ones(size(x,1)));
+	T2 = T * diag(L);
+	f = [(T2 * cos(T * x))(:), ...
+			(T2 * sin(T * x))(:)]; 
+end
+
+%%%%%%%%%%%%%%%%%%%%%%
+%Cost and gradient for an obstacle avoidance task with batch computation
+function [f, J, id] = f_avoid2(x, param)
+	f=[]; J=[]; id=[];
+	for i=1:param.nbObstacles
+		xee_batch = fkin0batch(x, param.l);
+		n= size(xee_batch,1);
+		e = (xee_batch - repmat(param.Mu2(1:2,i)', n , 1)) * param.U2(:,:,i);
+		ftmp = ones(n,1) - sum(e.^2, 2); %quadratic form
+		
+		%get the indices where there is collision (ftmp > 0)
+		idx_active = linspace(1,n,n)(ftmp>0);
+		
+		for idx=1:size(idx_active,2)
+			j = idx_active(idx);
+			t = floor((j-1)/param.nbVarX)+1;
+			k = mod(j-1,param.nbVarX)+1;	
+	
+			%compute Jacobian
+			Jrob = [jkin(x(1:k,t), param.l(1:k)), zeros(param.nbVarF, param.nbVarX-k)];
+			Jtmp = -e(j,:) * param.U2(:,:,i)' * Jrob(1:2,:); %quadratic form
+			Jj = zeros(1,param.nbVarX*param.nbData);
+			Jj(:,param.nbVarX*(t-1)+1:param.nbVarX*(t)) = Jtmp;
+			J = [J; Jj];
+			id = [id, (t-1) * param.nbVarX + [1:param.nbVarX]'];
+		end
+		
+		f = [f; ftmp(idx_active(:))];		#keep only active value
+	end
+	
+	id = unique(id); #remove duplicate
+	J = J(:,id); #keep only active value
+end
\ No newline at end of file
diff --git a/python/iLQR_manipulator_obstacle.py b/python/iLQR_manipulator_obstacle.py
index 744586a10f9dd16b817c46612c18ec09e03e04ef..ff77cbb4d52faede7812138a5f85c2a53f178288 100644
--- a/python/iLQR_manipulator_obstacle.py
+++ b/python/iLQR_manipulator_obstacle.py
@@ -87,7 +87,7 @@ def f_avoid(x, param):
 
                 if ftmp > 0:
                     f += [ftmp]
-                    J_rbt = np.hstack(( jkin(x[t,:(j+1)] , param.linkLengths[:(j+1)]), np.zeros(( param.nbVarF , param.nbVarU-(j+1))) ))
+                    J_rbt = np.hstack(( jkin(x[t,:(j+1)] , param.linkLengths[:(j+1)]), np.zeros(( param.nbVarF , param.nbVarX-(j+1))) ))
                     J_tmp = (-e.T @ param.U_obs[i].T @ J_rbt[:2]).reshape((-1,1))
                     #J_tmp = 1*(J_rbt[:2].T @ param.U_obs[i] @ e).reshape((-1,1))
 
@@ -96,7 +96,7 @@ def f_avoid(x, param):
                     J2[-J_tmp.shape[0]:,-J_tmp.shape[1]:] = J_tmp
                     J = J2 # Numpy does not provid a blockdiag function...
 
-                    idx.append( t*param.nbVarU + np.array(range(param.nbVarU)) )
+                    idx.append( t*param.nbVarX + np.array(range(param.nbVarX)) )
 
     f = np.array(f)
     idx = np.array(idx)