Skip to content

Commit b68811f

Browse files
committed
up - working? 🐝 :honey:
1 parent 408f079 commit b68811f

4 files changed

Lines changed: 170 additions & 91 deletions

File tree

dev/test.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,18 @@ def main():
3131
t = kevin()
3232
kc = KinematicChain.from_parameters(t)
3333

34-
j = [
35-
[0,0,0,0,0],
36-
[0,pi/4,-pi/4,-pi/2,0], # 204, 0, -32
37-
# [0,0,-pi/2,0,0],
38-
# np.deg2rad([90,131.17,-106.19,-114.98]),
39-
np.deg2rad([-45.00, 77.41, -98.15, -69.27, 0]) # 110, -110, -40
40-
]
34+
# j = [
35+
# [0,0,0,0,0],
36+
# [0,pi/4,-pi/4,-pi/2,0], # 204, 0, -32
37+
# # [0,0,-pi/2,0,0],
38+
# # np.deg2rad([90,131.17,-106.19,-114.98]),
39+
# np.deg2rad([-45.00, 77.41, -98.15, -69.27, 0]) # 110, -110, -40
40+
# ]
4141

42-
for jj in j:
43-
# print(jj)
44-
t = kc.transform(jj)
45-
print(t)
42+
# for jj in j:
43+
# # print(jj)
44+
# t = kc.transform(jj)
45+
# print(t)
4646
# print("----------------------")
4747

4848
j = [
@@ -53,7 +53,13 @@ def main():
5353
]
5454

5555
for jj in j:
56-
rads = kc.inverse(jj)
56+
p = np.array([
57+
[0,1,0, jj[0]],
58+
[0,0,-1,jj[1]],
59+
[-1,0,0,jj[2]],
60+
[0,0,0,1]
61+
])
62+
rads = kc.inverse(p)
5763
print(">>", np.rad2deg(rads))
5864

5965

dev/test2.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/env python3
2+
3+
"""Basic usage of the pybotics package."""
4+
import numpy as np
5+
from mdh import __version__ as version
6+
from mdh.link import mdh_params, JointType, RevoluteLink
7+
from mdh.kinematic_chain import KinematicChain
8+
9+
pi = np.pi
10+
11+
print(f">> {version}")
12+
13+
# make it print better
14+
np.set_printoptions(suppress=True)
15+
16+
def kevin():
17+
mm = pi
18+
"""alpha a theta d"""
19+
dh = [
20+
{'alpha': 0, 'a': 0, 'theta': 0, 'd': 0, 'type': 1},
21+
{'alpha': pi/2, 'a': 50, 'theta': 0, 'd': 0, 'type': 1},
22+
{'alpha': 0, 'a': 65, 'theta': 0, 'd': 0, 'type': 1},
23+
{'alpha': 0, 'a': 68, 'theta': 0, 'd': 0, 'type': 1, 'fixed': True}
24+
]
25+
26+
return dh
27+
28+
def main():
29+
# l = RevoluteLink(1,2,3,4)
30+
31+
t = kevin()
32+
kc = KinematicChain.from_parameters(t)
33+
print(f">> size: {kc.size}")
34+
35+
for l in kc:
36+
print(f">> {l}")
37+
38+
t = kc.forward(np.deg2rad([0,0,0,0]))
39+
print(t)
40+
41+
t = kc.forward(np.deg2rad([0,82.62,-154.1,0]))
42+
print(t)
43+
44+
jnts = kc.inverse(t)
45+
print(">> ", np.rad2deg(jnts))
46+
47+
p = np.array([
48+
[0,1,0, 80],
49+
[0,0,-1,0],
50+
[-1,0,0,0],
51+
[0,0,0,1]
52+
])
53+
54+
# p = np.array([
55+
# [1,0,0, 80],
56+
# [0,1,0,0],
57+
# [0,0,1,0],
58+
# [0,0,0,1]
59+
# ])
60+
61+
jnts = kc.inverse(p)
62+
print(">> ", np.rad2deg(jnts))
63+
64+
if __name__ == "__main__":
65+
main()

mdh/kinematic_chain.py

Lines changed: 59 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import numpy as np # type: ignore
22
import attr
3-
from typing import Any, Optional, Sequence, Sized, Union, Iterable, Dict, List
3+
# from typing import Any, Optional, Sequence, Sized, Union, Iterable, Dict, List
44
# import scipy # type: ignore
55
import scipy.optimize # type: ignore
66
# from numpy.linalg import norm
@@ -21,12 +21,16 @@ class UnReachable(Exception):
2121
pass
2222

2323
@attr.s
24-
class KinematicChain(Sized, Iterable):
25-
_links = attr.ib(type=Sequence[Any])
24+
# class KinematicChain(Sized, Iterable):
25+
class KinematicChain:
26+
# _links = attr.ib(type=Sequence[Any])
27+
_links = attr.ib()
28+
_size = attr.ib()
2629

