Skip to content

Commit 76a0595

Browse files
committed
kinematyka_odwrotna.ipynb
1 parent b765392 commit 76a0595

File tree

1 file changed

+306
-0
lines changed

1 file changed

+306
-0
lines changed

notebooks/kinematyka_odwrotna.ipynb

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"metadata": {},
7+
"outputs": [],
8+
"source": [
9+
"import numpy as np\n",
10+
"import roboticstoolbox as rtb\n",
11+
"from spatialmath import *\n",
12+
"from math import pi\n",
13+
"import matplotlib.pyplot as plt\n",
14+
"from matplotlib import cm\n",
15+
"np.set_printoptions(linewidth=100, formatter={'float': lambda x: f\"{x:8.4g}\" if abs(x) > 1e-10 else f\"{0:8.4g}\"})\n",
16+
"\n",
17+
"%matplotlib notebook"
18+
]
19+
},
20+
{
21+
"cell_type": "markdown",
22+
"metadata": {},
23+
"source": [
24+
"Rozwiązanie zagadnienia kinematyki odwrotnej, podobnie jak zagadnienia kinematyki prostej, trzeba rozpocząć od stworzenia modelu manipulatora."
25+
]
26+
},
27+
{
28+
"cell_type": "code",
29+
"execution_count": null,
30+
"metadata": {},
31+
"outputs": [],
32+
"source": [
33+
"L1 = rtb.DHLink(d=1.0, alpha=pi/2, theta=0.0, a=0.5)\n",
34+
"L2 = rtb.DHLink(theta=0.0, a=0.7)\n",
35+
"robot = rtb.DHRobot([L1, L2])"
36+
]
37+
},
38+
{
39+
"cell_type": "markdown",
40+
"metadata": {},
41+
"source": [
42+
"W następnym kroku konieczne jest określenie położenia i orientacji końcówki manipulatora, dla której zagadnienie ma zostać rozwiązane. Pozycję tą należny przedstawić w postaci macierzy homogenicznej. Jednym z najprostszych sposobów jest określenie macierzy translacji i rotacji. Macierz translacji tworzy się wykorzystując polecenie **SE3** jak w przykładzie:\n",
43+
"```py\n",
44+
"trans = SE3(0.1, 0.2, 0.3)\n",
45+
"```\n",
46+
"Kolejne argumenty odpowiadają kolejno współrzędnym x, y i z zadanego punktu. "
47+
]
48+
},
49+
{
50+
"cell_type": "code",
51+
"execution_count": null,
52+
"metadata": {},
53+
"outputs": [],
54+
"source": [
55+
"trans = SE3(0.5, 0.0, 1.7)\n",
56+
"trans"
57+
]
58+
},
59+
{
60+
"cell_type": "markdown",
61+
"metadata": {},
62+
"source": [
63+
"Powstaje w ten sposób macierz jednorodna, której część związana z rotacją jest macierzą jednostkową.\n",
64+
"Aby stworzyć odpowiednią macierz rotacji należy skorzystać z polecenia **SE3.OA**.\n",
65+
"```py\n",
66+
"y = [0,0,1]\n",
67+
"z = [1,0,0]\n",
68+
"rot = SE3.OA(y, z)\n",
69+
"```\n",
70+
"Parametry y i z są to:\n",
71+
"* y - wektor równoległy do osi y narzędzia\n",
72+
"* z - wektor równoległy do osi z narzędzia"
73+
]
74+
},
75+
{
76+
"cell_type": "code",
77+
"execution_count": null,
78+
"metadata": {},
79+
"outputs": [],
80+
"source": [
81+
"y = [0,0,1]\n",
82+
"z = [1,0,0]\n",
83+
"rot = SE3.OA(y, z)\n",
84+
"rot"
85+
]
86+
},
87+
{
88+
"cell_type": "markdown",
89+
"metadata": {},
90+
"source": [
91+
"Warto zwrócić uwagę, że wektory y i z nie mogą być zerowe lub rónoległe. Nie ma jednak konieczności normalizowania wektorów oraz zapewniania ich prostopadłości. W przypadku pary wektorów nieprostopadłych w macierzy wynikowej zostanie zachowany wektor z a wektor y zostanie do niego dopasowany. Takie działanie wynika z tego, że wektor z określa tzw. kierunek podejścia czyli prościej pozycję osi głównej narzędzia, wektor y odpowiada zaś za obrót narzędzia wokół tej osi."
92+
]
93+
},
94+
{
95+
"cell_type": "code",
96+
"execution_count": null,
97+
"metadata": {},
98+
"outputs": [],
99+
"source": [
100+
"y = [1,0,0.5]\n",
101+
"z = [1,0,0]\n",
102+
"rot = SE3.OA(y, z)\n",
103+
"rot"
104+
]
105+
},
106+
{
107+
"cell_type": "markdown",
108+
"metadata": {},
109+
"source": [
110+
"Mnożąc otrzymane w ten sposób macierze translacji i rotacji można w łatwy sposób utworzyć pożądaną macierz jednorodną."
111+
]
112+
},
113+
{
114+
"cell_type": "code",
115+
"execution_count": null,
116+
"metadata": {},
117+
"outputs": [],
118+
"source": [
119+
"T = trans * rot\n",
120+
"T"
121+
]
122+
},
123+
{
124+
"cell_type": "markdown",
125+
"metadata": {},
126+
"source": [
127+
"Rozwiązanie rozwiązania zagadnienia kinematyki odwrotnej można otrzymać wywołując na obiekcie robota metodę **ikine_LM** i podając jako argument macierz jednorodną.\n",
128+
"```py\n",
129+
"sol = robot.ikine_LM(T)\n",
130+
"```\n",
131+
"W zwracanym obiekcie *sol* zawarte są informacje o rozwiązaniu problemu, w tym współrzędne złączowe i informacja o tym czy udało się osiągnąć zadaną pozycję."
132+
]
133+
},
134+
{
135+
"cell_type": "code",
136+
"execution_count": null,
137+
"metadata": {},
138+
"outputs": [],
139+
"source": [
140+
"sol = robot.ikine_LM(T)\n",
141+
"sol"
142+
]
143+
},
144+
{
145+
"cell_type": "markdown",
146+
"metadata": {},
147+
"source": [
148+
"W przykładzie powyżej widać, że wyliczony wektor współrzędnych złączowych to \\[1.458, -0.5544\\]. Jednak parametr success=False oznacza, że zadana pozycja nie została osiągnięta."
149+
]
150+
},
151+
{
152+
"cell_type": "code",
153+
"execution_count": null,
154+
"metadata": {},
155+
"outputs": [],
156+
"source": [
157+
"print(sol.success)\n",
158+
"print(sol.q)"
159+
]
160+
},
161+
{
162+
"cell_type": "markdown",
163+
"metadata": {},
164+
"source": [
165+
"W tym przypadku problem wynika z bardzo prostej struktury manipulatora, która daje bardzo małe możliwości ruchu. W niektórych przypadkach, takich jak ten, zachowanie wszystkich ograniczeń odnośnie pozycji końcowej może być niemożliwe lub niepotrzebne. Narzędzie przewiduje takie sytuacje i daje możliwość określenie w metodzie **ikine_LM** maski odpowiadającej za to, które elementy zadanej pozycji muszą zostać dokładnie osiągnięte. Maska powinna być sześcioelementową tablicą zer i jedynek, w której kolejne elementy oznaczają konieczność dokładnego odwzorowania kolejno: pozycji x, y, i z oraz obrotów wokół osi x, y i z.\n",
166+
"```py\n",
167+
"mask = np.array([0, 1, 1, 0, 0, 0]) # dokładne odwzorowanie pozycjo w osi y i z\n",
168+
"sol = robot.ikine_LM(T, mask=mask)\n",
169+
"```\n",
170+
"Warto pamiętać, że ilość wartości 1 w masce nie może większa niż ilość stopni swobody manipulatora."
171+
]
172+
},
173+
{
174+
"cell_type": "code",
175+
"execution_count": null,
176+
"metadata": {},
177+
"outputs": [],
178+
"source": [
179+
"mask = np.array([0, 1, 1, 0, 0, 0])\n",
180+
"sol = robot.ikine_LM(T, mask=mask)\n",
181+
"sol"
182+
]
183+
},
184+
{
185+
"cell_type": "code",
186+
"execution_count": null,
187+
"metadata": {},
188+
"outputs": [],
189+
"source": [
190+
"print(sol.success)\n",
191+
"print(sol.q)"
192+
]
193+
},
194+
{
195+
"cell_type": "markdown",
196+
"metadata": {},
197+
"source": [
198+
"Często podanie tylko zadanej pozycji może nie być wystarczające do znalezienia rozwiązania, mimo że pozycja jest osiągalna. Jeżeli jest to możliwe warto również do metody **ikine_LM** podać wartość początkową zmiennych złączowych.\n",
199+
"```py\n",
200+
"mask = np.array([0, 1, 1, 0, 0, 0])\n",
201+
"q0 = np.array([0.0, 1.0])\n",
202+
"sol = robot.ikine_LM(T, q0=q0, mask=mask)\n",
203+
"\n",
204+
"```"
205+
]
206+
},
207+
{
208+
"cell_type": "code",
209+
"execution_count": null,
210+
"metadata": {},
211+
"outputs": [],
212+
"source": [
213+
"mask = np.array([0, 1, 1, 0, 0, 0])\n",
214+
"q0 = np.array([0.0, 1.0])\n",
215+
"sol = robot.ikine_LM(T, q0=q0, mask=mask)\n",
216+
"print(sol.success)\n",
217+
"print(sol.q)"
218+
]
219+
},
220+
{
221+
"cell_type": "markdown",
222+
"metadata": {},
223+
"source": [
224+
"Aby zapisać wynik do pliku należy skorzystać z następującego kodu:\n",
225+
"```py\n",
226+
"with open(\"wynik.txt\", \"w\") as plik: # otworzenie pliku \"wynik.txt\" w trybie zapisu (\"w\")\n",
227+
" plik.write(\"Tu wpisz tekst\") # wpisanie tekstu do pliku\n",
228+
"```\n",
229+
"**UWAGA: Przy takim zapisie wcześniejsza zawartość pliku zostanie utracona i zastąpiona nową.**"
230+
]
231+
},
232+
{
233+
"cell_type": "code",
234+
"execution_count": null,
235+
"metadata": {},
236+
"outputs": [],
237+
"source": [
238+
"with open(\"wynik.txt\", \"w\") as plik:\n",
239+
" plik.write(\"Tu wpisz tekst\")"
240+
]
241+
}
242+
],
243+
"metadata": {
244+
"kernelspec": {
245+
"display_name": "Python 3",
246+
"language": "python",
247+
"name": "python3"
248+
},
249+
"language_info": {
250+
"codemirror_mode": {
251+
"name": "ipython",
252+
"version": 3
253+
},
254+
"file_extension": ".py",
255+
"mimetype": "text/x-python",
256+
"name": "python",
257+
"nbconvert_exporter": "python",
258+
"pygments_lexer": "ipython3",
259+
"version": "3.7.8"
260+
},
261+
"toc": {
262+
"base_numbering": 1,
263+
"nav_menu": {},
264+
"number_sections": true,
265+
"sideBar": true,
266+
"skip_h1_title": false,
267+
"title_cell": "Table of Contents",
268+
"title_sidebar": "Contents",
269+
"toc_cell": false,
270+
"toc_position": {},
271+
"toc_section_display": true,
272+
"toc_window_display": false
273+
},
274+
"varInspector": {
275+
"cols": {
276+
"lenName": 16,
277+
"lenType": 16,
278+
"lenVar": 40
279+
},
280+
"kernels_config": {
281+
"python": {
282+
"delete_cmd_postfix": "",
283+
"delete_cmd_prefix": "del ",
284+
"library": "var_list.py",
285+
"varRefreshCmd": "print(var_dic_list())"
286+
},
287+
"r": {
288+
"delete_cmd_postfix": ") ",
289+
"delete_cmd_prefix": "rm(",
290+
"library": "var_list.r",
291+
"varRefreshCmd": "cat(var_dic_list()) "
292+
}
293+
},
294+
"types_to_exclude": [
295+
"module",
296+
"function",
297+
"builtin_function_or_method",
298+
"instance",
299+
"_Feature"
300+
],
301+
"window_display": false
302+
}
303+
},
304+
"nbformat": 4,
305+
"nbformat_minor": 4
306+
}

0 commit comments

Comments
 (0)