\documentclass[a4paper, 11pt, pdftex]{article} \usepackage[pdftex]{graphicx} \usepackage{ae} \usepackage{latexsym} \usepackage{rotating} \usepackage[intlimits, sumlimits]{amsmath} \usepackage[pdftex, bookmarks]{hyperref} \pdfcompresslevel=9 \newcommand{\unit}[1]{\textrm{#1}} \newcommand{\vi}[1]{_{\textrm{#1}}} \newcommand{\EtaProp}{\eta_{\textrm{prop}}} \newcommand{\EtaSteller}{\eta_{\textrm{steller}}} \def\jwwTitle{How to adjust multicopter parameters, multicopter model version 1} \def\jwwSubject{} \def\jwwKeywords{multicopter, quadrocopte, CRRCSim} \def\jwwAuthor{Jens Wilhelm Wulf} \hypersetup{pdftitle={\jwwTitle},% pdfsubject={\jwwSubject},% pdfkeywords={\jwwKeywords},% pdfauthor={\jwwAuthor}} \author{\jwwAuthor} \title{\jwwTitle} \date{06.12.2009} \begin{document} \numberwithin{equation}{section} \maketitle \tableofcontents \clearpage \setlength{\parindent}{0pt} \setlength{\parskip}{5pt plus 2pt minus 1pt} \section{General file format} Take a look at {\tt qc01.xml} as an example. Hard points/wheels, mass, inertia are just like with fixed wing models (see \cite{l:C_FILE}), the only difference is about aerodynamic data and controllers. You need to define where propellers are mounted. Describe x- and y-offsets to center of gravity and whether props are spinning counter-clockwise ({\tt dir="-1"}). All motors/propellers are assumed to be of the same type (except for direction of rotation) and defined in the power-section as it is done for fixed-wing models. Note that the simulation uses one battery for every motor, so its capacity defined in the file is smaller than you might think. {\tt qc01.xml} does not use the automagic type of description in order to allow a more detailed fit to the real model. Coordinate system: x positive forward, y positive right, z positive down. Rotation rates around these axes are $p$, $q$, $r$. In order to adjust the CRRCSim model to my real one, I used the following steps. Beware: this is NOT easy, and some parts even plain dangerous. I guess that people who are able to do this are able to do the math themselves and much more. \section{Statics} Hover data measured on the real copter and used for some of the calculations here: \begin{tabular}{r|r|r|r|r} PWM-ratio & battery voltage & rpm & mass & $M$ (calculated, see below)\\ \hline 80/255 & 11,2 V & 2768 rpm & 405 g & 0.02 N\\ 96/255 & 10,8 V & 3100 rpm & 505 g & 0.02494 N\\ 110/255 & 10,6 V & 3397 rpm & 612 g & 0.03022 N\\ \end{tabular} First of all, prop positions, mass and inertia should be quite accurate. All this can simply be measured and calculated. Describe your power plant. Set {\tt yaw.dist} and {\tt roll.dist} to zero. \subsection{Propeller} Weight is 400\,g, so every motor/prop needs to create $F = 0.1\,\unit{kg} \cdot 9.81\,\unit{m}/\unit{s}^2=0.981\,\unit{N}$. Take a look at the source code to see how propeller force is calculated: {\tt src/mod\_fdm/power/propeller.cpp}. When hovering, this is \begin{subequations} \begin{eqnarray} \EtaProp &=& 0.65\\ \varrho &=& 1.225\,\unit{kg}/\unit{m}^3\\ F &=& \pi \cdot 0.25 \cdot D^2 \varrho \left(H n\right)^2 \cdot 1/2\, \EtaProp \label{f:PROP_F} \end{eqnarray} \end{subequations} I know that my setup needs around 2800\,rpm to hover, $D$=0.235\,m. Using these values and equation~\eqref{f:PROP_F} results in $H$=0.162\,m. I recalculated using all the numbers from the table above, the mean value is $H$=0.1644\,m. You may ask about why I didn't just use the propeller's $H$ as defined by the manufacturer. First, my prop is a modified standard one, so usual rules don't apply. Secondly, I often read that manufacturers $H$ is not accurate. Set {\tt engine.log} to 1 and hover at fixed altitude using an attitude controlled setup. CRRCSim will write lots of data to stdout: one line per timestep and motor. Redirect this output to a file (is automatically done on windows) in order to not slow your PC down. Testing shows that the copter hovers at 2800\,rpm now. Fine. Motor parameters need to be adjusted. Also see \cite{l:C_POWER}. However, in this case I have some data at three operating points, but it does not include motor current. Going back to the propeller code, lets calculate the torque needed. Equations found in the code are: \begin{subequations} \begin{eqnarray} P &=& F_X \, V_p / (2 \, \EtaProp) \\ P &=& F_X \, H \, n / (2 \, \EtaProp) \\ M &=& P / \omega \\ M &=& P / (2 \, \pi \, n) \\ M &=& F_X \, H \, n / (2 \, \EtaProp \, 2 \, \pi \, n)\\ M &=& F_X \, H / (4 \, \pi \, \EtaProp) \end{eqnarray} \end{subequations} With $F_X = m/4 \cdot 9.81\,\unit{m}/\unit{s}^2$ this results in $M$ as written into the table above. \subsection{Engine} So let's take a look at the engine's equations. {\tt src/mod\_fdm/power/engine\_dcm.cpp} reveals \begin{subequations} \begin{eqnarray} \label{f:MOTOR} \EtaSteller &=& 0.95 \\ U\vi{K} &=& \textrm{throttle} \cdot U \cdot \EtaSteller \\ U\vi{Gen} &=& \omega \cdot k\vi{M} \\ I\vi{M} &=& (U\vi{K} - U\vi{Gen}) / R\vi{I} \\ M\vi{M} &=& k\vi{M} \cdot I\vi{M} - k\vi{r} \cdot \omega - M\vi{r} \\ M\vi{r} &=& k\vi{M} \cdot I_0 \\ k\vi{r} &=& 0 \\ \end{eqnarray} \end{subequations} Which boils down to \begin{equation} M\vi{M} = k\vi{M} \cdot (\textrm{throttle} \cdot U \cdot 0.95 - \omega \cdot k\vi{M}) / R\vi{I} - I_0 \cdot k\vi{M} \end{equation} for us. There are three unknown parameters here and luckily I have three sets of data, which solves to $k_M=0.0131$ Vs, $R_I=0.1839\,\Omega$, $I_0=-4.013$\,A. Of course a negative $I_0$ is bullshit. Something wrong with the simulation equations? However, I continue and force $I_0$ to be zero and solve again. Due to three data sets, I get three solutions: $k\vi{M}$ = 0.0081483226538728\,Vs, $R\vi{I}$ = 0.39817956295345\,$\Omega$ \\ $k\vi{M}$ = 0.0085130006948808\,Vs, $R\vi{I}$ = 0.37102864543948\,$\Omega$ \\ $k\vi{M}$ = 0.0089455381882278\,Vs, $R\vi{I}$ = 0.34435633250623\,$\Omega$ \\ Now motor current and voltage used are right. Don't be surprised because current is high according to log output: this is the current flowing through the motor, not the one which has to be delivered by the battery. The latter is lower (we use PWM here). \section{Dynamics} I measured the real one's behaviour using step responses. This is dangerous and you might need special firmware! However, I did it and will use the results to tweak simulation parameters. I used a firmware which records raw sensor data of every control cycle. In this case motor voltage (as commanded to the controller) and rate gyro output is important. After turning a switch, it turns of the controller of the axis to be examined for a defined time (about 500\,ms in my case). Afterwards, commands a predefined voltage to this axis for a defined time (some hundred milliseconds). By turning the switch back, the process can be interrupted at any time. Of course you can only do this on a calm day. If you're out of luck, the copter already leaves its attitude while the commanded voltage is zero. However, it will do this once the predefined voltage is applied. React quickly, it will go down and crash otherwise. I tried getting the parameters from data gathered while the control loop was closed. This is not dangerous at all, but only gave sane parameters for rotation about the z-axis. For x-axis, my controller commands voltage like this: \begin{subequations} \label{f:U} \begin{eqnarray} u\vi{MotLeft} &=& u_0 + u\vi{ControllerX}\\ u\vi{MotRight} &=& u_0 - u\vi{ControllerX} \end{eqnarray} \end{subequations} y-axis is the same. So the controller is turned of for some time, $u\vi{ControllerX}$=0. Afterwards $u\vi{ControllerX}$=const for some time. Rotation rate around x-axis is recorded, let's call it $p$. For shortness, $u\vi{ControllerX}$=$u$. I searched for parameters to make the following equation fit measurements (in laplace domain): \begin{equation} s \, p = a \, u/(\tau\,s+1)^2 - b \, p \end{equation} For x and y I found $a$=20\,rad/s$^2$/V, $b$=0, $\tau$=15\,ms. For z I found $a$=5.3\,rad/s$^2$/V, $b$=0.5/s, $\tau$=5\,ms. $\tau$ is not that important and may be wrong here. \subsection{Motor} There is something undefined up to now: inertia of motor and propeller. I approximate that from the x axis transfer function. The motors acceleration is $M\vi{M} / J\vi{M}$; using equations~\eqref{f:MOTOR}: \begin{equation} \frac{d\,\omega}{dt} = k\vi{M}\,\left( U - \omega \, k\vi{M} \right) / (R\vi{I}\,J\vi{M}) \end{equation} Bringing that from time domain to laplace and solving for $\omega/U$ gives \begin{equation} \omega/U = 1/k\vi{M}^2 \, \frac{1}{(R\vi{I} \, J\vi{M} / k\vi{M}^2) \, s + 1} \end{equation} So there is a PT1 (I guess its called first order time lag in english) with $\tau=R\vi{I} \, J\vi{M} / k\vi{M}^2$. I assume the motor speed as proportional to the copter's rotational acceleration. But the motor's transfer function contains a PT1 while my copter's rotation transfer function (see above) contains a PT2. Well, I just say that a PT2 with $\tau\vi{pt2}$ is similar to a PT1 with $\tau\vi{pt1}=\tau\vi{pt2} \cdot 1.7$. Therefore, $15\,\unit{ms} \cdot 1.7=\tau \cdot 1.7=R\vi{I} \, J\vi{M}/k\vi{M}^2$. Solving this for $J\vi{M}$ gives $J\vi{M}=5\cdot 10^{-6} \, \unit{kg} \, \unit{m}^2$. Of course, all this assumed that only the motor's inertia is active here, but there is the propeller's inertia, too. However, for the simulation, only their sum is important, therefore I set {\tt propeller.J=0} and {\tt engine.J\_M=5E-6}. The sum of both inertias could of course also be measured by applying a fixed voltage to the motor and recording its rotational speed. However, when getting to much details from the real system very accurately, keep in mind that CRRCSim doesn't model everything that accurately -- so using 'wrong' values might result in a more realistic simulation. In the case of a multicopter this is very important, because for example the time lag from measuring a rotation rate, calculating the controller, transferring a new setpoint to the motor's speed controller, until this speed controller applies the new voltage to the motor does depend on software heavily. And it depends on software of at least two different embedded electronics usually (main flight control and brushless controller). Furthermore, different copter firmwares use different filters here and there and so on... So in this regard CRRCSim's multicopter model can't realistically model every real one. It would be possible to do, but I guess noone would be willing to find all those parameters... \subsection{Aerodynamics} For yaw I found $b$=0.5/s. The simulator uses \begin{subequations} \begin{eqnarray} \frac{d\,r}{dt} &=& M\vi{z} \, \frac{I\vi{xx}}{I\vi{xx}\,I\vi{zz} - I\vi{xz}^2}\\ M\vi{z} &=& - \texttt{yaw.damp1} \cdot r - \texttt{yaw.damp2} \cdot |r| \, r \end{eqnarray} \end{subequations} as can be seen in {\tt EOM01::ls\_accel()} and {\tt CRRC\_AirplaneSim\_MCopter01::aero()}. Therefore, \begin{equation} \texttt{yaw.damp1} = b \, \frac{I\vi{xx}\,I\vi{zz} - I\vi{xz}^2}{I\vi{xx}} \end{equation} which results in {\tt yaw.damp1=0.00341, yaw.damp2=0}. Although I found $b$=0 for nick and roll, {\tt roll.damp1=0.0009}, {\tt roll.damp2=0} because the simulation likes at least some damping. I have not thought about something to measure {\tt speed.damp}, so this is done by try and error. \section{Controllers} Well, we're not through yet. Physics are defined now, but the control loop of the copter is not\dots Looking at the source, any controllers output means how much voltage is applied in the sense of equation~\eqref{f:U} with \begin{equation} u\vi{ControllerX} = \textrm{URel} \cdot U\vi{Rel} = \textrm{URel} \cdot U\vi{Battery0} \cdot 0.7 \end{equation} So if the controller output is one, the voltage $u\vi{ControllerX}$ that will be applied is 0.7 times the voltage of the fully charged battery. The controllers action will be independent of battery voltage as long as it is at least 0.7 times the full charge voltage and the controller output is smaller than one. \subsection{Controller type "Omega"} It gives rate controlled behaviour. Because it does not know about the scaling with $U\vi{Battery0} \cdot 0.7$, its parameters depend on this value. Using variable names for roll axis, with $p\vi{sp}$ being the setpoint and $p\vi{pv}$ being the process value, its output is \begin{subequations} \begin{eqnarray} p\vi{d} &=& p\vi{sp} - p\vi{pv}\\ u\vi{ControllerX} &=& U\vi{Battery0} \cdot 0.7 \left( K\vi{P} \, p\vi{d} + K\vi{D} \, \frac{d\,p\vi{pv}}{dt} + K\vi{I} \, \int p\vi{d} \right) \end{eqnarray} \end{subequations} Compared to the settings of my real copter I had to halve $K\vi{D}$, otherwise the simulation got unstable. To the controller, maximum stick input is 0.5 (just like every other signed stick input in CRRCSim) and $p\vi{sp} = {\tt stick} \cdot ${\tt scale}. If {\tt scale\_roll\_pitch.exp} $>$ 1, a special scaling is used for roll and nick to allow flips and loopings: \begin{equation} p\vi{sp} = \texttt{scale} \left( \texttt{a} \cdot \texttt{stick} + \texttt{b} \cdot \texttt{stick}^\texttt{exp} \right) \end{equation} Here {\tt a}, {\tt b} and {\tt exp} are from the {\tt scale\_roll\_pitch} section of the input file. \clearpage \begin{thebibliography}{99} \bibitem{l:C_FILE} CRRCSim fixed wing file format description, CRRCSim installation: {\tt documentation/file\_format/index.html} \bibitem{l:C_POWER} CRRCSim power and propulsion system description, CRRCSim installation: {\tt documentation/power\_propulsion/power\_propulsion.html} \end{thebibliography} \end{document}