2730
def __len__(self):
2831
"""Enables the length function, returns number links"""
29-
return len(self._links)
32+
# return len(self._links)
33+
return self._size
3034

3135
def __iter__(self):
3236
"""Enables iteration of joints: for j in chain: print(j)"""
@@ -39,8 +43,8 @@ def __getitem__(self, key):
3943

4044
def transform(self, joints):
4145
"""Calculates the transformation and returns a 4x4 matrix"""
42-
if len(joints) != len(self._links):
43-
raise Exception("inputs don't equal number of links")
46+
if len(joints) != self.size:
47+
raise Exception(f"inputs don't equal number of links {len(joints)} != {self.size}")
4448

4549
t = np.eye(4)
4650
for l, q in zip(reversed(self._links), reversed(joints)):
@@ -63,14 +67,14 @@ def inverse(self, pos):
6367
6468
FIXME: this only works for when the foot is straight down
6569
"""
66-
j = [[],[]] # type: Sequence[List]
70+
joint_limits = [[],[]] # type: Sequence[List]
6771
for l in self:
68-
j[0].append(l.min)
69-
j[1].append(l.max)
70-
# j[0][3] = -0.00001
71-
# j[1][3] = 0.00001
72-
73-
joint_limits = np.array(j) # type: np.ndarray
72+
joint_limits[0].append(l.min)
73+
joint_limits[1].append(l.max)
74+
# # j[0][3] = -0.00001
75+
# # j[1][3] = 0.00001
76+
# joint_limits = j
77+
# joint_limits = np.array(j) # type: np.ndarray
7478
# print(joint_limits)
7579

7680
# r = R.from_matrix([[1,0,0],[0,0,-1],[0,1,0]])
@@ -79,65 +83,81 @@ def inverse(self, pos):
7983

8084
# make desired transform pose (position, oritentation)
8185
# change the -90 x-axis to something else for non-down??
82-
x = pos[0]
83-
y = pos[1]
84-
c = R.from_euler('zyx', [-90,atan2(y,x)*180/pi,90], degrees=True)
85-
ppos = np.eye(4)
86-
ppos[:3,:3] = c.as_matrix()
87-
ppos[:3, 3] = pos
86+
# x = pos[0]
87+
# y = pos[1]
88+
# c = R.from_euler('zyx', [-90,atan2(y,x)*180/pi,90], degrees=True)
89+
# ppos = np.eye(4)
90+
# ppos[:3,:3] = c.as_matrix()
91+
# ppos[:3, 3] = pos
8892

8993
start = [0]*len(self._links)
9094

9195
result = scipy.optimize.least_squares(
9296
fun=_ik_cost_function,
9397
x0=np.array(start),
9498
bounds=joint_limits,
95-
args=(ppos, self)
96-
) # type: scipy.optimize.OptimizeResult
99+
args=(pos, self)
100+
)
97101

98102
if not result.success: # pragma: no cover
99103
raise UnReachable(f"Can't reach: {pos}m")
100104
# print(">> yeah!!!")
101105
# print(">>", np.rad2deg(result.x))
102106
actual_t = self.transform(result.x)
103-
actual_pos = actual_t[:3,3]
107+
actual_pos = actual_t #actual_t[:3,3]
104108
if np.allclose(actual_pos, pos, atol=1e-3):
105109
# print(result)
106110
return result.x
107111

108112
raise UnReachable(f"Can't reach: {pos}")
109113

114+
@property
115+
def size(self):
116+
return self._size
117+
110118
@classmethod
111119
def from_parameters(cls, params):
112120
"""Builds a KinematicChain object from an input"""
113121
links = []
122+
size = 0
114123
for l in params:
115124
if not isinstance(l, dict):
116125
raise Exception(f"Invalid parameters: {l}")
117126

118-
for key in ['alpha', 'a', 'theta', 'd', 'type']:
127+
for key in ['alpha', 'a', 'theta', 'd']:
119128
if key not in l:
120129
raise Exception(f"Missing parameter: {key}")
121130

122-
ll = mdh_params(l['alpha'], l['a'], l['theta'], l['d'], l['type'])
123-
124-
if ll.type == JointType.revolute:
125-
link = RevoluteLink(a=ll.a, alpha=ll.alpha, d=ll.d, theta=ll.theta)
126-
elif ll.type == JointType.prismatic:
127-
raise NotImplementedError(f"from_parameters: {l.type}")
128-
else:
129-
raise Exception(f"Invalid parameter: {l.type}")
130-
131-
if "max_min" in l:
132-
link.min = l["max_min"][1]
133-
link.max = l["max_min"][0]
134-
else:
135-
link.min = -pi
136-
link.max = pi
131+
# ll = mdh_params(l['alpha'], l['a'], l['theta'], l['d'])
132+
# print(f">> params: {ll}")
133+
# print(l['alpha'])
134+
135+
# if ll.type == JointType.revolute:
136+
# link = RevoluteLink(a=ll.a, alpha=ll.alpha, d=ll.d, theta=ll.theta)
137+
# link = RevoluteLink(alpha=ll.alpha, a=ll.a, theta=ll.theta, d=ll.d)
138+
link = RevoluteLink(l['alpha'], l['a'], l['theta'], l['d'])
139+
# elif ll.type == JointType.prismatic:
140+
# raise NotImplementedError(f"from_parameters: {l.type}")
141+
# else:
142+
# raise Exception(f"Invalid parameter: {l.type}")
143+
144+
# if "max_min" in l:
145+
# link.min = l["max_min"][1]
146+
# link.max = l["max_min"][0]
147+
# else:
148+
link.min = -pi
149+
link.max = pi
137150

138151
links.append(link)
139152

140-
ret = cls(links)
153+
# if 'fixed' in l:
154+
# if l['fixed'] is not True:
155+
# size += 1
156+
# else:
157+
# size += 1
158+
size += 1
159+
160+
ret = cls(links, size)
141161

142162
return ret
143163

mdh/link.py

Lines changed: 28 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,51 @@
33
from enum import IntFlag
44
import numpy as np # type: ignore
55
np.set_printoptions(suppress=True)
6+
from colorama import Fore
67

78
JointType = IntFlag('JointType', 'revolute prismatic revolute_theda revolute_alpha')
8-
mdh_params = namedtuple("mdh_params", "alpha a theta d type")
9+
mdh_params = namedtuple("mdh_params", "alpha a theta d ")
910

1011
from math import pi
11-
rad2deg = pi/180
12-
13-
# @attr.s
14-
# class Link:
15-
# """
16-
# why? what is the value of this?
17-
# prismatic/revolute have parameters that never chance ... need to freeze them!
18-
# """
19-
# # alpha = attr.ib(type=float)
20-
# # a = attr.ib(type=float)
21-
# # theta = attr.ib(type=float)
22-
# # d = attr.ib(type=float)
12+
rad2deg = 180/pi
13+
deg2rad = pi/180
2314

