Changed the cost to use Angle nad added LSQ cost for experiments
This commit is contained in:
@ -1,8 +1,8 @@
|
|||||||
from typing import Tuple, Union, Any, Callable, List, Optional
|
from typing import Tuple, Union, Any, Callable, List, Optional
|
||||||
from nptyping import NDArray as Array
|
from nptyping import NDArray as Array
|
||||||
|
|
||||||
from numpy import array, eye, zeros
|
from numpy import array, eye, zeros, pi
|
||||||
from scipy.optimize import minimize
|
from scipy.optimize import minimize, least_squares
|
||||||
|
|
||||||
from OCP.gp import gp_Vec, gp_Dir, gp_Pnt, gp_Trsf, gp_Quaternion
|
from OCP.gp import gp_Vec, gp_Dir, gp_Pnt, gp_Trsf, gp_Quaternion
|
||||||
|
|
||||||
@ -13,8 +13,8 @@ ConstraintMarker = Union[gp_Dir, gp_Pnt]
|
|||||||
Constraint = Tuple[Tuple[ConstraintMarker, ...], Tuple[Optional[ConstraintMarker], ...]]
|
Constraint = Tuple[Tuple[ConstraintMarker, ...], Tuple[Optional[ConstraintMarker], ...]]
|
||||||
|
|
||||||
NDOF = 6
|
NDOF = 6
|
||||||
DIR_SCALING = 1e3
|
DIR_SCALING = 1e4
|
||||||
DIFF_EPS = 1e-8
|
DIFF_EPS = 1e-9
|
||||||
|
|
||||||
|
|
||||||
class ConstraintSolver(object):
|
class ConstraintSolver(object):
|
||||||
@ -91,10 +91,12 @@ class ConstraintSolver(object):
|
|||||||
return (m1.Transformed(t1).XYZ() - m2.Transformed(t2).XYZ()).SquareModulus()
|
return (m1.Transformed(t1).XYZ() - m2.Transformed(t2).XYZ()).SquareModulus()
|
||||||
|
|
||||||
def dir_cost(
|
def dir_cost(
|
||||||
m1: gp_Dir, m2: gp_Dir, t1: gp_Trsf, t2: gp_Trsf, val: float = -1
|
m1: gp_Dir, m2: gp_Dir, t1: gp_Trsf, t2: gp_Trsf, val: float = pi
|
||||||
) -> float:
|
) -> float:
|
||||||
|
|
||||||
return DIR_SCALING * (val - m1.Transformed(t1).Dot(m2.Transformed(t2))) ** 2
|
return (
|
||||||
|
DIR_SCALING * (val - m1.Transformed(t1).Angle(m2.Transformed(t2))) ** 2
|
||||||
|
)
|
||||||
|
|
||||||
def f(x):
|
def f(x):
|
||||||
|
|
||||||
@ -183,6 +185,116 @@ class ConstraintSolver(object):
|
|||||||
|
|
||||||
return f, jac
|
return f, jac
|
||||||
|
|
||||||
|
def _costlsq(
|
||||||
|
self,
|
||||||
|
) -> Tuple[
|
||||||
|
Callable[[Array[(Any,), float]], Array[(Any,), float]],
|
||||||
|
Callable[[Array[(Any,), float]], Array[(Any, Any), float]],
|
||||||
|
]:
|
||||||
|
def pt_cost(m1: gp_Pnt, m2: gp_Pnt, t1: gp_Trsf, t2: gp_Trsf) -> float:
|
||||||
|
|
||||||
|
return (m1.Transformed(t1).XYZ() - m2.Transformed(t2).XYZ()).Modulus()
|
||||||
|
|
||||||
|
def dir_cost(
|
||||||
|
m1: gp_Dir, m2: gp_Dir, t1: gp_Trsf, t2: gp_Trsf, val: float = pi
|
||||||
|
) -> float:
|
||||||
|
|
||||||
|
return val - m1.Transformed(t1).Angle(m2.Transformed(t2))
|
||||||
|
|
||||||
|
def f(x):
|
||||||
|
|
||||||
|
constraints = self.constraints
|
||||||
|
ne = self.ne
|
||||||
|
nc = self.nc
|
||||||
|
|
||||||
|
rv = zeros(nc + ne * NDOF)
|
||||||
|
|
||||||
|
transforms = [
|
||||||
|
self._build_transform(*x[NDOF * i : NDOF * (i + 1)]) for i in range(ne)
|
||||||
|
]
|
||||||
|
|
||||||
|
for i, ((k1, k2), (ms1, ms2)) in enumerate(constraints):
|
||||||
|
t1 = transforms[k1] if k1 not in self.locked else gp_Trsf()
|
||||||
|
t2 = transforms[k2] if k2 not in self.locked else gp_Trsf()
|
||||||
|
|
||||||
|
for m1, m2 in zip(ms1, ms2):
|
||||||
|
if isinstance(m1, gp_Pnt):
|
||||||
|
rv[i] += pt_cost(m1, m2, t1, t2)
|
||||||
|
elif isinstance(m1, gp_Dir):
|
||||||
|
rv[i] += dir_cost(m1, m2, t1, t2)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(f"{m1,m2}")
|
||||||
|
|
||||||
|
rv[nc:] = 1e-9 * x ** 2
|
||||||
|
|
||||||
|
return rv
|
||||||
|
|
||||||
|
def jac(x):
|
||||||
|
|
||||||
|
constraints = self.constraints
|
||||||
|
ne = self.ne
|
||||||
|
nc = self.nc
|
||||||
|
|
||||||
|
delta = DIFF_EPS * eye(NDOF)
|
||||||
|
|
||||||
|
rv = zeros((nc + NDOF * ne, NDOF * ne))
|
||||||
|
|
||||||
|
transforms = [
|
||||||
|
self._build_transform(*x[NDOF * i : NDOF * (i + 1)]) for i in range(ne)
|
||||||
|
]
|
||||||
|
|
||||||
|
transforms_delta = [
|
||||||
|
self._build_transform(*(x[NDOF * i : NDOF * (i + 1)] + delta[j, :]))
|
||||||
|
for i in range(ne)
|
||||||
|
for j in range(NDOF)
|
||||||
|
]
|
||||||
|
|
||||||
|
for i, ((k1, k2), (ms1, ms2)) in enumerate(constraints):
|
||||||
|
t1 = transforms[k1] if k1 not in self.locked else gp_Trsf()
|
||||||
|
t2 = transforms[k2] if k2 not in self.locked else gp_Trsf()
|
||||||
|
|
||||||
|
for m1, m2 in zip(ms1, ms2):
|
||||||
|
if isinstance(m1, gp_Pnt):
|
||||||
|
tmp = pt_cost(m1, m2, t1, t2)
|
||||||
|
|
||||||
|
for j in range(NDOF):
|
||||||
|
|
||||||
|
t1j = transforms_delta[k1 * NDOF + j]
|
||||||
|
t2j = transforms_delta[k2 * NDOF + j]
|
||||||
|
|
||||||
|
if k1 not in self.locked:
|
||||||
|
tmp1 = pt_cost(m1, m2, t1j, t2)
|
||||||
|
rv[i, k1 * NDOF + j] += (tmp1 - tmp) / DIFF_EPS
|
||||||
|
|
||||||
|
if k2 not in self.locked:
|
||||||
|
tmp2 = pt_cost(m1, m2, t1, t2j)
|
||||||
|
rv[i, k2 * NDOF + j] += (tmp2 - tmp) / DIFF_EPS
|
||||||
|
|
||||||
|
elif isinstance(m1, gp_Dir):
|
||||||
|
tmp = dir_cost(m1, m2, t1, t2)
|
||||||
|
|
||||||
|
for j in range(NDOF):
|
||||||
|
|
||||||
|
t1j = transforms_delta[k1 * NDOF + j]
|
||||||
|
t2j = transforms_delta[k2 * NDOF + j]
|
||||||
|
|
||||||
|
if k1 not in self.locked:
|
||||||
|
tmp1 = dir_cost(m1, m2, t1j, t2)
|
||||||
|
rv[i, k1 * NDOF + j] += (tmp1 - tmp) / DIFF_EPS
|
||||||
|
|
||||||
|
if k2 not in self.locked:
|
||||||
|
tmp2 = dir_cost(m1, m2, t1, t2j)
|
||||||
|
rv[i, k2 * NDOF + j] += (tmp2 - tmp) / DIFF_EPS
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(f"{m1,m2}")
|
||||||
|
|
||||||
|
for i in range(NDOF * ne):
|
||||||
|
rv[nc + i, i] = 1e-9
|
||||||
|
|
||||||
|
return rv
|
||||||
|
|
||||||
|
return f, jac
|
||||||
|
|
||||||
def solve(self) -> List[Location]:
|
def solve(self) -> List[Location]:
|
||||||
|
|
||||||
x0 = array([el for el in self.entities]).ravel()
|
x0 = array([el for el in self.entities]).ravel()
|
||||||
@ -192,12 +304,11 @@ class ConstraintSolver(object):
|
|||||||
f,
|
f,
|
||||||
x0,
|
x0,
|
||||||
jac=jac,
|
jac=jac,
|
||||||
method="L-BFGS-B",
|
method="BFGS",
|
||||||
options=dict(disp=True, ftol=1e-14, maxiter=1000),
|
options=dict(disp=True, ftol=1e-12, maxiter=1000),
|
||||||
)
|
)
|
||||||
|
|
||||||
x = res.x
|
x = res.x
|
||||||
print(res.message)
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Location(self._build_transform(*x[NDOF * i : NDOF * (i + 1)]))
|
Location(self._build_transform(*x[NDOF * i : NDOF * (i + 1)]))
|
||||||
|
|||||||
Reference in New Issue
Block a user