From 4259a8f0387ba66294cfba99e5f27c8286e5f2e0 Mon Sep 17 00:00:00 2001
From: Philip Abbet <philip.abbet@idiap.ch>
Date: Fri, 23 Feb 2024 14:28:18 +0100
Subject: [PATCH] Fix some issues in 'iLQR_manipulator3D.py'

---
 python/iLQR_manipulator3D.py | 38 +++++++++++++++++++++++-------------
 1 file changed, 24 insertions(+), 14 deletions(-)

diff --git a/python/iLQR_manipulator3D.py b/python/iLQR_manipulator3D.py
index 60e66de..d16fb83 100644
--- a/python/iLQR_manipulator3D.py
+++ b/python/iLQR_manipulator3D.py
@@ -79,19 +79,20 @@ def logmap(f, f0):
 
 # Logarithmic map for S^3 manifold (with e in ambient space)
 def logmap_S3(x, x0):
+	x0 = x0.reshape((4, 1))
+	x = x.reshape((4, 1))
+
 	th = acoslog(x0.T @ x)
-	if math.isnan(th):
-		th = 1.0
 
 	u = x - (x0.T @ x) * x0
-	u = np.multiply(th, u) / np.linalg.norm(u)
+	if np.linalg.norm(u) > 1e-9:
+		u = np.multiply(th, u) / np.linalg.norm(u)
 
-	# import sys; sys.exit(0)
-	return u
+	return u[:, 0]
 
 # Arcosine redefinition to make sure the distance between antipodal quaternions is zero
 def acoslog(x):
-	y = np.arccos(x)
+	y = np.arccos(x)[0][0]
 	if (x>=-1.0) and (x<0):
 		y = y - np.pi
 	return y
@@ -175,7 +176,7 @@ Q = np.eye((param.nbVarF-1) * param.nbPoints) * param.q
 R = np.eye((param.nbData-1) * param.nbVarU) * param.r
 
 # Time occurrence of viapoints
-tl = np.linspace(0, param.nbData, param.nbPoints+1)
+tl = np.linspace(1, param.nbData, param.nbPoints+1)
 tl = np.rint(tl[1:]).astype(np.int64) - 1
 idx = np.array([i + np.arange(0,param.nbVarX,1) for i in (tl*param.nbVarX)]).flatten()
 
@@ -191,28 +192,37 @@ Su = Su0[idx,:] # We remove the lines that are out of interest
 # iLQR
 # ===============================
 
-u = np.zeros(param.nbVarU * (param.nbData-1)) # Initial control command
+u = np.zeros((param.nbVarU * (param.nbData-1), 1)) # Initial control command
 x0 = np.array([0, 0, 0, -np.pi/2, -0, np.pi/2, 0]) # Initial robot pose
 
+x0 = x0.reshape((-1, 1))
+
 for i in range(param.nbIter):
 	x = Su0 @ u + Sx0 @ x0 # System evolution
 	x = x.reshape([param.nbVarX, param.nbData], order='F')
+
 	f, J = f_reach(x[:,tl], param) # Residuals and Jacobians
-	du = np.linalg.inv(Su.T @ J.T @ Q @ J @ Su + R) @ (-Su.T @ J.T @ Q @ f.flatten('F') - u * param.r) # Gauss-Newton update
+	f = f.reshape((-1,1), order='F')
+
+	du = np.linalg.pinv(Su.T @ J.T @ Q @ J @ Su + R) @ (-Su.T @ J.T @ Q @ f - u * param.r) # Gauss-Newton update
+
 	# Estimate step size with backtracking line search method
 	alpha = 1
-	cost0 = f.flatten('F').T @ Q @ f.flatten('F') + np.linalg.norm(u)**2 * param.r # Cost
+	cost0 = f.T @ Q @ f + np.linalg.norm(u)**2 * param.r # Cost
 	while True:
 		utmp = u + du * alpha
 		xtmp = Su0 @ utmp + Sx0 @ x0 # System evolution
 		xtmp = xtmp.reshape([param.nbVarX, param.nbData], order='F')
-		ftmp,_ = f_reach(xtmp[:,tl], param) # Residuals 
-		cost = ftmp.flatten('F').T @ Q @ ftmp.flatten('F') + np.linalg.norm(utmp)**2 * param.r # Cost
+		ftmp,_ = f_reach(xtmp[:,tl], param) # Residuals
+		ftmp = ftmp.reshape((-1,1), order='F')
+		cost = ftmp.T @ Q @ ftmp + np.linalg.norm(utmp)**2 * param.r # Cost
 		if cost < cost0 or alpha < 1e-3:
-			u = utmp
-			print("Iteration {}, cost: {}".format(i,cost))
+			print("Iteration {}, cost: {}".format(i,cost[0][0]))
 			break
 		alpha /= 2
+
+	u = u + du * alpha
+
 	if np.linalg.norm(du * alpha) < 1E-2:
 		break # Stop iLQR iterations when solution is reached
 
-- 
GitLab