2415
@attr.s(slots=True)
2516
class RevoluteLink:
2617
"""
2718
RevoluteLink about theta. All other parameters (alpha, a, d) are fixed and
2819
cannot be changed once the link is created.
2920
"""
30-
_alpha = attr.ib(type=float)
31-
_a = attr.ib(type=float)
32-
theta = attr.ib(type=float)
33-
_d = attr.ib(type=float)
34-
min = attr.ib(init=False, default=-np.pi/2, type=float)
35-
max = attr.ib(init=False, default=np.pi/2, type=float)
21+
_alpha = attr.ib()
22+
_a = attr.ib()
23+
theta = attr.ib()
24+
_d = attr.ib()
25+
min = attr.ib(default=-np.pi/2)
26+
max = attr.ib(default=np.pi/2)
27+
28+
@max.validator
29+
def max_check(self, attribute, value):
30+
if self.min > value:
31+
raise Exception()
3632

3733
@property
38-
def alpha(self) -> float:
34+
def alpha(self):
3935
return self._alpha
4036

4137
@property
42-
def a(self) -> float:
38+
def a(self):
4339
return self._a
4440

4541
@property
46-
def d(self) -> float:
42+
def d(self):
4743
return self._d
48-
49-
@property
50-
def type(self):
51-
return JointType.revolute
44+
#
45+
# @property
46+
# def type(self):
47+
# return JointType.revolute
5248

5349
"""Some of these params are immutable, how do I do that?"""
54-
def transform(self, angle: float):
50+
def transform(self, angle):
5551
"""could move this to link"""
5652

5753
crx = np.cos(self._alpha)
@@ -76,16 +72,8 @@ def transform(self, angle: float):
7672
return transform
7773

7874
def __str__(self):
79-
aa = self._alpha*rad2deg
80-
t = self.theta*rad2deg
81-
s = f"Revolute: alpha: {aa:4.1f}deg a: {self.a:4.1f}m theta: {t:4.1}deg d: {self.d:4.1f}"
82-
return s
83-
84-
# @attr.s
85-
# class Prismatic:
86-
# min = attr.ib(type=float)
87-
# max = attr.ib(type=float)
88-
#
89-
# @property
90-
# def type(self):
91-
# return JointType.revolute
75+
saa = f"{Fore.CYAN}{self._alpha*rad2deg:4.1f}{Fore.RESET}"
76+
st = f"{Fore.CYAN}{self.theta*rad2deg:4.1f}{Fore.RESET}"
77+
sa = f"{Fore.YELLOW}{self._a:4.1f}{Fore.RESET}"
78+
sd = f"{Fore.YELLOW}{self._d:4.1f}{Fore.RESET}"
79+
return f"Rev[deg]: alpha: {saa} a: {sa} theta: {st} d: {sd}"

0 commit comments

Comments
 (0)