├── README.md
├── LICENSE
├── .gitignore
└── servo_mix_matrix.ipynb
/README.md:
--------------------------------------------------------------------------------
1 | # servo_mix_matrix
2 | Computes multicopter servo mixing matrix from the rotors geometry
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2017, Julien Lecoeur
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 |
49 | # Translations
50 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 |
57 | # Flask stuff:
58 | instance/
59 | .webassets-cache
60 |
61 | # Scrapy stuff:
62 | .scrapy
63 |
64 | # Sphinx documentation
65 | docs/_build/
66 |
67 | # PyBuilder
68 | target/
69 |
70 | # Jupyter Notebook
71 | .ipynb_checkpoints
72 |
73 | # pyenv
74 | .python-version
75 |
76 | # celery beat schedule file
77 | celerybeat-schedule
78 |
79 | # SageMath parsed files
80 | *.sage.py
81 |
82 | # dotenv
83 | .env
84 |
85 | # virtualenv
86 | .venv
87 | venv/
88 | ENV/
89 |
90 | # Spyder project settings
91 | .spyderproject
92 | .spyproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # mkdocs documentation
98 | /site
99 |
100 | # mypy
101 | .mypy_cache/
102 |
--------------------------------------------------------------------------------
/servo_mix_matrix.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Determining matrix for servo mix from position and orientation of rotors\n",
8 | "##### Julien Lecoeur 19/12/2016\n",
9 | "\n",
10 | "The goal is to determine the servo-mix matrix $B$, used to compute motor commands from 3D thrust and 3D torque commands:\n",
11 | "$$\n",
12 | "\\vec{u} = B \\cdot \\begin{bmatrix} \\vec{m} \\\\ \\vec{t} \\end{bmatrix}\n",
13 | "$$\n",
14 | "\n",
15 | "Where \n",
16 | "- $\\vec{t}$ is the $(3 \\times 1)$ thrust command vector\n",
17 | "- $\\vec{m}$ is the $(3 \\times 1)$ torque command vector\n",
18 | "- $\\vec{u}$ is the $(n \\times 1)$ motor command vector\n",
19 | "\n",
20 | "\n",
21 | "> Reference for simpler case (motors on 2D plane, all pointing vertically) from paparazzi : https://wiki.paparazziuav.org/wiki/RotorcraftMixing"
22 | ]
23 | },
24 | {
25 | "cell_type": "markdown",
26 | "metadata": {},
27 | "source": [
28 | "## Thrust generated by rotor\n",
29 | "$$\\vec{t}_i = k_t . \\rho . D^4 . \\omega_i^2 .\\vec{v}_i \\\\\n",
30 | " \\vec{t}_i \\approx C_t . u_i . \\vec{v}_i$$\n",
31 | " \n",
32 | "Where\n",
33 | "- $\\vec{t}_i$ is the thrust\n",
34 | "- $\\vec{v}_i$ is the main axis of the rotor (unit vector)\n",
35 | "- $k_t$ is the thrust coeffient of the propeller\n",
36 | "- $C_t$ is the approximated thrust coeffient of the motor/propeller unit\n",
37 | "- $\\omega_i$ is the rotation speed\n",
38 | "- $\\rho$ is the fluid density\n",
39 | "- $D$ is the diameter of the propeller\n",
40 | "- $u_i$ is the motor command"
41 | ]
42 | },
43 | {
44 | "cell_type": "markdown",
45 | "metadata": {},
46 | "source": [
47 | "## Thrust generated by a set of motors\n",
48 | "\n",
49 | "Can be computed using a matrix $A_t$ defined as:\n",
50 | "$$\n",
51 | "\\vec{t} = A_t \\cdot \\vec{u}\n",
52 | "$$\n",
53 | "Where \n",
54 | "- $\\vec{t}$ is the $(3 \\times 1)$ thrust vector\n",
55 | "$$\n",
56 | "\\vec{t} = \\begin{bmatrix} t_x \\\\ t_y \\\\ t_z \\end{bmatrix}\n",
57 | "$$\n",
58 | "- $A_t$ is a $(3 \\times n)$ matrix with the thrust generated by the i-th rotor on the i-th column:\n",
59 | "$$\n",
60 | "A_t = \\begin{bmatrix}\n",
61 | " & & & & \\\\\n",
62 | " \\vec{t}_0 & \\dots & \\vec{t}_i & \\dots & \\vec{t}_{n-1} \\\\\n",
63 | " & & & & \\\\\n",
64 | " \\end{bmatrix}\n",
65 | "$$\n",
66 | "- $\\vec{u}$ is the $(n \\times 1)$ command vector\n",
67 | "$$\n",
68 | "\\vec{u} = \\begin{bmatrix} u_0 \\\\ \\vdots \\\\ u_i \\\\ \\vdots \\\\ u_{n-1} \\end{bmatrix}\n",
69 | "$$"
70 | ]
71 | },
72 | {
73 | "cell_type": "markdown",
74 | "metadata": {},
75 | "source": [
76 | "## Torque generated by rotor\n",
77 | "$$\n",
78 | "\\vec{m}_i = (\\vec{p}_i - \\vec{p}_{cg}) \\times (k_t . \\rho . D^4 . \\omega_i^2 .\\vec{v}_i) - d_i . k_m . \\rho . D^5 . \\omega^2_i . \\vec{v}_i \\\\\n",
79 | "$$\n",
80 | "$$\n",
81 | "\\vec{m}_i \\approx \\left( C_t . (\\vec{p}_i - \\vec{p}_{cg}) \\times \\vec{v}_i \\right) . u_i \n",
82 | " - \\left( d_i . C_m . D . \\vec{v}_i \\right) . u_i\n",
83 | "$$\n",
84 | "$$\n",
85 | "\\vec{m}_i \\approx \\left( C_t . (\\vec{p}_i - \\vec{p}_{cg}) \\times \\vec{v}_i \\right) . u_i \n",
86 | " - \\left( d_i . \\frac{C_t}{10} . D . \\vec{v}_i \\right) . u_i\n",
87 | "$$\n",
88 | "\n",
89 | "Where\n",
90 | "- $\\vec{m}_i$ it the torque\n",
91 | "- $\\vec{v}_i$ is the main axis of the rotor\n",
92 | "- $\\vec{p}_i$ is the position of the center of the rotor\n",
93 | "- $\\vec{p}_{cg}$ is the position of the center of mass\n",
94 | "- $k_t$ is the thrust coeffient of the propeller\n",
95 | "- $k_m$ is the moment coeffient of the propeller (usually $k_m \\approx \\frac{k_t}{10}$)\n",
96 | "- $C_t$ is the approximated thrust coeffient of the motor/propeller unit\n",
97 | "- $C_m$ is the approximated moment coeffient of the motor/propeller unit ($C_m \\approx D.\\frac{C_t}{10}$)\n",
98 | "- $\\rho$ is the fluid density\n",
99 | "- $D$ is the diameter of the propeller\n",
100 | "- $d_i$ is the rotation direction (-1 for CW or +1 for CCW)\n",
101 | "- $\\omega_i$ is the rotation speed\n",
102 | "- $u_i$ is the motor command"
103 | ]
104 | },
105 | {
106 | "cell_type": "markdown",
107 | "metadata": {},
108 | "source": [
109 | "## Torque generated by a set of motors\n",
110 | "\n",
111 | "Can be computed using a matrix $A_m$ defined as:\n",
112 | "$$\n",
113 | "\\vec{m} = A_m \\cdot \\vec{u}\n",
114 | "$$\n",
115 | "Where \n",
116 | "- $\\vec{m}$ is the $(3 \\times 1)$ torque vector\n",
117 | "$$\n",
118 | "\\vec{m} = \\begin{bmatrix} m_x \\\\ m_y \\\\ m_z \\end{bmatrix}\n",
119 | "$$\n",
120 | "- $A_m$ is a $(3 \\times n)$ matrix with the torque generated by the i-th rotor on the i-th column:\n",
121 | "$$\n",
122 | "A_m = \\begin{bmatrix}\n",
123 | " & & & & \\\\\n",
124 | " \\vec{m}_0 & \\dots & \\vec{m}_i & \\dots & \\vec{m}_{n-1} \\\\\n",
125 | " & & & & \\\\\n",
126 | " \\end{bmatrix}\n",
127 | "$$\n",
128 | "- $\\vec{u}$ is the $(n \\times 1)$ command vector\n",
129 | "$$\n",
130 | "\\vec{u} = \\begin{bmatrix} u_0 \\\\ \\vdots \\\\ u_i \\\\ \\vdots \\\\ u_{n-1} \\end{bmatrix}\n",
131 | "$$"
132 | ]
133 | },
134 | {
135 | "cell_type": "markdown",
136 | "metadata": {},
137 | "source": [
138 | "## Combined torque and thrust matrix\n",
139 | "\n",
140 | "We define the $(6 \\times n)$ matrix $A$ as \n",
141 | "$$\n",
142 | "A = \\begin{bmatrix} A_m \\\\ At \\end{bmatrix}\n",
143 | "$$\n",
144 | "\n",
145 | "The matrix $A$ allows to compute the thrust and torque generated by a set of $n$ motors as a function of the throttle command of each motor:\n",
146 | "$$\n",
147 | "\\begin{bmatrix} \\vec{m} \\\\ \\vec{t} \\end{bmatrix} = A \\cdot \\vec{u}\n",
148 | "$$\n",
149 | "or\n",
150 | "$$\n",
151 | "\\begin{bmatrix} m_x \\\\ m_y \\\\ m_z \\\\ t_x \\\\ t_y \\\\ t_z \\end{bmatrix} = \n",
152 | "\\begin{bmatrix} \n",
153 | " m^0_x && \\dots && m^i_x && \\dots && m^{n-1}_x \\\\\n",
154 | " m^0_y && \\dots && m^i_y && \\dots && m^{n-1}_y \\\\\n",
155 | " m^0_z && \\dots && m^i_z && \\dots && m^{n-1}_z \\\\\n",
156 | " t^0_x && \\dots && t^i_x && \\dots && t^{n-1}_x \\\\\n",
157 | " t^0_y && \\dots && t^i_y && \\dots && t^{n-1}_y \\\\\n",
158 | " t^0_z && \\dots && t^i_z && \\dots && t^{n-1}_z \\\\\n",
159 | "\\end{bmatrix} \n",
160 | "\\cdot \\begin{bmatrix} u_0 \\\\ \\vdots \\\\ u_i \\\\ \\vdots \\\\ u_{n-1} \\end{bmatrix}\n",
161 | "$$"
162 | ]
163 | },
164 | {
165 | "cell_type": "markdown",
166 | "metadata": {},
167 | "source": [
168 | "## Servo mixing matrix\n",
169 | "\n",
170 | "In order to compute the command to apply to each motor for a desired thrust and torque, we need the $(n \\times 6)$ servo-mix matrix $B$:\n",
171 | "\n",
172 | "$$\n",
173 | "\\vec{u} = B \\cdot \\begin{bmatrix} \\vec{m} \\\\ \\vec{t} \\end{bmatrix}\n",
174 | "$$\n",
175 | "\n",
176 | "The matrix $B$ can be computed as the Moore-Penrose pseudo-inverse of matrix $A$. The singular value decomposition (SVD) of $A$ gives $A = U \\cdot \\sigma \\cdot V^T$, where $\\sigma$ is a diagonal matrix. If $A$ has a rank $r$, then the first $r$ elements of $\\sigma$ are non-nul. $B$ can be computed as\n",
177 | "$B = V \\cdot \\sigma^{+} \\cdot U^T $. Where $\\sigma^{+}$ is a diagonal matrix that contains the inverse of the non-nul terms of the diagonal of $\\sigma$.\n",
178 | "\n"
179 | ]
180 | },
181 | {
182 | "cell_type": "markdown",
183 | "metadata": {},
184 | "source": [
185 | "## Taking Mass and Inertia into account\n",
186 | "\n",
187 | "The formulas above allow to adapt the terms of the servo mixing matrix $B$ to the geometrical and aerodynamic characterisitcs of the drones. Thus it is possible to apply the correct motor commands for desired thrust and torque commands. \n",
188 | "\n",
189 | "However, in order to fully abstract the dynamics of the system, we may want to give angular and linear acceleration commands instead of torque and thrust commands. Torque and thrust are given by:\n",
190 | "$$\n",
191 | "\\vec{m} = J \\cdot \\vec{\\alpha} \\\\\n",
192 | "\\vec{t} = M \\cdot \\vec{a}\n",
193 | "$$\n",
194 | "\n",
195 | "Where\n",
196 | "- $\\vec{m}$ is the torque vector\n",
197 | "- $\\vec{t}$ is the thrust vector\n",
198 | "- $J$ is the inertia matrix\n",
199 | "- $M$ is the mass of the system\n",
200 | "- $\\vec{\\alpha}$ is the angular acceleration vector\n",
201 | "- $\\vec{a}$ is the acceleration vector\n",
202 | "\n",
203 | "Thus the motors commands can be computed from angular and acceleration commands as:\n",
204 | "$$\n",
205 | "\\vec{u} = B \\cdot H \\cdot \\begin{bmatrix} \\vec{\\alpha} \\\\ \\vec{a} \\end{bmatrix}\n",
206 | "$$\n",
207 | "\n",
208 | "Where $H$ is a concatenation of matrix of inertia $J$ and the mass of the system $M$ multiplied by the identity matrix $I_3$:\n",
209 | "$$\n",
210 | "H = \\begin{bmatrix} J & 0_3 \\\\ 0_3 & M \\cdot I_3 \\end{bmatrix}\n",
211 | "$$"
212 | ]
213 | },
214 | {
215 | "cell_type": "markdown",
216 | "metadata": {},
217 | "source": [
218 | "## Practical usage\n",
219 | "For robots where the geometry, motors and propellers are known, $B$ can be pre-computed offline (see the examples bellow using the numpy implementation of the pseudo-inverse `numpy.linalg.pinv`).\n",
220 | "\n",
221 | "Also, if the robot has planar symmetries relative to the planes $XY$, $XZ$ and $YZ$, then the matrix of inertia is diagonal and motor commands are computed as\n",
222 | "$$\n",
223 | "\\vec{u} = B \\cdot \n",
224 | "\\begin{bmatrix}\n",
225 | " J_{xx} & 0 & 0 & 0 & 0 & 0 \\\\\n",
226 | " 0 & J_{yy} & 0 & 0 & 0 & 0 \\\\\n",
227 | " 0 & 0 & J_{zz} & 0 & 0 & 0 \\\\\n",
228 | " 0 & 0 & 0 & M & 0 & 0 \\\\\n",
229 | " 0 & 0 & 0 & 0 & M & 0 \\\\\n",
230 | " 0 & 0 & 0 & 0 & 0 & M \\\\\n",
231 | "\\end{bmatrix}\n",
232 | "\\cdot \n",
233 | "\\begin{bmatrix} \\vec{\\alpha} \\\\ \\vec{a} \\end{bmatrix}\n",
234 | "$$\n"
235 | ]
236 | },
237 | {
238 | "cell_type": "markdown",
239 | "metadata": {},
240 | "source": [
241 | "---\n",
242 | "# Implementation\n",
243 | "---"
244 | ]
245 | },
246 | {
247 | "cell_type": "code",
248 | "execution_count": 1,
249 | "metadata": {
250 | "collapsed": true
251 | },
252 | "outputs": [],
253 | "source": [
254 | "import numpy as np\n",
255 | "import pandas as pd\n",
256 | "import matplotlib.pylab as plt\n",
257 | "%matplotlib inline"
258 | ]
259 | },
260 | {
261 | "cell_type": "markdown",
262 | "metadata": {},
263 | "source": [
264 | "### Torque matrix $A_m$ from geometry"
265 | ]
266 | },
267 | {
268 | "cell_type": "code",
269 | "execution_count": 2,
270 | "metadata": {
271 | "collapsed": true
272 | },
273 | "outputs": [],
274 | "source": [
275 | "def compute_torque(center, axis, dirs, Ct, Cm):\n",
276 | " #normalize rotor axis\n",
277 | " ax = axis / np.linalg.norm(axis, axis=1)[:,np.newaxis]\n",
278 | " torque = Ct * np.cross(center, ax) - Cm * ax * dirs\n",
279 | " return torque\n",
280 | "\n",
281 | "def compute_torque_matrices(geom):\n",
282 | " # Torque matrix, each column is the torque generated by one rotor\n",
283 | " Am = compute_torque(center=geom[['x', 'y', 'z']].values, \n",
284 | " axis=geom[['ax', 'ay', 'az']].values, \n",
285 | " dirs=geom[['dir']].values,\n",
286 | " Ct=geom[['ct']].values, \n",
287 | " Cm=geom[['cm']].values).T\n",
288 | " \n",
289 | " # Torque servo mix computed as pseudoinverse of At\n",
290 | " # Each column is the command to apply to the servos to get torques on roll, pitch and yaw torques\n",
291 | " Bm = np.linalg.pinv(Am)\n",
292 | "\n",
293 | " return Am, Bm"
294 | ]
295 | },
296 | {
297 | "cell_type": "markdown",
298 | "metadata": {},
299 | "source": [
300 | "\n",
301 | "### Thrust matrix $A_t$ from geometry"
302 | ]
303 | },
304 | {
305 | "cell_type": "code",
306 | "execution_count": 3,
307 | "metadata": {
308 | "collapsed": true
309 | },
310 | "outputs": [],
311 | "source": [
312 | "def compute_thrust(axis, Ct):\n",
313 | " # Normalize rotor axis\n",
314 | " ax = axis / np.linalg.norm(axis, axis=1)[:,np.newaxis]\n",
315 | " thrust = Ct * ax\n",
316 | " return thrust\n",
317 | "\n",
318 | "def compute_thrust_matrices(geom):\n",
319 | " # Thrust matrix, each column is the thrust generated by one rotor\n",
320 | " At = compute_thrust(axis=geom[['ax', 'ay', 'az']].values,\n",
321 | " Ct=geom[['ct']].values).T\n",
322 | " \n",
323 | " # Thrust servo mix computed as pseudoinverse of At\n",
324 | " # Each column is the command to apply to the servos to get thrust on x, y, and z\n",
325 | " Bt = np.linalg.pinv(At)\n",
326 | "\n",
327 | " return At, Bt"
328 | ]
329 | },
330 | {
331 | "cell_type": "markdown",
332 | "metadata": {},
333 | "source": [
334 | "### Combined torque/thrust matrices $A$ and $B$"
335 | ]
336 | },
337 | {
338 | "cell_type": "code",
339 | "execution_count": 4,
340 | "metadata": {
341 | "collapsed": true
342 | },
343 | "outputs": [],
344 | "source": [
345 | "def compute_torque_thrust_matrices(geom):\n",
346 | " # Torque matrices\n",
347 | " Am, Bm = compute_torque_matrices(geom)\n",
348 | "\n",
349 | " # Thrust matrices\n",
350 | " At, Bt = compute_thrust_matrices(geom)\n",
351 | "\n",
352 | " # Combined matrices\n",
353 | " A = np.vstack([Am, At])\n",
354 | " B = np.linalg.pinv(A)\n",
355 | " \n",
356 | " A = pd.DataFrame(A, index= ['Roll', 'Pitch', 'Yaw', 'X', 'Y', 'Z'])\n",
357 | " B = pd.DataFrame(B, columns=['Roll', 'Pitch', 'Yaw', 'X', 'Y', 'Z'])\n",
358 | " \n",
359 | " return A, B \n",
360 | "\n",
361 | "def print_matrices(A, B):\n",
362 | " print('\\nA|' + ''.join(['| ' + str(i) + ' ' for i in range(geom.shape[0])]) + '|\\n', \n",
363 | " A.round(2))\n",
364 | " print('\\nB| R | P | Y | X | Y | Z |\\n', \n",
365 | " B.round(2))\n",
366 | " \n",
367 | " print('\\nActuation effort for unit commands')\n",
368 | " print('Torque: norm ', np.linalg.norm(B[:, :3], axis=0).round(2), '/ std ', np.abs(B[:, :3]).std(axis=0).round(2))\n",
369 | " print('Thrust: norm ', np.linalg.norm(B[:, 3:], axis=0).round(2), '/ std ', np.abs(B[:, 3:]).std(axis=0).round(2))\n",
370 | " \n",
371 | "def print_actuation_effort(Bdf):\n",
372 | " B = Bdf.values\n",
373 | " print('\\nActuation effort for unit commands')\n",
374 | " print('Torque: norm ', np.linalg.norm(B[:, :3], axis=0).round(2), '/ std ', np.abs(B[:, :3]).std(axis=0).round(2))\n",
375 | " print('Thrust: norm ', np.linalg.norm(B[:, 3:], axis=0).round(2), '/ std ', np.abs(B[:, 3:]).std(axis=0).round(2))\n",
376 | " "
377 | ]
378 | },
379 | {
380 | "cell_type": "code",
381 | "execution_count": 5,
382 | "metadata": {
383 | "collapsed": true
384 | },
385 | "outputs": [],
386 | "source": [
387 | "# Plotting\n",
388 | "def plot(geom):\n",
389 | " plt.figure(figsize=[6,6])\n",
390 | " l = 0.05\n",
391 | " for i, g in geom.iterrows():\n",
392 | " color = plt.cm.rainbow(i / geom.shape[0])\n",
393 | " style='-'\n",
394 | " if g.dir == 1:\n",
395 | " marker='o'\n",
396 | " else:\n",
397 | " marker='s'\n",
398 | " \n",
399 | " # top view\n",
400 | " plt.subplot(221)\n",
401 | " plt.plot([0.0, 0.1], [0.0, 0.0], '--k', alpha=0.3)\n",
402 | " plt.plot([0.0, 0.0], [0.0, -0.1], '--k', alpha=0.1)\n",
403 | " plt.plot([0.0, g.x], [0.0, -g.y], '-k', alpha=0.5)\n",
404 | " plt.plot([g.x, g.x + l*g.ax], [-g.y,-(g.y + l*g.ay)], \n",
405 | " linestyle=style, marker=marker, color=color, markevery=2, linewidth=4)\n",
406 | " plt.xlabel('x')\n",
407 | " plt.ylabel('y')\n",
408 | " plt.xlim([-0.2, 0.2])\n",
409 | " plt.ylim([-0.2, 0.2])\n",
410 | " plt.xticks([])\n",
411 | " plt.yticks([])\n",
412 | " \n",
413 | " # side view\n",
414 | " plt.subplot(222)\n",
415 | " plt.plot([0.0, 0.1], [0.0, 0.0], '--k', alpha=0.3)\n",
416 | " plt.plot([0.0, 0.0], [0.0, -0.1], '--k', alpha=0.1)\n",
417 | " plt.plot([0.0, -g.y], [0.0, -g.z], '-k', alpha=0.5)\n",
418 | " plt.plot([-g.y,-(g.y + l*g.ay)], [-g.z,-(g.z + l*g.az)], \n",
419 | " linestyle=style, marker=marker, color=color, markevery=2, linewidth=4)\n",
420 | " plt.xlabel('y')\n",
421 | " plt.ylabel('z')\n",
422 | " plt.xlim([-0.2, 0.2])\n",
423 | " plt.ylim([-0.2, 0.2])\n",
424 | " plt.xticks([])\n",
425 | " plt.yticks([])\n",
426 | " \n",
427 | " # front view\n",
428 | " plt.subplot(223)\n",
429 | " plt.plot([0.0, 0.1], [0.0, 0.0], '--k', alpha=0.3)\n",
430 | " plt.plot([0.0, 0.0], [0.0, -0.1], '--k', alpha=0.1)\n",
431 | " plt.plot([0.0, g.x], [0.0, -g.z], '-k', alpha=0.5)\n",
432 | " plt.plot([g.x, g.x + l*g.ax], [-g.z, -(g.z + l*g.az)], \n",
433 | " linestyle=style, marker=marker, color=color, markevery=2, linewidth=4)\n",
434 | " plt.xlabel('x')\n",
435 | " plt.ylabel('z')\n",
436 | " plt.xlim([-0.2, 0.2])\n",
437 | " plt.ylim([-0.2, 0.2])\n",
438 | " plt.xticks([])\n",
439 | " plt.yticks([])\n",
440 | " \n",
441 | " # perspective view\n",
442 | " view = np.array([-1.0, -0.3, 0.5])\n",
443 | " ax_x = np.cross(np.array([0, 0, 1]), view)\n",
444 | " ax_x = ax_x / np.linalg.norm(ax_x)\n",
445 | " ax_y = np.cross(view, ax_x)\n",
446 | " ax_y = ax_y / np.linalg.norm(ax_y)\n",
447 | " pos = [np.dot(np.array([g.x, -g.y, -g.z]), ax_x),\n",
448 | " np.dot(np.array([g.x, -g.y, -g.z]), ax_y)]\n",
449 | " axis = [np.dot(np.array([g.ax, -g.ay, -g.az]), ax_x),\n",
450 | " np.dot(np.array([g.ax, -g.ay, -g.az]), ax_y)] \n",
451 | " plt.subplot(224)\n",
452 | " plt.plot([0.0, np.dot([0.1, 0, 0], ax_x)], [0.0, np.dot([0.1, 0, 0], ax_y)], '--k', alpha=0.3)\n",
453 | " plt.plot([0.0, np.dot([0, -0.1, 0], ax_x)], [0.0, np.dot([0, -0.1, 0], ax_y)], '--k', alpha=0.1)\n",
454 | " plt.plot([0.0, np.dot([0, 0, -0.1], ax_x)], [0.0, np.dot([0, 0, -0.1], ax_y)], '--k', alpha=0.1)\n",
455 | " plt.plot([0.0, pos[0]], [0.0, pos[1]], '-k', alpha=0.5)\n",
456 | " plt.plot([pos[0], pos[0] + l*axis[0]], [pos[1], pos[1] + l*axis[1]], \n",
457 | " linestyle=style, marker=marker, color=color, markevery=2, linewidth=4)\n",
458 | " plt.xlabel('')\n",
459 | " plt.ylabel('')\n",
460 | " plt.xlim([-0.2, 0.2])\n",
461 | " plt.ylim([-0.2, 0.2])\n",
462 | " plt.xticks([])\n",
463 | " plt.yticks([])\n",
464 | " \n",
465 | " plt.tight_layout()"
466 | ]
467 | },
468 | {
469 | "cell_type": "markdown",
470 | "metadata": {},
471 | "source": [
472 | "---\n",
473 | "# Examples\n",
474 | "---"
475 | ]
476 | },
477 | {
478 | "cell_type": "markdown",
479 | "metadata": {},
480 | "source": [
481 | "## Example for quadrotor"
482 | ]
483 | },
484 | {
485 | "cell_type": "code",
486 | "execution_count": 6,
487 | "metadata": {},
488 | "outputs": [
489 | {
490 | "name": "stdout",
491 | "output_type": "stream",
492 | "text": [
493 | "\n",
494 | "Actuation effort for unit commands\n",
495 | "Torque: norm [ 4.35 4.35 33.33] / std [ 0. 0. 0.]\n",
496 | "Thrust: norm [ 0. 0. 0.5] / std [ 0. 0. 0.]\n",
497 | "A\n",
498 | " 0 1 2 3\n",
499 | "Roll 0.12 0.12 -0.12 -0.12\n",
500 | "Pitch -0.12 0.12 0.12 -0.12\n",
501 | "Yaw 0.02 -0.02 0.02 -0.02\n",
502 | "X 0.00 0.00 0.00 0.00\n",
503 | "Y 0.00 0.00 0.00 0.00\n",
504 | "Z -1.00 -1.00 -1.00 -1.00\n",
505 | "\n",
506 | "Mix:\n"
507 | ]
508 | },
509 | {
510 | "data": {
511 | "text/html": [
512 | "
\n",
513 | "\n",
526 | "
\n",
527 | " \n",
528 | " \n",
529 | " | \n",
530 | " Roll | \n",
531 | " Pitch | \n",
532 | " Yaw | \n",
533 | " X | \n",
534 | " Y | \n",
535 | " Z | \n",
536 | "
\n",
537 | " \n",
538 | " \n",
539 | " \n",
540 | " | 0 | \n",
541 | " 2.17 | \n",
542 | " -2.17 | \n",
543 | " 16.67 | \n",
544 | " 0.0 | \n",
545 | " 0.0 | \n",
546 | " -0.25 | \n",
547 | "
\n",
548 | " \n",
549 | " | 1 | \n",
550 | " 2.17 | \n",
551 | " 2.17 | \n",
552 | " -16.67 | \n",
553 | " 0.0 | \n",
554 | " 0.0 | \n",
555 | " -0.25 | \n",
556 | "
\n",
557 | " \n",
558 | " | 2 | \n",
559 | " -2.17 | \n",
560 | " 2.17 | \n",
561 | " 16.67 | \n",
562 | " 0.0 | \n",
563 | " 0.0 | \n",
564 | " -0.25 | \n",
565 | "
\n",
566 | " \n",
567 | " | 3 | \n",
568 | " -2.17 | \n",
569 | " -2.17 | \n",
570 | " -16.67 | \n",
571 | " 0.0 | \n",
572 | " 0.0 | \n",
573 | " -0.25 | \n",
574 | "
\n",
575 | " \n",
576 | "
\n",
577 | "
"
578 | ],
579 | "text/plain": [
580 | " Roll Pitch Yaw X Y Z\n",
581 | "0 2.17 -2.17 16.67 0.0 0.0 -0.25\n",
582 | "1 2.17 2.17 -16.67 0.0 0.0 -0.25\n",
583 | "2 -2.17 2.17 16.67 0.0 0.0 -0.25\n",
584 | "3 -2.17 -2.17 -16.67 0.0 0.0 -0.25"
585 | ]
586 | },
587 | "execution_count": 6,
588 | "metadata": {},
589 | "output_type": "execute_result"
590 | },
591 | {
592 | "data": {
593 | "image/png": "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\n",
594 | "text/plain": [
595 | ""
596 | ]
597 | },
598 | "metadata": {},
599 | "output_type": "display_data"
600 | }
601 | ],
602 | "source": [
603 | "# Geometry\n",
604 | "width = 0.23\n",
605 | "length = 0.23\n",
606 | "geom = pd.DataFrame({ 'x':[-0.5*width, 0.5*width, 0.5*width, -0.5*width ],\n",
607 | " 'y':[-0.5*length, -0.5*length, 0.5*length, 0.5*length],\n",
608 | " 'z':[0.0, 0.0, 0.0, 0.0 ],\n",
609 | " 'ax':[0.0, 0.0, 0.0, 0.0 ],\n",
610 | " 'ay':[0.0, 0.0, 0.0, 0.0 ],\n",
611 | " 'az':[-1.0, -1.0, -1.0, -1.0 ],\n",
612 | " 'dir':[1.0, -1.0, 1.0, -1.0 ],\n",
613 | " 'ct':[1.0, 1.0, 1.0, 1.0 ],\n",
614 | " 'cm':[0.015, 0.015, 0.015, 0.015 ]}, # prop diameter=0.15 -> cm = 0.1*0.15*ct\n",
615 | " columns = ['x', 'y', 'z', 'ax', 'ay', 'az', 'dir', 'ct', 'cm'])\n",
616 | "\n",
617 | "# Matrices\n",
618 | "A, B = compute_torque_thrust_matrices(geom)\n",
619 | "\n",
620 | "plot(geom)\n",
621 | "print_actuation_effort(B)\n",
622 | "\n",
623 | "print(\"A\")\n",
624 | "print(A.round(2))\n",
625 | "\n",
626 | "print('\\nMix:')\n",
627 | "B.round(2)"
628 | ]
629 | },
630 | {
631 | "cell_type": "markdown",
632 | "metadata": {},
633 | "source": [
634 | "# Example for quadrotor with tilted motors"
635 | ]
636 | },
637 | {
638 | "cell_type": "code",
639 | "execution_count": 7,
640 | "metadata": {},
641 | "outputs": [
642 | {
643 | "name": "stdout",
644 | "output_type": "stream",
645 | "text": [
646 | "\n",
647 | "Actuation effort for unit commands\n",
648 | "Torque: norm [ 0.65 0.48 7.02] / std [ 0.21 0. 0.13]\n",
649 | "Thrust: norm [ 1.59 1.59 0.55] / std [ 0.01 0.04 0.01]\n",
650 | "\n",
651 | "Normalized Mix (as in paparazzi):\n",
652 | " Roll Pitch Yaw X Y Z\n",
653 | "0 -255.0 253.0 -255.0 251.0 -233.0 -255.0\n",
654 | "1 255.0 253.0 255.0 251.0 233.0 -255.0\n",
655 | "2 22.0 -255.0 -237.0 -255.0 255.0 -237.0\n",
656 | "3 -22.0 -255.0 237.0 -255.0 -255.0 -237.0\n",
657 | "\n",
658 | "Normalized Mix (as in PX4):\n",
659 | " Roll Pitch Yaw X Y Z\n",
660 | "0 -1.00 0.52 -1.00 0.95 -0.91 -0.34\n",
661 | "1 1.00 0.52 1.00 0.95 0.91 -0.34\n",
662 | "2 0.09 -0.53 -0.93 -0.97 1.00 -0.32\n",
663 | "3 -0.09 -0.53 0.93 -0.97 -1.00 -0.32\n",
664 | "\n",
665 | "Mix:\n"
666 | ]
667 | },
668 | {
669 | "data": {
670 | "text/html": [
671 | "\n",
672 | "\n",
685 | "
\n",
686 | " \n",
687 | " \n",
688 | " | \n",
689 | " Roll | \n",
690 | " Pitch | \n",
691 | " Yaw | \n",
692 | " X | \n",
693 | " Y | \n",
694 | " Z | \n",
695 | "
\n",
696 | " \n",
697 | " \n",
698 | " \n",
699 | " | 0 | \n",
700 | " -0.46 | \n",
701 | " 0.24 | \n",
702 | " -3.64 | \n",
703 | " 0.79 | \n",
704 | " -0.76 | \n",
705 | " -0.28 | \n",
706 | "
\n",
707 | " \n",
708 | " | 1 | \n",
709 | " 0.46 | \n",
710 | " 0.24 | \n",
711 | " 3.64 | \n",
712 | " 0.79 | \n",
713 | " 0.76 | \n",
714 | " -0.28 | \n",
715 | "
\n",
716 | " \n",
717 | " | 2 | \n",
718 | " 0.04 | \n",
719 | " -0.24 | \n",
720 | " -3.38 | \n",
721 | " -0.80 | \n",
722 | " 0.83 | \n",
723 | " -0.26 | \n",
724 | "
\n",
725 | " \n",
726 | " | 3 | \n",
727 | " -0.04 | \n",
728 | " -0.24 | \n",
729 | " 3.38 | \n",
730 | " -0.80 | \n",
731 | " -0.83 | \n",
732 | " -0.26 | \n",
733 | "
\n",
734 | " \n",
735 | "
\n",
736 | "
"
737 | ],
738 | "text/plain": [
739 | " Roll Pitch Yaw X Y Z\n",
740 | "0 -0.46 0.24 -3.64 0.79 -0.76 -0.28\n",
741 | "1 0.46 0.24 3.64 0.79 0.76 -0.28\n",
742 | "2 0.04 -0.24 -3.38 -0.80 0.83 -0.26\n",
743 | "3 -0.04 -0.24 3.38 -0.80 -0.83 -0.26"
744 | ]
745 | },
746 | "execution_count": 7,
747 | "metadata": {},
748 | "output_type": "execute_result"
749 | },
750 | {
751 | "data": {
752 | "image/png": "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\n",
753 | "text/plain": [
754 | ""
755 | ]
756 | },
757 | "metadata": {},
758 | "output_type": "display_data"
759 | }
760 | ],
761 | "source": [
762 | "# Geometry\n",
763 | "s45 = np.sin(np.deg2rad(45))\n",
764 | "c45 = np.cos(np.deg2rad(45))\n",
765 | "s25 = np.sin(np.deg2rad(25))\n",
766 | "c25 = np.cos(np.deg2rad(25))\n",
767 | "geom = pd.DataFrame({ 'x':np.array([ 0.1, 0.1, -0.1, -0.1]),\n",
768 | " 'y':np.array([ 0.1, -0.1, -0.1, 0.1]),\n",
769 | " 'z':[0.0 for _ in range(4) ],\n",
770 | " 'ax':np.array([ 1, 1,-1,-1]) * s25 * c45,\n",
771 | " 'ay':np.array([-1, 1, 1,-1]) * s25 * c45,\n",
772 | " 'az':[-1.0, -1.0, -c25, -c25 ],\n",
773 | " 'dir':[(-1.0)**(i+1) for i in range(4) ],\n",
774 | " 'ct':[1.0 for _ in range(4) ],\n",
775 | " 'cm':[0.015 for _ in range(4) ] # prop diameter=0.15 -> cm = 0.1*0.15*ct\n",
776 | " },\n",
777 | " columns = ['x', 'y', 'z', 'ax', 'ay', 'az', 'dir', 'ct', 'cm'])\n",
778 | "\n",
779 | "# Matrices\n",
780 | "A, B = compute_torque_thrust_matrices(geom)\n",
781 | "\n",
782 | "plot(geom)\n",
783 | "print_actuation_effort(B)\n",
784 | "\n",
785 | "print('\\nNormalized Mix (as in paparazzi):')\n",
786 | "from scipy.stats import threshold\n",
787 | "B_norm = B.abs().max(axis=0)\n",
788 | "B_norm[np.abs(B_norm)<1e-3] = 1\n",
789 | "B_papa = (255 * B / B_norm).round()\n",
790 | "print(B_papa)\n",
791 | "\n",
792 | "print('\\nNormalized Mix (as in PX4):')\n",
793 | "from scipy.stats import threshold\n",
794 | "B_norm = B.abs().max(axis=0)\n",
795 | "\n",
796 | "# Same scale on roll and pitch\n",
797 | "B_norm.Roll = max(B_norm.Roll, B_norm.Pitch)\n",
798 | "B_norm.Pitch = B_norm.Roll\n",
799 | "\n",
800 | "# Same scale on x, y and z thrust\n",
801 | "B_norm.X = max(B_norm.X, B_norm.Y, B_norm.Z)\n",
802 | "B_norm.Y = B_norm.X\n",
803 | "B_norm.Z = B_norm.X\n",
804 | "\n",
805 | "B_norm[np.abs(B_norm)<1e-3] = 1\n",
806 | "B_px4 = (1.0 * B / B_norm).round(2)\n",
807 | "print(B_px4)\n",
808 | "\n",
809 | "print('\\nMix:')\n",
810 | "B.round(2)"
811 | ]
812 | },
813 | {
814 | "cell_type": "markdown",
815 | "metadata": {
816 | "collapsed": true
817 | },
818 | "source": [
819 | "# Example for hexacopter"
820 | ]
821 | },
822 | {
823 | "cell_type": "code",
824 | "execution_count": 8,
825 | "metadata": {},
826 | "outputs": [
827 | {
828 | "name": "stdout",
829 | "output_type": "stream",
830 | "text": [
831 | "\n",
832 | "Actuation effort for unit commands\n",
833 | "Torque: norm [ 3.61 3.61 27.22] / std [ 0.49 0.85 0. ]\n",
834 | "Thrust: norm [ 0. 0. 0.41] / std [ 0. 0. 0.]\n",
835 | "A\n",
836 | " 0 1 2 3 4 5\n",
837 | "Roll -0.08 -0.16 -0.08 0.08 0.16 0.08\n",
838 | "Pitch 0.14 0.00 -0.14 -0.14 -0.00 0.14\n",
839 | "Yaw -0.02 0.02 -0.02 0.02 -0.02 0.02\n",
840 | "X 0.00 0.00 0.00 0.00 0.00 0.00\n",
841 | "Y 0.00 0.00 0.00 0.00 0.00 0.00\n",
842 | "Z -1.00 -1.00 -1.00 -1.00 -1.00 -1.00\n",
843 | "\n",
844 | "Mix:\n"
845 | ]
846 | },
847 | {
848 | "data": {
849 | "text/html": [
850 | "\n",
851 | "\n",
864 | "
\n",
865 | " \n",
866 | " \n",
867 | " | \n",
868 | " Roll | \n",
869 | " Pitch | \n",
870 | " Yaw | \n",
871 | " X | \n",
872 | " Y | \n",
873 | " Z | \n",
874 | "
\n",
875 | " \n",
876 | " \n",
877 | " \n",
878 | " | 0 | \n",
879 | " -1.04 | \n",
880 | " 1.8 | \n",
881 | " -11.11 | \n",
882 | " 0.0 | \n",
883 | " 0.0 | \n",
884 | " -0.17 | \n",
885 | "
\n",
886 | " \n",
887 | " | 1 | \n",
888 | " -2.08 | \n",
889 | " -0.0 | \n",
890 | " 11.11 | \n",
891 | " 0.0 | \n",
892 | " 0.0 | \n",
893 | " -0.17 | \n",
894 | "
\n",
895 | " \n",
896 | " | 2 | \n",
897 | " -1.04 | \n",
898 | " -1.8 | \n",
899 | " -11.11 | \n",
900 | " 0.0 | \n",
901 | " 0.0 | \n",
902 | " -0.17 | \n",
903 | "
\n",
904 | " \n",
905 | " | 3 | \n",
906 | " 1.04 | \n",
907 | " -1.8 | \n",
908 | " 11.11 | \n",
909 | " 0.0 | \n",
910 | " 0.0 | \n",
911 | " -0.17 | \n",
912 | "
\n",
913 | " \n",
914 | " | 4 | \n",
915 | " 2.08 | \n",
916 | " 0.0 | \n",
917 | " -11.11 | \n",
918 | " 0.0 | \n",
919 | " 0.0 | \n",
920 | " -0.17 | \n",
921 | "
\n",
922 | " \n",
923 | " | 5 | \n",
924 | " 1.04 | \n",
925 | " 1.8 | \n",
926 | " 11.11 | \n",
927 | " 0.0 | \n",
928 | " 0.0 | \n",
929 | " -0.17 | \n",
930 | "
\n",
931 | " \n",
932 | "
\n",
933 | "
"
934 | ],
935 | "text/plain": [
936 | " Roll Pitch Yaw X Y Z\n",
937 | "0 -1.04 1.8 -11.11 0.0 0.0 -0.17\n",
938 | "1 -2.08 -0.0 11.11 0.0 0.0 -0.17\n",
939 | "2 -1.04 -1.8 -11.11 0.0 0.0 -0.17\n",
940 | "3 1.04 -1.8 11.11 0.0 0.0 -0.17\n",
941 | "4 2.08 0.0 -11.11 0.0 0.0 -0.17\n",
942 | "5 1.04 1.8 11.11 0.0 0.0 -0.17"
943 | ]
944 | },
945 | "execution_count": 8,
946 | "metadata": {},
947 | "output_type": "execute_result"
948 | },
949 | {
950 | "data": {
951 | "image/png": "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\nSUVORK5CYII=\n",
952 | "text/plain": [
953 | ""
954 | ]
955 | },
956 | "metadata": {},
957 | "output_type": "display_data"
958 | }
959 | ],
960 | "source": [
961 | "# Geometry\n",
962 | "l = 0.16\n",
963 | "thetas = np.arange(0, 2*np.pi, np.pi/3) + np.pi/6.0\n",
964 | "geom = pd.DataFrame({ 'x':[l * np.cos(theta) for theta in thetas ],\n",
965 | " 'y':[l * np.sin(theta) for theta in thetas ],\n",
966 | " 'z':[0.0 for _ in thetas ],\n",
967 | " 'ax':[0.0 for _ in thetas ],\n",
968 | " 'ay':[0.0 for _ in thetas ],\n",
969 | " 'az':[-1.0 for _ in thetas ],\n",
970 | " 'dir':[-1+2*(i%2) for i,_ in enumerate(thetas)],\n",
971 | " 'ct':[1.0 for _ in thetas ],\n",
972 | " 'cm':[0.015 for _ in thetas ], # prop diameter=0.15 -> cm = 0.1*0.15*ct\n",
973 | " },\n",
974 | " columns = ['x', 'y', 'z', 'ax', 'ay', 'az', 'dir', 'ct', 'cm'])\n",
975 | "\n",
976 | "# Matrices\n",
977 | "A, B = compute_torque_thrust_matrices(geom)\n",
978 | "\n",
979 | "plot(geom)\n",
980 | "print_actuation_effort(B)\n",
981 | "\n",
982 | "print(\"A\")\n",
983 | "print(A.round(2))\n",
984 | "\n",
985 | "print('\\nMix:')\n",
986 | "B.round(2)"
987 | ]
988 | },
989 | {
990 | "cell_type": "markdown",
991 | "metadata": {},
992 | "source": [
993 | "## Example for hexacopter in V shape (same example as paparazzi)"
994 | ]
995 | },
996 | {
997 | "cell_type": "code",
998 | "execution_count": 9,
999 | "metadata": {},
1000 | "outputs": [
1001 | {
1002 | "name": "stdout",
1003 | "output_type": "stream",
1004 | "text": [
1005 | "\n",
1006 | "Actuation effort for unit commands\n",
1007 | "Torque: norm [ 4.17 3.57 28.75] / std [ 0.71 0.84 3.79]\n",
1008 | "Thrust: norm [ 0. 0. 0.41] / std [ 0. 0. 0.]\n",
1009 | "\n",
1010 | "Normalized Mix (as in paparazzi):\n",
1011 | " Roll Pitch Yaw X Y Z\n",
1012 | "0 -67.0 -256.0 -154.0 0.0 0.0 -256.0\n",
1013 | "1 67.0 -256.0 154.0 0.0 0.0 -256.0\n",
1014 | "2 -256.0 -0.0 256.0 0.0 0.0 -256.0\n",
1015 | "3 256.0 0.0 -256.0 0.0 0.0 -256.0\n",
1016 | "4 -189.0 256.0 -115.0 0.0 0.0 -256.0\n",
1017 | "5 189.0 256.0 115.0 0.0 0.0 -256.0\n",
1018 | "\n",
1019 | "Mix:\n"
1020 | ]
1021 | },
1022 | {
1023 | "data": {
1024 | "text/html": [
1025 | "\n",
1026 | "\n",
1039 | "
\n",
1040 | " \n",
1041 | " \n",
1042 | " | \n",
1043 | " Roll | \n",
1044 | " Pitch | \n",
1045 | " Yaw | \n",
1046 | " X | \n",
1047 | " Y | \n",
1048 | " Z | \n",
1049 | "
\n",
1050 | " \n",
1051 | " \n",
1052 | " \n",
1053 | " | 0 | \n",
1054 | " -0.60 | \n",
1055 | " -1.79 | \n",
1056 | " -9.77 | \n",
1057 | " 0.0 | \n",
1058 | " 0.0 | \n",
1059 | " -0.17 | \n",
1060 | "
\n",
1061 | " \n",
1062 | " | 1 | \n",
1063 | " 0.60 | \n",
1064 | " -1.79 | \n",
1065 | " 9.77 | \n",
1066 | " 0.0 | \n",
1067 | " 0.0 | \n",
1068 | " -0.17 | \n",
1069 | "
\n",
1070 | " \n",
1071 | " | 2 | \n",
1072 | " -2.32 | \n",
1073 | " -0.00 | \n",
1074 | " 16.27 | \n",
1075 | " 0.0 | \n",
1076 | " 0.0 | \n",
1077 | " -0.17 | \n",
1078 | "
\n",
1079 | " \n",
1080 | " | 3 | \n",
1081 | " 2.32 | \n",
1082 | " 0.00 | \n",
1083 | " -16.27 | \n",
1084 | " 0.0 | \n",
1085 | " 0.0 | \n",
1086 | " -0.17 | \n",
1087 | "
\n",
1088 | " \n",
1089 | " | 4 | \n",
1090 | " -1.72 | \n",
1091 | " 1.79 | \n",
1092 | " -7.29 | \n",
1093 | " 0.0 | \n",
1094 | " 0.0 | \n",
1095 | " -0.17 | \n",
1096 | "
\n",
1097 | " \n",
1098 | " | 5 | \n",
1099 | " 1.72 | \n",
1100 | " 1.79 | \n",
1101 | " 7.29 | \n",
1102 | " 0.0 | \n",
1103 | " 0.0 | \n",
1104 | " -0.17 | \n",
1105 | "
\n",
1106 | " \n",
1107 | "
\n",
1108 | "
"
1109 | ],
1110 | "text/plain": [
1111 | " Roll Pitch Yaw X Y Z\n",
1112 | "0 -0.60 -1.79 -9.77 0.0 0.0 -0.17\n",
1113 | "1 0.60 -1.79 9.77 0.0 0.0 -0.17\n",
1114 | "2 -2.32 -0.00 16.27 0.0 0.0 -0.17\n",
1115 | "3 2.32 0.00 -16.27 0.0 0.0 -0.17\n",
1116 | "4 -1.72 1.79 -7.29 0.0 0.0 -0.17\n",
1117 | "5 1.72 1.79 7.29 0.0 0.0 -0.17"
1118 | ]
1119 | },
1120 | "execution_count": 9,
1121 | "metadata": {},
1122 | "output_type": "execute_result"
1123 | },
1124 | {
1125 | "data": {
1126 | "image/png": "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\nAfAaBJSHeWryxPr6em3YsEEnTpzQU089pQkTJnTKdgHAUwgoh7hz8sTa2lqtXbtW586d04wZMzR6\n9OhOrBwAPIOAclh7kydOmDBB4eHhd7W96upq5eTkqLi4WLNnz9bw4cPdVDkAuBcBZYjOmDyxsrJS\nq1atUmlpqebOnashQ4Z4oHIAcA8CyjD3OnlieXm5srOzdf36dc2fP19JSUkerhwAOhc3wxiqZfLE\n1157TWlpaTp27Jj+/d//Xe+//75KSkpavffq1atavny5qqurlZmZSTjhnh0/91abtmOnl7psv5PN\nlZUdet9bcW3bllqu27u6LYcbOvS+3+hPbdre0BaX7Xd0+LO7X8dD6EEZrr3JE8vKyiRJK1askGVZ\nysrK6vKz/sK9Ghur7qq9haswev3qVUnSM6Gh7a5bVXJ37V2FqzD6x03NbdNT2v9orlLdXbXf4CqM\nNv2m+e+UKe2v6wDLtu3232BZfy0px7btso5udMyYMfa+ffvutza48P333+uLL75Qfn6+li9frjNn\nziguLk6xsbE3HqOUnp6uf/mXf1FpaammTp3aZhtPPvmk3nzzTZ08eVIvvfRSm+UzZ87UP/zDP2jf\nvn169dVX2yyfN2+efv7zn2vHjh36+7//+zbLs7Ky9NOf/lSbN2/WG2+80Wb53/zN32jhwoX38uM7\nzrKs/bZtj7nHdbdL+o1t25/c1Paftm3/t9ut4+lj6djppbddVpCbcNtl/3ztmioaG9u0B9XX6/Ez\nZ9rd54F3br+s56Rv2l23s3z99de6du2agoODW7WHhoZq4MCBqq+vV2FhYZv1IiIilJSUpOrqan39\n9ddtlvfq1Uv9+/dXZWWlTp482WpZnV+U/CMGyD8iUQ3fl6q25KgkyUdNCvVr/kIwaNAgJScnq6io\nSAcPHryx7gNPj5AkxQzrr569I1ptd6ZSbvtzPl+0UT1dfdkI7y39Yt1t1+tsHT2OOnKKL05SgWVZ\nGyzLmmpxp6ej/P391bNnTwUEBKi0tFRNTU2ybZsbcL1DkqS/syzr9Zva7insTOMqnCSpxkseRlxd\nXa2mpiaP7tOW62dhNrnxykvI7XrCFVfcts/7cccelCT9EEpPScpS8wG1QdI7tm2fcvV+elCdr76+\nXvv379fu3btVWVmp+Ph4ffJJ8xfxMWPGqGfPnsrMzFRERMQdtoT7cZ89qAOSxkn6naR+khZI+rNt\n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\neu2WHpW3SEtL06xZs3T69GmtWrVKNTU1TpcEwAAElBd6JjRUS6Oj1cfPT5akPn5+Whod7RXXn24n\nNTVVL7zwgr799lutXLlSVVVVTpcEwGHedU4INzwTGurVgeRKcnKyAgICtH79eq1YsUKZmZkKCwtz\nuiwADqEHBaMMHDhQCxYsUGVlpZYvX67S0lKnSwLgEAIKxklISNCiRYtUV1en5cuX6/Lly06XBMAB\nBBSM1KdPH2VlZcmyLK1YsUIXL150uiQAHkZAwVgxMTFavHixgoKC9O677+rs2bNOlwTAgwgoGC0y\nMlJZWVkKDw/X6tWrdeLECadLAuAhBBSMFxYWpqysLPXu3Vtr167VsWPHnC4JgAcwzBxeoUePHsrM\nzNTatWtVo/d17PT7bd7j6xuihxJ+6UB1ANyBHhS8RlBQkBYsWKCgYNfLGxu5uRfoSggoeBV/f3+n\nSwDgIQQUAMBIBBQAwEgEFADASAQUvI6vb8hdtQPwTgwzh9dhKDnQPdCDAgAYiYACABiJgAIAGImA\nAgAYiYACABiJgAIAGImAAgAYiYACABiJgAIAGImAAgAYiYACABiJgAIAGImAAgAYiYACABiJgAIA\nGImAAgAYiYACABiJgAIAGImAAgAYiYACABiJgAIAGImAAgAYiYACABiJgAIAGImAAgAYiYACABjJ\nsm278zdqWVcknev0DQPOS7BtO8ZTO+NYQhfVoePILQEFAMD94hQfAMBIBBQAwEgEFADASAQUAMBI\nBBQAwEgElJeyLGusZVlHLMsKsiwrxLKsY5ZlPex0XYA3sSzrf1mW9bObXr9pWdb/dLIm/AXDzL2Y\nZVn/JClIUrCkC7Zt/2+HSwK8imVZiZI+sG17lGVZPpJOSBpn2/Y1RwuDJMnP6QJwX96QVCCpRhLf\n+oC7ZNv2WcuyrlmWNVJSrKSDhJM5CCjvFiWppyR/NfekqpwtB/BKyyQtkhQnabmzpeBmnOLzYpZl\nfSxpnaQkSX1s2/5rh0sCvI5lWQGSjqr5i94g27YbHS4JP6AH5aUsy8qU1GDb9hrLsnwl5VuW9YRt\n2zucrg3wJrZt11mW9WdJ5YSTWehBAejWfhgccUDSC7Ztn3C6HvwFw8wBdFuWZSVLOilpO+FkHnpQ\nAAAj0YMCABiJgAIAGImAAgAYiYACABiJgAIAGImAAgAYiYACABiJgAIAGImAAgAYiYACABiJgAIA\n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\n",
1127 | "text/plain": [
1128 | ""
1129 | ]
1130 | },
1131 | "metadata": {},
1132 | "output_type": "display_data"
1133 | }
1134 | ],
1135 | "source": [
1136 | "# Geometry\n",
1137 | "geom = pd.DataFrame({ 'x':np.array([-0.35, -0.35, 0.0, 0.0, 0.35, 0.35])*0.4,\n",
1138 | " 'y':np.array([ 0.17, -0.17, 0.25, -0.25, 0.33, -0.33])*0.4,\n",
1139 | " 'z':[0.0 for _ in range(6) ],\n",
1140 | " 'ax':[0.0 for _ in range(6) ],\n",
1141 | " 'ay':[0.0 for _ in range(6) ],\n",
1142 | " 'az':[-1.0 for _ in range(6) ],\n",
1143 | " 'dir':[-1+2*(((i+1)//2)%2) for i in range(6)],\n",
1144 | " 'ct':[1.0 for _ in range(6) ],\n",
1145 | " 'cm':[0.015 for _ in range(6) ] # prop diameter=0.15 -> cm = 0.1*0.15*ct\n",
1146 | " },\n",
1147 | " columns = ['x', 'y', 'z', 'ax', 'ay', 'az', 'dir', 'ct', 'cm'])\n",
1148 | "\n",
1149 | "# Matrices\n",
1150 | "A, B = compute_torque_thrust_matrices(geom)\n",
1151 | "\n",
1152 | "plot(geom)\n",
1153 | "print_actuation_effort(B)\n",
1154 | "\n",
1155 | "print('\\nNormalized Mix (as in paparazzi):')\n",
1156 | "from scipy.stats import threshold\n",
1157 | "B_norm = B.abs().max(axis=0)\n",
1158 | "B_norm[np.abs(B_norm)<1e-3] = 1\n",
1159 | "B_papa = (256 * B / B_norm).round()\n",
1160 | "print(B_papa)\n",
1161 | "\n",
1162 | "print('\\nMix:')\n",
1163 | "B.round(2)"
1164 | ]
1165 | },
1166 | {
1167 | "cell_type": "markdown",
1168 | "metadata": {},
1169 | "source": [
1170 | "## Example for hexacopter in H shape"
1171 | ]
1172 | },
1173 | {
1174 | "cell_type": "code",
1175 | "execution_count": 10,
1176 | "metadata": {},
1177 | "outputs": [
1178 | {
1179 | "name": "stdout",
1180 | "output_type": "stream",
1181 | "text": [
1182 | "\n",
1183 | "Actuation effort for unit commands\n",
1184 | "Torque: norm [ 6.56 10. 28.87] / std [ 0.89 2.36 3.93]\n",
1185 | "Thrust: norm [ 0. 0. 0.41] / std [ 0. 0. 0.]\n",
1186 | "\n",
1187 | "Normalized Mix (as in paparazzi):\n",
1188 | " Roll Pitch Yaw X Y Z\n",
1189 | "0 -255.0 -0.0 255.0 0.0 0.0 -255.0\n",
1190 | "1 255.0 0.0 -255.0 0.0 0.0 -255.0\n",
1191 | "2 127.0 255.0 127.0 0.0 0.0 -255.0\n",
1192 | "3 -128.0 -255.0 -127.0 0.0 0.0 -255.0\n",
1193 | "4 -127.0 255.0 -127.0 0.0 0.0 -255.0\n",
1194 | "5 128.0 -255.0 127.0 0.0 0.0 -255.0\n",
1195 | "\n",
1196 | "Normalized Mix (as in PX4):\n",
1197 | " Roll Pitch Yaw X Y Z\n",
1198 | "0 -0.76 -0.0 1.0 0.0 0.0 -1.0\n",
1199 | "1 0.76 0.0 -1.0 0.0 0.0 -1.0\n",
1200 | "2 0.38 1.0 0.5 0.0 0.0 -1.0\n",
1201 | "3 -0.38 -1.0 -0.5 0.0 0.0 -1.0\n",
1202 | "4 -0.38 1.0 -0.5 0.0 0.0 -1.0\n",
1203 | "5 0.38 -1.0 0.5 0.0 0.0 -1.0\n",
1204 | "\n",
1205 | "Mix:\n"
1206 | ]
1207 | },
1208 | {
1209 | "data": {
1210 | "text/html": [
1211 | "\n",
1212 | "\n",
1225 | "
\n",
1226 | " \n",
1227 | " \n",
1228 | " | \n",
1229 | " Roll | \n",
1230 | " Pitch | \n",
1231 | " Yaw | \n",
1232 | " X | \n",
1233 | " Y | \n",
1234 | " Z | \n",
1235 | "
\n",
1236 | " \n",
1237 | " \n",
1238 | " \n",
1239 | " | 0 | \n",
1240 | " -3.79 | \n",
1241 | " -0.0 | \n",
1242 | " 16.67 | \n",
1243 | " 0.0 | \n",
1244 | " 0.0 | \n",
1245 | " -0.17 | \n",
1246 | "
\n",
1247 | " \n",
1248 | " | 1 | \n",
1249 | " 3.79 | \n",
1250 | " 0.0 | \n",
1251 | " -16.67 | \n",
1252 | " 0.0 | \n",
1253 | " 0.0 | \n",
1254 | " -0.17 | \n",
1255 | "
\n",
1256 | " \n",
1257 | " | 2 | \n",
1258 | " 1.89 | \n",
1259 | " 5.0 | \n",
1260 | " 8.33 | \n",
1261 | " 0.0 | \n",
1262 | " 0.0 | \n",
1263 | " -0.17 | \n",
1264 | "
\n",
1265 | " \n",
1266 | " | 3 | \n",
1267 | " -1.89 | \n",
1268 | " -5.0 | \n",
1269 | " -8.33 | \n",
1270 | " 0.0 | \n",
1271 | " 0.0 | \n",
1272 | " -0.17 | \n",
1273 | "
\n",
1274 | " \n",
1275 | " | 4 | \n",
1276 | " -1.89 | \n",
1277 | " 5.0 | \n",
1278 | " -8.33 | \n",
1279 | " 0.0 | \n",
1280 | " 0.0 | \n",
1281 | " -0.17 | \n",
1282 | "
\n",
1283 | " \n",
1284 | " | 5 | \n",
1285 | " 1.89 | \n",
1286 | " -5.0 | \n",
1287 | " 8.33 | \n",
1288 | " 0.0 | \n",
1289 | " 0.0 | \n",
1290 | " -0.17 | \n",
1291 | "
\n",
1292 | " \n",
1293 | "
\n",
1294 | "
"
1295 | ],
1296 | "text/plain": [
1297 | " Roll Pitch Yaw X Y Z\n",
1298 | "0 -3.79 -0.0 16.67 0.0 0.0 -0.17\n",
1299 | "1 3.79 0.0 -16.67 0.0 0.0 -0.17\n",
1300 | "2 1.89 5.0 8.33 0.0 0.0 -0.17\n",
1301 | "3 -1.89 -5.0 -8.33 0.0 0.0 -0.17\n",
1302 | "4 -1.89 5.0 -8.33 0.0 0.0 -0.17\n",
1303 | "5 1.89 -5.0 8.33 0.0 0.0 -0.17"
1304 | ]
1305 | },
1306 | "execution_count": 10,
1307 | "metadata": {},
1308 | "output_type": "execute_result"
1309 | },
1310 | {
1311 | "data": {
1312 | "image/png": "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\nusx99E/dfy1FX5yLIlJd9TZQxnEcr6RHjTH3S/pPSQlf/RSULJyvlUVvKaL1yxdTW8LDVLJwvla5\nOBdgnSO7pGmLerzL6/Wqtra2M0CXIlRbW9vlQoXY2FglJSVp2rRpnVfLeTweRUdH9+rIJiQkRDfd\ndJOmTp2qXbt26dChQ/rwww+1ePFiZWVlaeHChV0e39jYqPr6ejU1Nemvf/2rysrKVFVV1XkBR+r/\n8ygiJlJhERFqrDmrZfctU3x8vEKK7lSokhShGCXrBkVouFqbpJKnCdSVehuozjcEOI7ze2PMUUn/\n6J+RBo8T06apSB2vRcWdPa+zcbEqWThfJ6ZNG9B6+3Ouvre4kgh+d2RX92VFz6nV26q/j76xy9HQ\npQsVLl2pZ4zpvFDh2muv7XKhgq9eH4qJidGdd96pzMxMbd++XZs3b1ZZWZluv/32Lh8YGx0drejo\njv1i4sSJWr6864fBrvO+IfPFRyyFRYZrxowZqqqqUnVDk1r1Fzlq10hdpwhJJ7RfZ05+rOiX2jRi\nxAjFx8drxIgRmjlzpiKuOAIbSszll2j6SmZmplNaWurz9aKrl156SZL00EMPuTzJ0GGMKXMcJ2Cv\nvw7Kfen/3C2d/Xu3xfUapufNHEkdl4snJiZ2BuhShBITExUeHu7zka62L7W3t+v9999XSUmJLly4\noMzMTGVlZfV41d6VrvZp5s+Pl86elJp0VsMVJ0mq1jE1j/xEs396Sg0NDWpqalJoaGjnRUivv/66\nPvvsM8XGxio6OloTJkzovBQ+GPV2P+Iy8yA2adIkt0cA+u5sdY+L49Ssu+++Wx6PRyNHjuzzB7wO\nxNX2pZCQEM2cOVNTpkzRnj179O6776q8vFwLFy5URkZGv2ZcuKHjNafhTXGdy74xfJJWvjCp8xRf\nS0tLly9IHDVqlJqbm3XmzBnV1NQoPDw8qAPVWwQqiN1yyy1ujwD0XVxSj0dQJi5Z119/vQsDff2+\nFBUVpWXLlmnGjBl68803VVRU1Hnary8fQit9+TpTydPS2UopblxHtC5//SkiIkIjR47svD137lzN\nnTu3T9sZDAhUEGtpaZGkIX2OGkFo4Vqp6Dmp9bKvaQ8f1rHcJb3dl0aPHq37779fH374YZ8/hPZy\n6Wu4IKI3CFQQ27hxoyReg0KQuXS1XsnLHaf74pI64nSVq/gCoS/7kjFG6enpuu6667R///5efQgt\n+odAAQi8aYtcDZIvDBs2TIsWLdL06dO/8kNo0X985TsADIDH49GaNWt0zz33yOv16pVXXtGGC0Xd\nHveMtuk6QmQQAAADhklEQVQ57XRhwuDFERQADJAxRpMmTVJaWpoOHjyot6Maenxco1oCPFlw4wgK\nAHwkPDxct956q9tjDBocQQWxqVOnuj0CMCiwL9mJQAWxofi+CMAf2JfsxCm+INbQ0NDl3eYA+od9\nyU4EKoht2rRJmzZtcnsMIOj5el+KVs9v+L3acvSMU3wA4GNParHbIwwKHEEBAKxEoAAAViJQAAAr\n8RpUEMvIyHB7BGBQYF+yE4EKYkPhC8uAQGBfshOn+ILYmTNndObMGbfHAIIe+5KdCFQQKygoUEFB\ngdtjAEGPfclOBAoAYCUCBQCwEoECAFiJQAEArMRl5kFszpw5bo8ADArsS3YiUEHsxhtvdHsEYFBg\nX7ITp/iCWFVVlaqqqtweAwh67Et2IlBBrKioSEVFRW6PAQQ99iU7ESgAgJUIFADASgQKAGAlAgUA\nsBKXmQexefPmuT0CMCiwL9mJQAWxKVOmuD0CMCiwL9mJU3xBrLKyUpWVlW6PAQQ99iU7EaggVlxc\nrOLiYrfHAIIe+5KdOMUHYMh76KGH3B4BPeAICgBgJQIFALASgQIAWInXoIIY580BDGYcQQEArESg\nAABWIlAAACsRKACAlQgUAMBKBAoAYCUCBQCwEoECAFiJQAEArESgAABWIlAAACsRKACAlQgUAMBK\nBAoAYCUCBQCwEoECAFiJQAEArESgAABWIlAAACsRKACAlQgUAMBKBAoAYCUCBQCwEoECAFiJQAEA\nrESgAABWIlAAACsRKACAlQgUAMBKBAoAYCUCBQCwEoECAFiJQAEArESgAABWIlAAACsRKACAlQgU\nAMBKBAoAYCUCBQCwEoECAFiJQAEArESgAABWIlAAACsRKACAlQgUAMBKxnEc36/UmGpJJ32+YsB9\nqY7jJAVqY+xLGKR6tR/5JVAAAAwUp/gAAFYiUAAAKxEoAICVCBQAwEoECgBgJQIVpIwxs4wxHxhj\nIo0x0caYcmPMVLfnAgBf4TLzIGaM+RdJkZKiJP3NcZx/c3kkAPAZAhXEjDERkt6VdFHSf3Mcp83l\nkQDAZzjFF9xGSoqRFKuOIykAGDQ4ggpixpgtkl6VNEFSiuM4P3B5JADwmTC3B0D/GGPuk+R1HOc/\njDGhkg4aY7Icx9nt9mwA4AscQQEArMRrUAAAKxEoAICVCBQAwEoECgBgJQIFALASgQIAWIlAAQCs\n9P8BwM75W6p5wo0AAAAASUVORK5CYII=\n",
1313 | "text/plain": [
1314 | ""
1315 | ]
1316 | },
1317 | "metadata": {},
1318 | "output_type": "display_data"
1319 | }
1320 | ],
1321 | "source": [
1322 | "# Geometry\n",
1323 | "geom = pd.DataFrame({ 'x':np.array([ 0.000, -0.000, 0.050, -0.050, 0.050, -0.050]),\n",
1324 | " 'y':np.array([ 0.066, -0.066, -0.066, 0.066, 0.066, -0.066]),\n",
1325 | " 'z':[0.0 for _ in range(6) ],\n",
1326 | " 'ax':[0.0 for _ in range(6) ],\n",
1327 | " 'ay':[0.0 for _ in range(6) ],\n",
1328 | " 'az':[-1.0 for _ in range(6) ],\n",
1329 | " 'dir':np.array([1, -1, 1, -1, -1, 1]),\n",
1330 | " 'ct':[1.0 for _ in range(6) ],\n",
1331 | " 'cm':[0.015 for _ in range(6) ] # prop diameter=0.15 -> cm = 0.1*0.15*ct\n",
1332 | " },\n",
1333 | " columns = ['x', 'y', 'z', 'ax', 'ay', 'az', 'dir', 'ct', 'cm'])\n",
1334 | "\n",
1335 | "# Matrices\n",
1336 | "A, B = compute_torque_thrust_matrices(geom)\n",
1337 | "\n",
1338 | "plot(geom)\n",
1339 | "print_actuation_effort(B)\n",
1340 | "\n",
1341 | "print('\\nNormalized Mix (as in paparazzi):')\n",
1342 | "from scipy.stats import threshold\n",
1343 | "B_norm = B.abs().max(axis=0)\n",
1344 | "B_norm[np.abs(B_norm)<1e-3] = 1\n",
1345 | "B_papa = (255 * B / B_norm).round()\n",
1346 | "# B_papa = (1.0 * B / B_norm).round(2)\n",
1347 | "print(B_papa)\n",
1348 | "\n",
1349 | "print('\\nNormalized Mix (as in PX4):')\n",
1350 | "from scipy.stats import threshold\n",
1351 | "B_norm = B.abs().max(axis=0)\n",
1352 | "\n",
1353 | "# Same scale on roll and pitch\n",
1354 | "B_norm.Roll = max(B_norm.Roll, B_norm.Pitch)\n",
1355 | "B_norm.Pitch = B_norm.Roll\n",
1356 | "\n",
1357 | "# Same scale on x, y and z thrust\n",
1358 | "B_norm.X = max(B_norm.X, B_norm.Y, B_norm.Z)\n",
1359 | "B_norm.Y = B_norm.X\n",
1360 | "B_norm.Z = B_norm.X\n",
1361 | "\n",
1362 | "B_norm[np.abs(B_norm)<1e-3] = 1\n",
1363 | "B_px4 = (1.0 * B / B_norm).round(2)\n",
1364 | "print(B_px4)\n",
1365 | "\n",
1366 | "print('\\nMix:')\n",
1367 | "B.round(2)"
1368 | ]
1369 | },
1370 | {
1371 | "cell_type": "markdown",
1372 | "metadata": {},
1373 | "source": [
1374 | "## Example for holonomic hexacopter"
1375 | ]
1376 | },
1377 | {
1378 | "cell_type": "code",
1379 | "execution_count": 11,
1380 | "metadata": {},
1381 | "outputs": [
1382 | {
1383 | "name": "stdout",
1384 | "output_type": "stream",
1385 | "text": [
1386 | "\n",
1387 | "Actuation effort for unit commands\n",
1388 | "Torque: norm [ 4.12 4.12 31.43] / std [ 0.91 0.57 0. ]\n",
1389 | "Thrust: norm [ 1.15 1.15 0.47] / std [ 0.16 0.27 0. ]\n",
1390 | "\n",
1391 | "Mix:\n"
1392 | ]
1393 | },
1394 | {
1395 | "data": {
1396 | "text/html": [
1397 | "\n",
1398 | "\n",
1411 | "
\n",
1412 | " \n",
1413 | " \n",
1414 | " | \n",
1415 | " Roll | \n",
1416 | " Pitch | \n",
1417 | " Yaw | \n",
1418 | " X | \n",
1419 | " Y | \n",
1420 | " Z | \n",
1421 | "
\n",
1422 | " \n",
1423 | " \n",
1424 | " \n",
1425 | " | 0 | \n",
1426 | " -0.13 | \n",
1427 | " -2.37 | \n",
1428 | " 12.83 | \n",
1429 | " 0.67 | \n",
1430 | " -0.00 | \n",
1431 | " -0.19 | \n",
1432 | "
\n",
1433 | " \n",
1434 | " | 1 | \n",
1435 | " 1.99 | \n",
1436 | " -1.30 | \n",
1437 | " -12.83 | \n",
1438 | " -0.33 | \n",
1439 | " -0.58 | \n",
1440 | " -0.19 | \n",
1441 | "
\n",
1442 | " \n",
1443 | " | 2 | \n",
1444 | " 2.12 | \n",
1445 | " 1.08 | \n",
1446 | " 12.83 | \n",
1447 | " -0.33 | \n",
1448 | " 0.58 | \n",
1449 | " -0.19 | \n",
1450 | "
\n",
1451 | " \n",
1452 | " | 3 | \n",
1453 | " 0.13 | \n",
1454 | " 2.37 | \n",
1455 | " -12.83 | \n",
1456 | " 0.67 | \n",
1457 | " -0.00 | \n",
1458 | " -0.19 | \n",
1459 | "
\n",
1460 | " \n",
1461 | " | 4 | \n",
1462 | " -1.99 | \n",
1463 | " 1.30 | \n",
1464 | " 12.83 | \n",
1465 | " -0.33 | \n",
1466 | " -0.58 | \n",
1467 | " -0.19 | \n",
1468 | "
\n",
1469 | " \n",
1470 | " | 5 | \n",
1471 | " -2.12 | \n",
1472 | " -1.08 | \n",
1473 | " -12.83 | \n",
1474 | " -0.33 | \n",
1475 | " 0.58 | \n",
1476 | " -0.19 | \n",
1477 | "
\n",
1478 | " \n",
1479 | "
\n",
1480 | "
"
1481 | ],
1482 | "text/plain": [
1483 | " Roll Pitch Yaw X Y Z\n",
1484 | "0 -0.13 -2.37 12.83 0.67 -0.00 -0.19\n",
1485 | "1 1.99 -1.30 -12.83 -0.33 -0.58 -0.19\n",
1486 | "2 2.12 1.08 12.83 -0.33 0.58 -0.19\n",
1487 | "3 0.13 2.37 -12.83 0.67 -0.00 -0.19\n",
1488 | "4 -1.99 1.30 12.83 -0.33 -0.58 -0.19\n",
1489 | "5 -2.12 -1.08 -12.83 -0.33 0.58 -0.19"
1490 | ]
1491 | },
1492 | "execution_count": 11,
1493 | "metadata": {},
1494 | "output_type": "execute_result"
1495 | },
1496 | {
1497 | "data": {
1498 | "image/png": "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\nZnFxMfPz87l06VKuXbu2+cUT//5X8oufjB7b/c3kxS8/uUHHzBbfgO3fv7/vEWAiVFhL09PTWVhY\nyOXLl3P9+vXcvXs3x44d2/jno359MfnH3z58/Mynk0PfG8+wYyJQA7Z79+6+R4CJUGUtTU1N5ciR\nI5mbm8uVK1eyvLyckydPZseOHaNP/Offk1++MXps/7Hkcy+Mb9gxsMU3YOvr61lfX+97DBi8amtp\n3759WVhYyP3793PmzJncuXNn9AlvnXu0xfeBmc8mXz853iHHQKAGbHV1Naurq32PAYNXcS3t3Lkz\np0+fzrZt23L27NncunXr0R/eXUt+97PRJ3/jVPLs8G9c+r9s8QEUNTc3l8XFxVy4cCEvXfxBcvH/\n3JSzTSV7j45/uDFwBgVQ2MzMTE6dOpXnN7pjdPfw0QUSE0igAIqb1F+R34xAAVCSz6AG7ODBg32P\nABPBWqpJoAZs165dfY8AE8FaqskW34Ctra1lbW2t7zFg8Aaxlp77/OMdnwDOoAbs6tWrSZKlpaWe\nJ4FhG8Raeu3pu/ebQAFPvdJheorZ4gOgJIECoCSBAqAkn0ENmH1zYJI5gwKgJIECoCSBAqAkgQKg\nJIECoCSBAqAkgQKgJIECoCSBAqAkgQKgJIECoCSBAqAkgQKgJIECoCSBAqAkgQKgJIECoCSBAqAk\ngQKgJIECoCSBAqAkgQKgJIECoCSBAqAkgQKgJIECoCSBAqAkgQKgJIECoCSBAqAkgQKgJIECoCSB\nAqAkgQKgJIECoCSBAqAkgQKgJIECoCSBAqAkgQKgJIECoCSBAqAkgQKgJIECoCSBAqCk1nXd1r9p\na+8m+fOWvzH074td182N659ZS0yoj7SOnkigAOCTssUHQEkCBUBJAgVASQIFQEkCBUBJAjVQrbW9\nrbXft9amW2vPtdb+0Fr7St9zAWwVl5kPWGvth0mmkzyb5E7Xda/3PBLAlhGoAWutbUvy2yQPknyt\n67r3ex4JYMvY4hu22STPJ/lMHp1JAUwMZ1AD1lr7aZI3kryU5MWu677f80gAW+aZvgfg42mtfSfJ\ne13XnW+tfSrJr1prh7qu+3nfswFsBWdQAJTkMygAShIoAEoSKABKEigAShIoAEoSKABKEigASvoP\nA1d23ZvwEHgAAAAASUVORK5CYII=\n",
1499 | "text/plain": [
1500 | ""
1501 | ]
1502 | },
1503 | "metadata": {},
1504 | "output_type": "display_data"
1505 | }
1506 | ],
1507 | "source": [
1508 | "# Geometry\n",
1509 | "t30 = np.deg2rad(30)\n",
1510 | "t60 = np.deg2rad(60)\n",
1511 | "thetas = np.arange(-np.pi, np.pi, t60)\n",
1512 | "l = 0.16\n",
1513 | "h = 0.5*l * np.sin(t30)\n",
1514 | "\n",
1515 | "geom = pd.DataFrame({ 'x':[l * np.cos(t30) * np.cos(theta) for theta in thetas ],\n",
1516 | " 'y':[l * np.cos(t30) * np.sin(theta) for theta in thetas ],\n",
1517 | " 'z':[h * (-1+2*((i+0)%2)) for i,_ in enumerate(thetas) ],\n",
1518 | " 'ax':[-np.sin(t30)*np.cos(theta)*(-1+2*((i+1)%2)) for i,theta in enumerate(thetas) ],\n",
1519 | " 'ay':[-np.sin(t30)*np.sin(theta)*(-1+2*((i+1)%2)) for i,theta in enumerate(thetas) ],\n",
1520 | " 'az':[-np.cos(t30) for _ in thetas ],\n",
1521 | " 'dir':[-1+2*((i+1)%2) for i,_ in enumerate(thetas)],\n",
1522 | " 'ct':[1.0 for _ in thetas ],\n",
1523 | " 'cm':[0.015 for _ in thetas ] \n",
1524 | " },\n",
1525 | " columns = ['x', 'y', 'z', 'ax', 'ay', 'az', 'dir', 'ct', 'cm'])\n",
1526 | "\n",
1527 | "# Matrices\n",
1528 | "A, B = compute_torque_thrust_matrices(geom)\n",
1529 | "\n",
1530 | "plot(geom)\n",
1531 | "print_actuation_effort(B)\n",
1532 | "\n",
1533 | "print('\\nMix:')\n",
1534 | "B.round(2)"
1535 | ]
1536 | },
1537 | {
1538 | "cell_type": "markdown",
1539 | "metadata": {},
1540 | "source": [
1541 | "---\n",
1542 | "### Example for holonomic +4 octo with rotors tilted towards center"
1543 | ]
1544 | },
1545 | {
1546 | "cell_type": "code",
1547 | "execution_count": 12,
1548 | "metadata": {},
1549 | "outputs": [
1550 | {
1551 | "name": "stdout",
1552 | "output_type": "stream",
1553 | "text": [
1554 | "\n",
1555 | "Actuation effort for unit commands\n",
1556 | "Torque: norm [ 2.8 2.8 27.22] / std [ 0.04 0.04 0. ]\n",
1557 | "Thrust: norm [ 1. 1. 0.41] / std [ 0. 0. 0.]\n",
1558 | "\n",
1559 | "Mix:\n"
1560 | ]
1561 | },
1562 | {
1563 | "data": {
1564 | "text/html": [
1565 | "\n",
1566 | "\n",
1579 | "
\n",
1580 | " \n",
1581 | " \n",
1582 | " | \n",
1583 | " Roll | \n",
1584 | " Pitch | \n",
1585 | " Yaw | \n",
1586 | " X | \n",
1587 | " Y | \n",
1588 | " Z | \n",
1589 | "
\n",
1590 | " \n",
1591 | " \n",
1592 | " \n",
1593 | " | 0 | \n",
1594 | " -1.03 | \n",
1595 | " 0.95 | \n",
1596 | " -9.62 | \n",
1597 | " -0.35 | \n",
1598 | " -0.35 | \n",
1599 | " -0.14 | \n",
1600 | "
\n",
1601 | " \n",
1602 | " | 1 | \n",
1603 | " -1.03 | \n",
1604 | " 0.95 | \n",
1605 | " 9.62 | \n",
1606 | " 0.35 | \n",
1607 | " 0.35 | \n",
1608 | " -0.14 | \n",
1609 | "
\n",
1610 | " \n",
1611 | " | 2 | \n",
1612 | " -0.95 | \n",
1613 | " -1.03 | \n",
1614 | " -9.62 | \n",
1615 | " 0.35 | \n",
1616 | " -0.35 | \n",
1617 | " -0.14 | \n",
1618 | "
\n",
1619 | " \n",
1620 | " | 3 | \n",
1621 | " -0.95 | \n",
1622 | " -1.03 | \n",
1623 | " 9.62 | \n",
1624 | " -0.35 | \n",
1625 | " 0.35 | \n",
1626 | " -0.14 | \n",
1627 | "
\n",
1628 | " \n",
1629 | " | 4 | \n",
1630 | " 1.03 | \n",
1631 | " -0.95 | \n",
1632 | " -9.62 | \n",
1633 | " 0.35 | \n",
1634 | " 0.35 | \n",
1635 | " -0.14 | \n",
1636 | "
\n",
1637 | " \n",
1638 | " | 5 | \n",
1639 | " 1.03 | \n",
1640 | " -0.95 | \n",
1641 | " 9.62 | \n",
1642 | " -0.35 | \n",
1643 | " -0.35 | \n",
1644 | " -0.14 | \n",
1645 | "
\n",
1646 | " \n",
1647 | " | 6 | \n",
1648 | " 0.95 | \n",
1649 | " 1.03 | \n",
1650 | " -9.62 | \n",
1651 | " -0.35 | \n",
1652 | " 0.35 | \n",
1653 | " -0.14 | \n",
1654 | "
\n",
1655 | " \n",
1656 | " | 7 | \n",
1657 | " 0.95 | \n",
1658 | " 1.03 | \n",
1659 | " 9.62 | \n",
1660 | " 0.35 | \n",
1661 | " -0.35 | \n",
1662 | " -0.14 | \n",
1663 | "
\n",
1664 | " \n",
1665 | "
\n",
1666 | "
"
1667 | ],
1668 | "text/plain": [
1669 | " Roll Pitch Yaw X Y Z\n",
1670 | "0 -1.03 0.95 -9.62 -0.35 -0.35 -0.14\n",
1671 | "1 -1.03 0.95 9.62 0.35 0.35 -0.14\n",
1672 | "2 -0.95 -1.03 -9.62 0.35 -0.35 -0.14\n",
1673 | "3 -0.95 -1.03 9.62 -0.35 0.35 -0.14\n",
1674 | "4 1.03 -0.95 -9.62 0.35 0.35 -0.14\n",
1675 | "5 1.03 -0.95 9.62 -0.35 -0.35 -0.14\n",
1676 | "6 0.95 1.03 -9.62 -0.35 0.35 -0.14\n",
1677 | "7 0.95 1.03 9.62 0.35 -0.35 -0.14"
1678 | ]
1679 | },
1680 | "execution_count": 12,
1681 | "metadata": {},
1682 | "output_type": "execute_result"
1683 | },
1684 | {
1685 | "data": {
1686 | "image/png": "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\nrkJggg==\n",
1687 | "text/plain": [
1688 | ""
1689 | ]
1690 | },
1691 | "metadata": {},
1692 | "output_type": "display_data"
1693 | }
1694 | ],
1695 | "source": [
1696 | "# Geometry\n",
1697 | "t30 = np.deg2rad(30)\n",
1698 | "t45 = np.deg2rad(45)\n",
1699 | "t90 = np.deg2rad(90)\n",
1700 | "t135 = np.deg2rad(135)\n",
1701 | "l = 0.16\n",
1702 | "# h = 0.0\n",
1703 | "h = 1.0 * l * np.sin(t30)\n",
1704 | "\n",
1705 | "thetas = np.array([t45, t45, t135, t135, -t135, -t135, -t45, -t45])\n",
1706 | "# thetas = np.array([0.0, 0.0, t90, t90, 2*t90, 2*t90, -t90, -t90])\n",
1707 | "# thetas = np.array([-t45/4, t45/4, t90-t45/4, t90+t45/4, 2*t90-t45/4, 2*t90+t45/4, -t90-t45/4, -t90+t45/4])\n",
1708 | "# thetas = np.array([-t45/2, t45/2, t90-t45/2, t90+t45/2, 2*t90-t45/2, 2*t90+t45/2, -t90-t45/2, -t90+t45/2])\n",
1709 | "\n",
1710 | "\n",
1711 | "geom = pd.DataFrame({ 'x':[l * np.cos(theta) for theta in thetas ],\n",
1712 | " 'y':[l * np.sin(theta) for theta in thetas ],\n",
1713 | " 'z':[h * (-1+2*(i%2)) for i,_ in enumerate(thetas) ],\n",
1714 | " 'ax':[np.sin(t30)*np.cos(theta)*(-1+2*((1*i+0)%2)) for i,theta in enumerate(thetas) ],\n",
1715 | " 'ay':[np.sin(t30)*np.sin(theta)*(-1+2*((1*i+0)%2)) for i,theta in enumerate(thetas) ],\n",
1716 | " 'az':[-np.cos(t30) for _ in thetas ],\n",
1717 | " 'dir':[-1+2*(((2*(i+0))//2)%2) for i,_ in enumerate(thetas)],\n",
1718 | " 'ct':[1.0 for _ in thetas ],\n",
1719 | " 'cm':[0.015 for _ in thetas ]\n",
1720 | " },\n",
1721 | " columns = ['x', 'y', 'z', 'ax', 'ay', 'az', 'dir', 'ct', 'cm'])\n",
1722 | "\n",
1723 | "\n",
1724 | "# Matrices\n",
1725 | "A, B = compute_torque_thrust_matrices(geom)\n",
1726 | "\n",
1727 | "plot(geom)\n",
1728 | "print_actuation_effort(B)\n",
1729 | "\n",
1730 | "print('\\nMix:')\n",
1731 | "B.round(2)"
1732 | ]
1733 | },
1734 | {
1735 | "cell_type": "markdown",
1736 | "metadata": {},
1737 | "source": [
1738 | "---\n",
1739 | "### Example for holonomic x4 octo with rotors tilted sideways"
1740 | ]
1741 | },
1742 | {
1743 | "cell_type": "code",
1744 | "execution_count": 13,
1745 | "metadata": {},
1746 | "outputs": [
1747 | {
1748 | "name": "stdout",
1749 | "output_type": "stream",
1750 | "text": [
1751 | "\n",
1752 | "Actuation effort for unit commands\n",
1753 | "Torque: norm [ 3.81 3.81 3.8 ] / std [ 0. 0. 0.]\n",
1754 | "Thrust: norm [ 1. 1. 0.41] / std [ 0. 0. 0.]\n",
1755 | "\n",
1756 | "Mix:\n"
1757 | ]
1758 | },
1759 | {
1760 | "data": {
1761 | "text/html": [
1762 | "\n",
1763 | "\n",
1776 | "
\n",
1777 | " \n",
1778 | " \n",
1779 | " | \n",
1780 | " Roll | \n",
1781 | " Pitch | \n",
1782 | " Yaw | \n",
1783 | " X | \n",
1784 | " Y | \n",
1785 | " Z | \n",
1786 | "
\n",
1787 | " \n",
1788 | " \n",
1789 | " \n",
1790 | " | 0 | \n",
1791 | " -1.35 | \n",
1792 | " 1.35 | \n",
1793 | " -1.34 | \n",
1794 | " 0.35 | \n",
1795 | " -0.35 | \n",
1796 | " -0.14 | \n",
1797 | "
\n",
1798 | " \n",
1799 | " | 1 | \n",
1800 | " -1.35 | \n",
1801 | " 1.35 | \n",
1802 | " 1.34 | \n",
1803 | " -0.35 | \n",
1804 | " 0.35 | \n",
1805 | " -0.14 | \n",
1806 | "
\n",
1807 | " \n",
1808 | " | 2 | \n",
1809 | " -1.35 | \n",
1810 | " -1.35 | \n",
1811 | " -1.34 | \n",
1812 | " 0.35 | \n",
1813 | " 0.35 | \n",
1814 | " -0.14 | \n",
1815 | "
\n",
1816 | " \n",
1817 | " | 3 | \n",
1818 | " -1.35 | \n",
1819 | " -1.35 | \n",
1820 | " 1.34 | \n",
1821 | " -0.35 | \n",
1822 | " -0.35 | \n",
1823 | " -0.14 | \n",
1824 | "
\n",
1825 | " \n",
1826 | " | 4 | \n",
1827 | " 1.35 | \n",
1828 | " -1.35 | \n",
1829 | " -1.34 | \n",
1830 | " -0.35 | \n",
1831 | " 0.35 | \n",
1832 | " -0.14 | \n",
1833 | "
\n",
1834 | " \n",
1835 | " | 5 | \n",
1836 | " 1.35 | \n",
1837 | " -1.35 | \n",
1838 | " 1.34 | \n",
1839 | " 0.35 | \n",
1840 | " -0.35 | \n",
1841 | " -0.14 | \n",
1842 | "
\n",
1843 | " \n",
1844 | " | 6 | \n",
1845 | " 1.35 | \n",
1846 | " 1.35 | \n",
1847 | " -1.34 | \n",
1848 | " -0.35 | \n",
1849 | " -0.35 | \n",
1850 | " -0.14 | \n",
1851 | "
\n",
1852 | " \n",
1853 | " | 7 | \n",
1854 | " 1.35 | \n",
1855 | " 1.35 | \n",
1856 | " 1.34 | \n",
1857 | " 0.35 | \n",
1858 | " 0.35 | \n",
1859 | " -0.14 | \n",
1860 | "
\n",
1861 | " \n",
1862 | "
\n",
1863 | "
"
1864 | ],
1865 | "text/plain": [
1866 | " Roll Pitch Yaw X Y Z\n",
1867 | "0 -1.35 1.35 -1.34 0.35 -0.35 -0.14\n",
1868 | "1 -1.35 1.35 1.34 -0.35 0.35 -0.14\n",
1869 | "2 -1.35 -1.35 -1.34 0.35 0.35 -0.14\n",
1870 | "3 -1.35 -1.35 1.34 -0.35 -0.35 -0.14\n",
1871 | "4 1.35 -1.35 -1.34 -0.35 0.35 -0.14\n",
1872 | "5 1.35 -1.35 1.34 0.35 -0.35 -0.14\n",
1873 | "6 1.35 1.35 -1.34 -0.35 -0.35 -0.14\n",
1874 | "7 1.35 1.35 1.34 0.35 0.35 -0.14"
1875 | ]
1876 | },
1877 | "execution_count": 13,
1878 | "metadata": {},
1879 | "output_type": "execute_result"
1880 | },
1881 | {
1882 | "data": {
1883 | "image/png": "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\nQmCC\n",
1884 | "text/plain": [
1885 | ""
1886 | ]
1887 | },
1888 | "metadata": {},
1889 | "output_type": "display_data"
1890 | }
1891 | ],
1892 | "source": [
1893 | "# Thrust and moment coefficients\n",
1894 | "Ct = 1.0\n",
1895 | "Cm = Ct / 10.0\n",
1896 | "\n",
1897 | "# Geometry\n",
1898 | "t30 = np.deg2rad(30)\n",
1899 | "t45 = np.deg2rad(45)\n",
1900 | "t90 = np.deg2rad(90)\n",
1901 | "t135 = np.deg2rad(135)\n",
1902 | "l = 0.16\n",
1903 | "h = 0.0#l * np.sin(t30)\n",
1904 | "# h = 0.5*l * np.sin(t30)\n",
1905 | "\n",
1906 | "thetas = np.array([t45, t45, t135, t135, -t135, -t135, -t45, -t45])\n",
1907 | "# thetas = np.array([-t45/2, t45/2, t90-t45/2, t90+t45/2, 2*t90-t45/2, 2*t90+t45/2, -t90-t45/2, -t90+t45/2])\n",
1908 | "\n",
1909 | "geom = pd.DataFrame({ 'x':[l * np.cos(theta) for theta in thetas ],\n",
1910 | " 'y':[l * np.sin(theta) for theta in thetas ],\n",
1911 | " 'z':[h * (-1+2*((i+0)%2)) for i,_ in enumerate(thetas) ],\n",
1912 | " 'ax':[np.sin(t30)*np.cos(theta + t90*(-1+2*(((2*i+1)//2)%2))) for i,theta in enumerate(thetas) ],\n",
1913 | " 'ay':[np.sin(t30)*np.sin(theta + t90*(-1+2*(((2*i+1)//2)%2))) for i,theta in enumerate(thetas) ],\n",
1914 | " 'az':[-np.cos(t30) for _ in thetas ],\n",
1915 | " 'dir':[(-1+2*(((2*i)//2)%2)) for i,_ in enumerate(thetas)],\n",
1916 | " 'ct':[1.0 for _ in thetas ],\n",
1917 | " 'cm':[0.015 for _ in thetas ]\n",
1918 | " },\n",
1919 | " columns = ['x', 'y', 'z', 'ax', 'ay', 'az', 'dir', 'ct', 'cm'])\n",
1920 | "\n",
1921 | "\n",
1922 | "# Matrices\n",
1923 | "A, B = compute_torque_thrust_matrices(geom)\n",
1924 | "\n",
1925 | "plot(geom)\n",
1926 | "print_actuation_effort(B)\n",
1927 | "\n",
1928 | "print('\\nMix:')\n",
1929 | "B.round(2)"
1930 | ]
1931 | },
1932 | {
1933 | "cell_type": "code",
1934 | "execution_count": null,
1935 | "metadata": {
1936 | "collapsed": true
1937 | },
1938 | "outputs": [],
1939 | "source": []
1940 | }
1941 | ],
1942 | "metadata": {
1943 | "kernelspec": {
1944 | "display_name": "Python 3",
1945 | "language": "python",
1946 | "name": "python3"
1947 | },
1948 | "language_info": {
1949 | "codemirror_mode": {
1950 | "name": "ipython",
1951 | "version": 3
1952 | },
1953 | "file_extension": ".py",
1954 | "mimetype": "text/x-python",
1955 | "name": "python",
1956 | "nbconvert_exporter": "python",
1957 | "pygments_lexer": "ipython3",
1958 | "version": "3.6.2"
1959 | }
1960 | },
1961 | "nbformat": 4,
1962 | "nbformat_minor": 2
1963 | }
1964 |
--------------------------------------------------------------------------------