├── 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 | " \n", 531 | " \n", 532 | " \n", 533 | " \n", 534 | " \n", 535 | " \n", 536 | " \n", 537 | " \n", 538 | " \n", 539 | " \n", 540 | " \n", 541 | " \n", 542 | " \n", 543 | " \n", 544 | " \n", 545 | " \n", 546 | " \n", 547 | " \n", 548 | " \n", 549 | " \n", 550 | " \n", 551 | " \n", 552 | " \n", 553 | " \n", 554 | " \n", 555 | " \n", 556 | " \n", 557 | " \n", 558 | " \n", 559 | " \n", 560 | " \n", 561 | " \n", 562 | " \n", 563 | " \n", 564 | " \n", 565 | " \n", 566 | " \n", 567 | " \n", 568 | " \n", 569 | " \n", 570 | " \n", 571 | " \n", 572 | " \n", 573 | " \n", 574 | " \n", 575 | " \n", 576 | "
RollPitchYawXYZ
02.17-2.1716.670.00.0-0.25
12.172.17-16.670.00.0-0.25
2-2.172.1716.670.00.0-0.25
3-2.17-2.17-16.670.00.0-0.25
\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 | " \n", 690 | " \n", 691 | " \n", 692 | " \n", 693 | " \n", 694 | " \n", 695 | " \n", 696 | " \n", 697 | " \n", 698 | " \n", 699 | " \n", 700 | " \n", 701 | " \n", 702 | " \n", 703 | " \n", 704 | " \n", 705 | " \n", 706 | " \n", 707 | " \n", 708 | " \n", 709 | " \n", 710 | " \n", 711 | " \n", 712 | " \n", 713 | " \n", 714 | " \n", 715 | " \n", 716 | " \n", 717 | " \n", 718 | " \n", 719 | " \n", 720 | " \n", 721 | " \n", 722 | " \n", 723 | " \n", 724 | " \n", 725 | " \n", 726 | " \n", 727 | " \n", 728 | " \n", 729 | " \n", 730 | " \n", 731 | " \n", 732 | " \n", 733 | " \n", 734 | " \n", 735 | "
RollPitchYawXYZ
0-0.460.24-3.640.79-0.76-0.28
10.460.243.640.790.76-0.28
20.04-0.24-3.38-0.800.83-0.26
3-0.04-0.243.38-0.80-0.83-0.26
\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 | " \n", 869 | " \n", 870 | " \n", 871 | " \n", 872 | " \n", 873 | " \n", 874 | " \n", 875 | " \n", 876 | " \n", 877 | " \n", 878 | " \n", 879 | " \n", 880 | " \n", 881 | " \n", 882 | " \n", 883 | " \n", 884 | " \n", 885 | " \n", 886 | " \n", 887 | " \n", 888 | " \n", 889 | " \n", 890 | " \n", 891 | " \n", 892 | " \n", 893 | " \n", 894 | " \n", 895 | " \n", 896 | " \n", 897 | " \n", 898 | " \n", 899 | " \n", 900 | " \n", 901 | " \n", 902 | " \n", 903 | " \n", 904 | " \n", 905 | " \n", 906 | " \n", 907 | " \n", 908 | " \n", 909 | " \n", 910 | " \n", 911 | " \n", 912 | " \n", 913 | " \n", 914 | " \n", 915 | " \n", 916 | " \n", 917 | " \n", 918 | " \n", 919 | " \n", 920 | " \n", 921 | " \n", 922 | " \n", 923 | " \n", 924 | " \n", 925 | " \n", 926 | " \n", 927 | " \n", 928 | " \n", 929 | " \n", 930 | " \n", 931 | " \n", 932 | "
RollPitchYawXYZ
0-1.041.8-11.110.00.0-0.17
1-2.08-0.011.110.00.0-0.17
2-1.04-1.8-11.110.00.0-0.17
31.04-1.811.110.00.0-0.17
42.080.0-11.110.00.0-0.17
51.041.811.110.00.0-0.17
\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 | " \n", 1044 | " \n", 1045 | " \n", 1046 | " \n", 1047 | " \n", 1048 | " \n", 1049 | " \n", 1050 | " \n", 1051 | " \n", 1052 | " \n", 1053 | " \n", 1054 | " \n", 1055 | " \n", 1056 | " \n", 1057 | " \n", 1058 | " \n", 1059 | " \n", 1060 | " \n", 1061 | " \n", 1062 | " \n", 1063 | " \n", 1064 | " \n", 1065 | " \n", 1066 | " \n", 1067 | " \n", 1068 | " \n", 1069 | " \n", 1070 | " \n", 1071 | " \n", 1072 | " \n", 1073 | " \n", 1074 | " \n", 1075 | " \n", 1076 | " \n", 1077 | " \n", 1078 | " \n", 1079 | " \n", 1080 | " \n", 1081 | " \n", 1082 | " \n", 1083 | " \n", 1084 | " \n", 1085 | " \n", 1086 | " \n", 1087 | " \n", 1088 | " \n", 1089 | " \n", 1090 | " \n", 1091 | " \n", 1092 | " \n", 1093 | " \n", 1094 | " \n", 1095 | " \n", 1096 | " \n", 1097 | " \n", 1098 | " \n", 1099 | " \n", 1100 | " \n", 1101 | " \n", 1102 | " \n", 1103 | " \n", 1104 | " \n", 1105 | " \n", 1106 | " \n", 1107 | "
RollPitchYawXYZ
0-0.60-1.79-9.770.00.0-0.17
10.60-1.799.770.00.0-0.17
2-2.32-0.0016.270.00.0-0.17
32.320.00-16.270.00.0-0.17
4-1.721.79-7.290.00.0-0.17
51.721.797.290.00.0-0.17
\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 | " \n", 1230 | " \n", 1231 | " \n", 1232 | " \n", 1233 | " \n", 1234 | " \n", 1235 | " \n", 1236 | " \n", 1237 | " \n", 1238 | " \n", 1239 | " \n", 1240 | " \n", 1241 | " \n", 1242 | " \n", 1243 | " \n", 1244 | " \n", 1245 | " \n", 1246 | " \n", 1247 | " \n", 1248 | " \n", 1249 | " \n", 1250 | " \n", 1251 | " \n", 1252 | " \n", 1253 | " \n", 1254 | " \n", 1255 | " \n", 1256 | " \n", 1257 | " \n", 1258 | " \n", 1259 | " \n", 1260 | " \n", 1261 | " \n", 1262 | " \n", 1263 | " \n", 1264 | " \n", 1265 | " \n", 1266 | " \n", 1267 | " \n", 1268 | " \n", 1269 | " \n", 1270 | " \n", 1271 | " \n", 1272 | " \n", 1273 | " \n", 1274 | " \n", 1275 | " \n", 1276 | " \n", 1277 | " \n", 1278 | " \n", 1279 | " \n", 1280 | " \n", 1281 | " \n", 1282 | " \n", 1283 | " \n", 1284 | " \n", 1285 | " \n", 1286 | " \n", 1287 | " \n", 1288 | " \n", 1289 | " \n", 1290 | " \n", 1291 | " \n", 1292 | " \n", 1293 | "
RollPitchYawXYZ
0-3.79-0.016.670.00.0-0.17
13.790.0-16.670.00.0-0.17
21.895.08.330.00.0-0.17
3-1.89-5.0-8.330.00.0-0.17
4-1.895.0-8.330.00.0-0.17
51.89-5.08.330.00.0-0.17
\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 | " \n", 1416 | " \n", 1417 | " \n", 1418 | " \n", 1419 | " \n", 1420 | " \n", 1421 | " \n", 1422 | " \n", 1423 | " \n", 1424 | " \n", 1425 | " \n", 1426 | " \n", 1427 | " \n", 1428 | " \n", 1429 | " \n", 1430 | " \n", 1431 | " \n", 1432 | " \n", 1433 | " \n", 1434 | " \n", 1435 | " \n", 1436 | " \n", 1437 | " \n", 1438 | " \n", 1439 | " \n", 1440 | " \n", 1441 | " \n", 1442 | " \n", 1443 | " \n", 1444 | " \n", 1445 | " \n", 1446 | " \n", 1447 | " \n", 1448 | " \n", 1449 | " \n", 1450 | " \n", 1451 | " \n", 1452 | " \n", 1453 | " \n", 1454 | " \n", 1455 | " \n", 1456 | " \n", 1457 | " \n", 1458 | " \n", 1459 | " \n", 1460 | " \n", 1461 | " \n", 1462 | " \n", 1463 | " \n", 1464 | " \n", 1465 | " \n", 1466 | " \n", 1467 | " \n", 1468 | " \n", 1469 | " \n", 1470 | " \n", 1471 | " \n", 1472 | " \n", 1473 | " \n", 1474 | " \n", 1475 | " \n", 1476 | " \n", 1477 | " \n", 1478 | " \n", 1479 | "
RollPitchYawXYZ
0-0.13-2.3712.830.67-0.00-0.19
11.99-1.30-12.83-0.33-0.58-0.19
22.121.0812.83-0.330.58-0.19
30.132.37-12.830.67-0.00-0.19
4-1.991.3012.83-0.33-0.58-0.19
5-2.12-1.08-12.83-0.330.58-0.19
\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 | " \n", 1584 | " \n", 1585 | " \n", 1586 | " \n", 1587 | " \n", 1588 | " \n", 1589 | " \n", 1590 | " \n", 1591 | " \n", 1592 | " \n", 1593 | " \n", 1594 | " \n", 1595 | " \n", 1596 | " \n", 1597 | " \n", 1598 | " \n", 1599 | " \n", 1600 | " \n", 1601 | " \n", 1602 | " \n", 1603 | " \n", 1604 | " \n", 1605 | " \n", 1606 | " \n", 1607 | " \n", 1608 | " \n", 1609 | " \n", 1610 | " \n", 1611 | " \n", 1612 | " \n", 1613 | " \n", 1614 | " \n", 1615 | " \n", 1616 | " \n", 1617 | " \n", 1618 | " \n", 1619 | " \n", 1620 | " \n", 1621 | " \n", 1622 | " \n", 1623 | " \n", 1624 | " \n", 1625 | " \n", 1626 | " \n", 1627 | " \n", 1628 | " \n", 1629 | " \n", 1630 | " \n", 1631 | " \n", 1632 | " \n", 1633 | " \n", 1634 | " \n", 1635 | " \n", 1636 | " \n", 1637 | " \n", 1638 | " \n", 1639 | " \n", 1640 | " \n", 1641 | " \n", 1642 | " \n", 1643 | " \n", 1644 | " \n", 1645 | " \n", 1646 | " \n", 1647 | " \n", 1648 | " \n", 1649 | " \n", 1650 | " \n", 1651 | " \n", 1652 | " \n", 1653 | " \n", 1654 | " \n", 1655 | " \n", 1656 | " \n", 1657 | " \n", 1658 | " \n", 1659 | " \n", 1660 | " \n", 1661 | " \n", 1662 | " \n", 1663 | " \n", 1664 | " \n", 1665 | "
RollPitchYawXYZ
0-1.030.95-9.62-0.35-0.35-0.14
1-1.030.959.620.350.35-0.14
2-0.95-1.03-9.620.35-0.35-0.14
3-0.95-1.039.62-0.350.35-0.14
41.03-0.95-9.620.350.35-0.14
51.03-0.959.62-0.35-0.35-0.14
60.951.03-9.62-0.350.35-0.14
70.951.039.620.35-0.35-0.14
\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 | " \n", 1781 | " \n", 1782 | " \n", 1783 | " \n", 1784 | " \n", 1785 | " \n", 1786 | " \n", 1787 | " \n", 1788 | " \n", 1789 | " \n", 1790 | " \n", 1791 | " \n", 1792 | " \n", 1793 | " \n", 1794 | " \n", 1795 | " \n", 1796 | " \n", 1797 | " \n", 1798 | " \n", 1799 | " \n", 1800 | " \n", 1801 | " \n", 1802 | " \n", 1803 | " \n", 1804 | " \n", 1805 | " \n", 1806 | " \n", 1807 | " \n", 1808 | " \n", 1809 | " \n", 1810 | " \n", 1811 | " \n", 1812 | " \n", 1813 | " \n", 1814 | " \n", 1815 | " \n", 1816 | " \n", 1817 | " \n", 1818 | " \n", 1819 | " \n", 1820 | " \n", 1821 | " \n", 1822 | " \n", 1823 | " \n", 1824 | " \n", 1825 | " \n", 1826 | " \n", 1827 | " \n", 1828 | " \n", 1829 | " \n", 1830 | " \n", 1831 | " \n", 1832 | " \n", 1833 | " \n", 1834 | " \n", 1835 | " \n", 1836 | " \n", 1837 | " \n", 1838 | " \n", 1839 | " \n", 1840 | " \n", 1841 | " \n", 1842 | " \n", 1843 | " \n", 1844 | " \n", 1845 | " \n", 1846 | " \n", 1847 | " \n", 1848 | " \n", 1849 | " \n", 1850 | " \n", 1851 | " \n", 1852 | " \n", 1853 | " \n", 1854 | " \n", 1855 | " \n", 1856 | " \n", 1857 | " \n", 1858 | " \n", 1859 | " \n", 1860 | " \n", 1861 | " \n", 1862 | "
RollPitchYawXYZ
0-1.351.35-1.340.35-0.35-0.14
1-1.351.351.34-0.350.35-0.14
2-1.35-1.35-1.340.350.35-0.14
3-1.35-1.351.34-0.35-0.35-0.14
41.35-1.35-1.34-0.350.35-0.14
51.35-1.351.340.35-0.35-0.14
61.351.35-1.34-0.35-0.35-0.14
71.351.351.340.350.35-0.14
\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 | --------------------------------------------------------------------------------