├── .gitignore ├── Documentation ├── AddFramework.png └── RunScript.png ├── LICENSE.md ├── MadgwickAHRS.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── MadgwickAHRS.xcscheme ├── MadgwickAHRS ├── CoreMotionMadgwickTestDriver.h ├── CoreMotionMadgwickTestDriver.m ├── CoreMotionMadgwickTestDriverDelegate.h ├── Info.plist ├── MadgwickAHRS.h ├── MadgwickSensorFusion.h └── MadgwickSensorFusion.m ├── MadgwickAHRSTests ├── Info.plist └── MadgwickAHRSTests.m └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OS X 2 | *.DS_Store 3 | 4 | 5 | # Xcode 6 | *.pbxuser 7 | *.mode2v3 8 | *.mode1v3 9 | *.perspective 10 | *.perspectivev3 11 | *.xcuserstate 12 | xcuserdata/ 13 | 14 | ## Generic Files To Ignore 15 | *~ 16 | *.swp 17 | *.out 18 | -------------------------------------------------------------------------------- /Documentation/AddFramework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softwarenerd/MadgwickAHRS/498dbc02862ce4037d966660108b94e21e2cbfd5/Documentation/AddFramework.png -------------------------------------------------------------------------------- /Documentation/RunScript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softwarenerd/MadgwickAHRS/498dbc02862ce4037d966660108b94e21e2cbfd5/Documentation/RunScript.png -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 [Free Software Foundation, Inc.](http://fsf.org/) 5 | 6 | Everyone is permitted to copy and distribute verbatim copies of this license 7 | document, but changing it is not allowed. 8 | 9 | ## Preamble 10 | 11 | The GNU General Public License is a free, copyleft license for software and 12 | other kinds of works. 13 | 14 | The licenses for most software and other practical works are designed to take 15 | away your freedom to share and change the works. By contrast, the GNU General 16 | Public License is intended to guarantee your freedom to share and change all 17 | versions of a program--to make sure it remains free software for all its users. 18 | We, the Free Software Foundation, use the GNU General Public License for most 19 | of our software; it applies also to any other work released this way by its 20 | authors. You can apply it to your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not price. Our 23 | General Public Licenses are designed to make sure that you have the freedom to 24 | distribute copies of free software (and charge for them if you wish), that you 25 | receive source code or can get it if you want it, that you can change the 26 | software or use pieces of it in new free programs, and that you know you can do 27 | these things. 28 | 29 | To protect your rights, we need to prevent others from denying you these rights 30 | or asking you to surrender the rights. Therefore, you have certain 31 | responsibilities if you distribute copies of the software, or if you modify it: 32 | responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether gratis or for 35 | a fee, you must pass on to the recipients the same freedoms that you received. 36 | You must make sure that they, too, receive or can get the source code. And you 37 | must show them these terms so they know their rights. 38 | 39 | Developers that use the GNU GPL protect your rights with two steps: 40 | 41 | 1. assert copyright on the software, and 42 | 2. offer you this License giving you legal permission to copy, distribute 43 | and/or modify it. 44 | 45 | For the developers' and authors' protection, the GPL clearly explains that 46 | there is no warranty for this free software. For both users' and authors' sake, 47 | the GPL requires that modified versions be marked as changed, so that their 48 | problems will not be attributed erroneously to authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run modified 51 | versions of the software inside them, although the manufacturer can do so. This 52 | is fundamentally incompatible with the aim of protecting users' freedom to 53 | change the software. The systematic pattern of such abuse occurs in the area of 54 | products for individuals to use, which is precisely where it is most 55 | unacceptable. Therefore, we have designed this version of the GPL to prohibit 56 | the practice for those products. If such problems arise substantially in other 57 | domains, we stand ready to extend this provision to those domains in future 58 | versions of the GPL, as needed to protect the freedom of users. 59 | 60 | Finally, every program is threatened constantly by software patents. States 61 | should not allow patents to restrict development and use of software on 62 | general-purpose computers, but in those that do, we wish to avoid the special 63 | danger that patents applied to a free program could make it effectively 64 | proprietary. To prevent this, the GPL assures that patents cannot be used to 65 | render the program non-free. 66 | 67 | The precise terms and conditions for copying, distribution and modification 68 | follow. 69 | 70 | ## TERMS AND CONDITIONS 71 | 72 | ### 0. Definitions. 73 | 74 | *This License* refers to version 3 of the GNU General Public License. 75 | 76 | *Copyright* also means copyright-like laws that apply to other kinds of works, 77 | such as semiconductor masks. 78 | 79 | *The Program* refers to any copyrightable work licensed under this License. 80 | Each licensee is addressed as *you*. *Licensees* and *recipients* may be 81 | individuals or organizations. 82 | 83 | To *modify* a work means to copy from or adapt all or part of the work in a 84 | fashion requiring copyright permission, other than the making of an exact copy. 85 | The resulting work is called a *modified version* of the earlier work or a work 86 | *based on* the earlier work. 87 | 88 | A *covered work* means either the unmodified Program or a work based on the 89 | Program. 90 | 91 | To *propagate* a work means to do anything with it that, without permission, 92 | would make you directly or secondarily liable for infringement under applicable 93 | copyright law, except executing it on a computer or modifying a private copy. 94 | Propagation includes copying, distribution (with or without modification), 95 | making available to the public, and in some countries other activities as well. 96 | 97 | To *convey* a work means any kind of propagation that enables other parties to 98 | make or receive copies. Mere interaction with a user through a computer 99 | network, with no transfer of a copy, is not conveying. 100 | 101 | An interactive user interface displays *Appropriate Legal Notices* to the 102 | extent that it includes a convenient and prominently visible feature that 103 | 104 | 1. displays an appropriate copyright notice, and 105 | 2. tells the user that there is no warranty for the work (except to the 106 | extent that warranties are provided), that licensees may convey the work 107 | under this License, and how to view a copy of this License. 108 | 109 | If the interface presents a list of user commands or options, such as a menu, a 110 | prominent item in the list meets this criterion. 111 | 112 | ### 1. Source Code. 113 | 114 | The *source code* for a work means the preferred form of the work for making 115 | modifications to it. *Object code* means any non-source form of a work. 116 | 117 | A *Standard Interface* means an interface that either is an official standard 118 | defined by a recognized standards body, or, in the case of interfaces specified 119 | for a particular programming language, one that is widely used among developers 120 | working in that language. 121 | 122 | The *System Libraries* of an executable work include anything, other than the 123 | work as a whole, that (a) is included in the normal form of packaging a Major 124 | Component, but which is not part of that Major Component, and (b) serves only 125 | to enable use of the work with that Major Component, or to implement a Standard 126 | Interface for which an implementation is available to the public in source code 127 | form. A *Major Component*, in this context, means a major essential component 128 | (kernel, window system, and so on) of the specific operating system (if any) on 129 | which the executable work runs, or a compiler used to produce the work, or an 130 | object code interpreter used to run it. 131 | 132 | The *Corresponding Source* for a work in object code form means all the source 133 | code needed to generate, install, and (for an executable work) run the object 134 | code and to modify the work, including scripts to control those activities. 135 | However, it does not include the work's System Libraries, or general-purpose 136 | tools or generally available free programs which are used unmodified in 137 | performing those activities but which are not part of the work. For example, 138 | Corresponding Source includes interface definition files associated with source 139 | files for the work, and the source code for shared libraries and dynamically 140 | linked subprograms that the work is specifically designed to require, such as 141 | by intimate data communication or control flow between those subprograms and 142 | other parts of the work. 143 | 144 | The Corresponding Source need not include anything that users can regenerate 145 | automatically from other parts of the Corresponding Source. 146 | 147 | The Corresponding Source for a work in source code form is that same work. 148 | 149 | ### 2. Basic Permissions. 150 | 151 | All rights granted under this License are granted for the term of copyright on 152 | the Program, and are irrevocable provided the stated conditions are met. This 153 | License explicitly affirms your unlimited permission to run the unmodified 154 | Program. The output from running a covered work is covered by this License only 155 | if the output, given its content, constitutes a covered work. This License 156 | acknowledges your rights of fair use or other equivalent, as provided by 157 | copyright law. 158 | 159 | You may make, run and propagate covered works that you do not convey, without 160 | conditions so long as your license otherwise remains in force. You may convey 161 | covered works to others for the sole purpose of having them make modifications 162 | exclusively for you, or provide you with facilities for running those works, 163 | provided that you comply with the terms of this License in conveying all 164 | material for which you do not control copyright. Those thus making or running 165 | the covered works for you must do so exclusively on your behalf, under your 166 | direction and control, on terms that prohibit them from making any copies of 167 | your copyrighted material outside their relationship with you. 168 | 169 | Conveying under any other circumstances is permitted solely under the 170 | conditions stated below. Sublicensing is not allowed; section 10 makes it 171 | unnecessary. 172 | 173 | ### 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 174 | 175 | No covered work shall be deemed part of an effective technological measure 176 | under any applicable law fulfilling obligations under article 11 of the WIPO 177 | copyright treaty adopted on 20 December 1996, or similar laws prohibiting or 178 | restricting circumvention of such measures. 179 | 180 | When you convey a covered work, you waive any legal power to forbid 181 | circumvention of technological measures to the extent such circumvention is 182 | effected by exercising rights under this License with respect to the covered 183 | work, and you disclaim any intention to limit operation or modification of the 184 | work as a means of enforcing, against the work's users, your or third parties' 185 | legal rights to forbid circumvention of technological measures. 186 | 187 | ### 4. Conveying Verbatim Copies. 188 | 189 | You may convey verbatim copies of the Program's source code as you receive it, 190 | in any medium, provided that you conspicuously and appropriately publish on 191 | each copy an appropriate copyright notice; keep intact all notices stating that 192 | this License and any non-permissive terms added in accord with section 7 apply 193 | to the code; keep intact all notices of the absence of any warranty; and give 194 | all recipients a copy of this License along with the Program. 195 | 196 | You may charge any price or no price for each copy that you convey, and you may 197 | offer support or warranty protection for a fee. 198 | 199 | ### 5. Conveying Modified Source Versions. 200 | 201 | You may convey a work based on the Program, or the modifications to produce it 202 | from the Program, in the form of source code under the terms of section 4, 203 | provided that you also meet all of these conditions: 204 | 205 | - a) The work must carry prominent notices stating that you modified it, and 206 | giving a relevant date. 207 | - b) The work must carry prominent notices stating that it is released under 208 | this License and any conditions added under section 7. This requirement 209 | modifies the requirement in section 4 to *keep intact all notices*. 210 | - c) You must license the entire work, as a whole, under this License to 211 | anyone who comes into possession of a copy. This License will therefore 212 | apply, along with any applicable section 7 additional terms, to the whole 213 | of the work, and all its parts, regardless of how they are packaged. This 214 | License gives no permission to license the work in any other way, but it 215 | does not invalidate such permission if you have separately received it. 216 | - d) If the work has interactive user interfaces, each must display 217 | Appropriate Legal Notices; however, if the Program has interactive 218 | interfaces that do not display Appropriate Legal Notices, your work need 219 | not make them do so. 220 | 221 | A compilation of a covered work with other separate and independent works, 222 | which are not by their nature extensions of the covered work, and which are not 223 | combined with it such as to form a larger program, in or on a volume of a 224 | storage or distribution medium, is called an *aggregate* if the compilation and 225 | its resulting copyright are not used to limit the access or legal rights of the 226 | compilation's users beyond what the individual works permit. Inclusion of a 227 | covered work in an aggregate does not cause this License to apply to the other 228 | parts of the aggregate. 229 | 230 | ### 6. Conveying Non-Source Forms. 231 | 232 | You may convey a covered work in object code form under the terms of sections 4 233 | and 5, provided that you also convey the machine-readable Corresponding Source 234 | under the terms of this License, in one of these ways: 235 | 236 | - a) Convey the object code in, or embodied in, a physical product (including 237 | a physical distribution medium), accompanied by the Corresponding Source 238 | fixed on a durable physical medium customarily used for software 239 | interchange. 240 | - b) Convey the object code in, or embodied in, a physical product (including 241 | a physical distribution medium), accompanied by a written offer, valid for 242 | at least three years and valid for as long as you offer spare parts or 243 | customer support for that product model, to give anyone who possesses the 244 | object code either 245 | 1. a copy of the Corresponding Source for all the software in the product 246 | that is covered by this License, on a durable physical medium 247 | customarily used for software interchange, for a price no more than your 248 | reasonable cost of physically performing this conveying of source, or 249 | 2. access to copy the Corresponding Source from a network server at no 250 | charge. 251 | - c) Convey individual copies of the object code with a copy of the written 252 | offer to provide the Corresponding Source. This alternative is allowed only 253 | occasionally and noncommercially, and only if you received the object code 254 | with such an offer, in accord with subsection 6b. 255 | - d) Convey the object code by offering access from a designated place 256 | (gratis or for a charge), and offer equivalent access to the Corresponding 257 | Source in the same way through the same place at no further charge. You 258 | need not require recipients to copy the Corresponding Source along with the 259 | object code. If the place to copy the object code is a network server, the 260 | Corresponding Source may be on a different server operated by you or a 261 | third party) that supports equivalent copying facilities, provided you 262 | maintain clear directions next to the object code saying where to find the 263 | Corresponding Source. Regardless of what server hosts the Corresponding 264 | Source, you remain obligated to ensure that it is available for as long as 265 | needed to satisfy these requirements. 266 | - e) Convey the object code using peer-to-peer transmission, provided you 267 | inform other peers where the object code and Corresponding Source of the 268 | work are being offered to the general public at no charge under subsection 269 | 6d. 270 | 271 | A separable portion of the object code, whose source code is excluded from the 272 | Corresponding Source as a System Library, need not be included in conveying the 273 | object code work. 274 | 275 | A *User Product* is either 276 | 277 | 1. a *consumer product*, which means any tangible personal property which is 278 | normally used for personal, family, or household purposes, or 279 | 2. anything designed or sold for incorporation into a dwelling. 280 | 281 | In determining whether a product is a consumer product, doubtful cases shall be 282 | resolved in favor of coverage. For a particular product received by a 283 | particular user, *normally used* refers to a typical or common use of that 284 | class of product, regardless of the status of the particular user or of the way 285 | in which the particular user actually uses, or expects or is expected to use, 286 | the product. A product is a consumer product regardless of whether the product 287 | has substantial commercial, industrial or non-consumer uses, unless such uses 288 | represent the only significant mode of use of the product. 289 | 290 | *Installation Information* for a User Product means any methods, procedures, 291 | authorization keys, or other information required to install and execute 292 | modified versions of a covered work in that User Product from a modified 293 | version of its Corresponding Source. The information must suffice to ensure 294 | that the continued functioning of the modified object code is in no case 295 | prevented or interfered with solely because modification has been made. 296 | 297 | If you convey an object code work under this section in, or with, or 298 | specifically for use in, a User Product, and the conveying occurs as part of a 299 | transaction in which the right of possession and use of the User Product is 300 | transferred to the recipient in perpetuity or for a fixed term (regardless of 301 | how the transaction is characterized), the Corresponding Source conveyed under 302 | this section must be accompanied by the Installation Information. But this 303 | requirement does not apply if neither you nor any third party retains the 304 | ability to install modified object code on the User Product (for example, the 305 | work has been installed in ROM). 306 | 307 | The requirement to provide Installation Information does not include a 308 | requirement to continue to provide support service, warranty, or updates for a 309 | work that has been modified or installed by the recipient, or for the User 310 | Product in which it has been modified or installed. Access to a network may be 311 | denied when the modification itself materially and adversely affects the 312 | operation of the network or violates the rules and protocols for communication 313 | across the network. 314 | 315 | Corresponding Source conveyed, and Installation Information provided, in accord 316 | with this section must be in a format that is publicly documented (and with an 317 | implementation available to the public in source code form), and must require 318 | no special password or key for unpacking, reading or copying. 319 | 320 | ### 7. Additional Terms. 321 | 322 | *Additional permissions* are terms that supplement the terms of this License by 323 | making exceptions from one or more of its conditions. Additional permissions 324 | that are applicable to the entire Program shall be treated as though they were 325 | included in this License, to the extent that they are valid under applicable 326 | law. If additional permissions apply only to part of the Program, that part may 327 | be used separately under those permissions, but the entire Program remains 328 | governed by this License without regard to the additional permissions. 329 | 330 | When you convey a copy of a covered work, you may at your option remove any 331 | additional permissions from that copy, or from any part of it. (Additional 332 | permissions may be written to require their own removal in certain cases when 333 | you modify the work.) You may place additional permissions on material, added 334 | by you to a covered work, for which you have or can give appropriate copyright 335 | permission. 336 | 337 | Notwithstanding any other provision of this License, for material you add to a 338 | covered work, you may (if authorized by the copyright holders of that material) 339 | supplement the terms of this License with terms: 340 | 341 | - a) Disclaiming warranty or limiting liability differently from the terms of 342 | sections 15 and 16 of this License; or 343 | - b) Requiring preservation of specified reasonable legal notices or author 344 | attributions in that material or in the Appropriate Legal Notices displayed 345 | by works containing it; or 346 | - c) Prohibiting misrepresentation of the origin of that material, or 347 | requiring that modified versions of such material be marked in reasonable 348 | ways as different from the original version; or 349 | - d) Limiting the use for publicity purposes of names of licensors or authors 350 | of the material; or 351 | - e) Declining to grant rights under trademark law for use of some trade 352 | names, trademarks, or service marks; or 353 | - f) Requiring indemnification of licensors and authors of that material by 354 | anyone who conveys the material (or modified versions of it) with 355 | contractual assumptions of liability to the recipient, for any liability 356 | that these contractual assumptions directly impose on those licensors and 357 | authors. 358 | 359 | All other non-permissive additional terms are considered *further restrictions* 360 | within the meaning of section 10. If the Program as you received it, or any 361 | part of it, contains a notice stating that it is governed by this License along 362 | with a term that is a further restriction, you may remove that term. If a 363 | license document contains a further restriction but permits relicensing or 364 | conveying under this License, you may add to a covered work material governed 365 | by the terms of that license document, provided that the further restriction 366 | does not survive such relicensing or conveying. 367 | 368 | If you add terms to a covered work in accord with this section, you must place, 369 | in the relevant source files, a statement of the additional terms that apply to 370 | those files, or a notice indicating where to find the applicable terms. 371 | 372 | Additional terms, permissive or non-permissive, may be stated in the form of a 373 | separately written license, or stated as exceptions; the above requirements 374 | apply either way. 375 | 376 | ### 8. Termination. 377 | 378 | You may not propagate or modify a covered work except as expressly provided 379 | under this License. Any attempt otherwise to propagate or modify it is void, 380 | and will automatically terminate your rights under this License (including any 381 | patent licenses granted under the third paragraph of section 11). 382 | 383 | However, if you cease all violation of this License, then your license from a 384 | particular copyright holder is reinstated 385 | 386 | - a) provisionally, unless and until the copyright holder explicitly and 387 | finally terminates your license, and 388 | - b) permanently, if the copyright holder fails to notify you of the 389 | violation by some reasonable means prior to 60 days after the cessation. 390 | 391 | Moreover, your license from a particular copyright holder is reinstated 392 | permanently if the copyright holder notifies you of the violation by some 393 | reasonable means, this is the first time you have received notice of violation 394 | of this License (for any work) from that copyright holder, and you cure the 395 | violation prior to 30 days after your receipt of the notice. 396 | 397 | Termination of your rights under this section does not terminate the licenses 398 | of parties who have received copies or rights from you under this License. If 399 | your rights have been terminated and not permanently reinstated, you do not 400 | qualify to receive new licenses for the same material under section 10. 401 | 402 | ### 9. Acceptance Not Required for Having Copies. 403 | 404 | You are not required to accept this License in order to receive or run a copy 405 | of the Program. Ancillary propagation of a covered work occurring solely as a 406 | consequence of using peer-to-peer transmission to receive a copy likewise does 407 | not require acceptance. However, nothing other than this License grants you 408 | permission to propagate or modify any covered work. These actions infringe 409 | copyright if you do not accept this License. Therefore, by modifying or 410 | propagating a covered work, you indicate your acceptance of this License to do 411 | so. 412 | 413 | ### 10. Automatic Licensing of Downstream Recipients. 414 | 415 | Each time you convey a covered work, the recipient automatically receives a 416 | license from the original licensors, to run, modify and propagate that work, 417 | subject to this License. You are not responsible for enforcing compliance by 418 | third parties with this License. 419 | 420 | An *entity transaction* is a transaction transferring control of an 421 | organization, or substantially all assets of one, or subdividing an 422 | organization, or merging organizations. If propagation of a covered work 423 | results from an entity transaction, each party to that transaction who receives 424 | a copy of the work also receives whatever licenses to the work the party's 425 | predecessor in interest had or could give under the previous paragraph, plus a 426 | right to possession of the Corresponding Source of the work from the 427 | predecessor in interest, if the predecessor has it or can get it with 428 | reasonable efforts. 429 | 430 | You may not impose any further restrictions on the exercise of the rights 431 | granted or affirmed under this License. For example, you may not impose a 432 | license fee, royalty, or other charge for exercise of rights granted under this 433 | License, and you may not initiate litigation (including a cross-claim or 434 | counterclaim in a lawsuit) alleging that any patent claim is infringed by 435 | making, using, selling, offering for sale, or importing the Program or any 436 | portion of it. 437 | 438 | ### 11. Patents. 439 | 440 | A *contributor* is a copyright holder who authorizes use under this License of 441 | the Program or a work on which the Program is based. The work thus licensed is 442 | called the contributor's *contributor version*. 443 | 444 | A contributor's *essential patent claims* are all patent claims owned or 445 | controlled by the contributor, whether already acquired or hereafter acquired, 446 | that would be infringed by some manner, permitted by this License, of making, 447 | using, or selling its contributor version, but do not include claims that would 448 | be infringed only as a consequence of further modification of the contributor 449 | version. For purposes of this definition, *control* includes the right to grant 450 | patent sublicenses in a manner consistent with the requirements of this 451 | License. 452 | 453 | Each contributor grants you a non-exclusive, worldwide, royalty-free patent 454 | license under the contributor's essential patent claims, to make, use, sell, 455 | offer for sale, import and otherwise run, modify and propagate the contents of 456 | its contributor version. 457 | 458 | In the following three paragraphs, a *patent license* is any express agreement 459 | or commitment, however denominated, not to enforce a patent (such as an express 460 | permission to practice a patent or covenant not to sue for patent 461 | infringement). To *grant* such a patent license to a party means to make such 462 | an agreement or commitment not to enforce a patent against the party. 463 | 464 | If you convey a covered work, knowingly relying on a patent license, and the 465 | Corresponding Source of the work is not available for anyone to copy, free of 466 | charge and under the terms of this License, through a publicly available 467 | network server or other readily accessible means, then you must either 468 | 469 | 1. cause the Corresponding Source to be so available, or 470 | 2. arrange to deprive yourself of the benefit of the patent license for this 471 | particular work, or 472 | 3. arrange, in a manner consistent with the requirements of this License, to 473 | extend the patent license to downstream recipients. 474 | 475 | *Knowingly relying* means you have actual knowledge that, but for the patent 476 | license, your conveying the covered work in a country, or your recipient's use 477 | of the covered work in a country, would infringe one or more identifiable 478 | patents in that country that you have reason to believe are valid. 479 | 480 | If, pursuant to or in connection with a single transaction or arrangement, you 481 | convey, or propagate by procuring conveyance of, a covered work, and grant a 482 | patent license to some of the parties receiving the covered work authorizing 483 | them to use, propagate, modify or convey a specific copy of the covered work, 484 | then the patent license you grant is automatically extended to all recipients 485 | of the covered work and works based on it. 486 | 487 | A patent license is *discriminatory* if it does not include within the scope of 488 | its coverage, prohibits the exercise of, or is conditioned on the non-exercise 489 | of one or more of the rights that are specifically granted under this License. 490 | You may not convey a covered work if you are a party to an arrangement with a 491 | third party that is in the business of distributing software, under which you 492 | make payment to the third party based on the extent of your activity of 493 | conveying the work, and under which the third party grants, to any of the 494 | parties who would receive the covered work from you, a discriminatory patent 495 | license 496 | 497 | - a) in connection with copies of the covered work conveyed by you (or copies 498 | made from those copies), or 499 | - b) primarily for and in connection with specific products or compilations 500 | that contain the covered work, unless you entered into that arrangement, or 501 | that patent license was granted, prior to 28 March 2007. 502 | 503 | Nothing in this License shall be construed as excluding or limiting any implied 504 | license or other defenses to infringement that may otherwise be available to 505 | you under applicable patent law. 506 | 507 | ### 12. No Surrender of Others' Freedom. 508 | 509 | If conditions are imposed on you (whether by court order, agreement or 510 | otherwise) that contradict the conditions of this License, they do not excuse 511 | you from the conditions of this License. If you cannot convey a covered work so 512 | as to satisfy simultaneously your obligations under this License and any other 513 | pertinent obligations, then as a consequence you may not convey it at all. For 514 | example, if you agree to terms that obligate you to collect a royalty for 515 | further conveying from those to whom you convey the Program, the only way you 516 | could satisfy both those terms and this License would be to refrain entirely 517 | from conveying the Program. 518 | 519 | ### 13. Use with the GNU Affero General Public License. 520 | 521 | Notwithstanding any other provision of this License, you have permission to 522 | link or combine any covered work with a work licensed under version 3 of the 523 | GNU Affero General Public License into a single combined work, and to convey 524 | the resulting work. The terms of this License will continue to apply to the 525 | part which is the covered work, but the special requirements of the GNU Affero 526 | General Public License, section 13, concerning interaction through a network 527 | will apply to the combination as such. 528 | 529 | ### 14. Revised Versions of this License. 530 | 531 | The Free Software Foundation may publish revised and/or new versions of the GNU 532 | General Public License from time to time. Such new versions will be similar in 533 | spirit to the present version, but may differ in detail to address new problems 534 | or concerns. 535 | 536 | Each version is given a distinguishing version number. If the Program specifies 537 | that a certain numbered version of the GNU General Public License *or any later 538 | version* applies to it, you have the option of following the terms and 539 | conditions either of that numbered version or of any later version published by 540 | the Free Software Foundation. If the Program does not specify a version number 541 | of the GNU General Public License, you may choose any version ever published by 542 | the Free Software Foundation. 543 | 544 | If the Program specifies that a proxy can decide which future versions of the 545 | GNU General Public License can be used, that proxy's public statement of 546 | acceptance of a version permanently authorizes you to choose that version for 547 | the Program. 548 | 549 | Later license versions may give you additional or different permissions. 550 | However, no additional obligations are imposed on any author or copyright 551 | holder as a result of your choosing to follow a later version. 552 | 553 | ### 15. Disclaimer of Warranty. 554 | 555 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE 556 | LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER 557 | PARTIES PROVIDE THE PROGRAM *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER 558 | EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 559 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE 560 | QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE 561 | DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR 562 | CORRECTION. 563 | 564 | ### 16. Limitation of Liability. 565 | 566 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY 567 | COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS 568 | PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, 569 | INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE 570 | THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED 571 | INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE 572 | PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY 573 | HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 574 | 575 | ### 17. Interpretation of Sections 15 and 16. 576 | 577 | If the disclaimer of warranty and limitation of liability provided above cannot 578 | be given local legal effect according to their terms, reviewing courts shall 579 | apply local law that most closely approximates an absolute waiver of all civil 580 | liability in connection with the Program, unless a warranty or assumption of 581 | liability accompanies a copy of the Program in return for a fee. 582 | 583 | ## END OF TERMS AND CONDITIONS ### 584 | 585 | ### How to Apply These Terms to Your New Programs 586 | 587 | If you develop a new program, and you want it to be of the greatest possible 588 | use to the public, the best way to achieve this is to make it free software 589 | which everyone can redistribute and change under these terms. 590 | 591 | To do so, attach the following notices to the program. It is safest to attach 592 | them to the start of each source file to most effectively state the exclusion 593 | of warranty; and each file should have at least the *copyright* line and a 594 | pointer to where the full notice is found. 595 | 596 | 597 | Copyright (C) 598 | 599 | This program is free software: you can redistribute it and/or modify 600 | it under the terms of the GNU General Public License as published by 601 | the Free Software Foundation, either version 3 of the License, or 602 | (at your option) any later version. 603 | 604 | This program is distributed in the hope that it will be useful, 605 | but WITHOUT ANY WARRANTY; without even the implied warranty of 606 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 607 | GNU General Public License for more details. 608 | 609 | You should have received a copy of the GNU General Public License 610 | along with this program. If not, see . 611 | 612 | Also add information on how to contact you by electronic and paper mail. 613 | 614 | If the program does terminal interaction, make it output a short notice like 615 | this when it starts in an interactive mode: 616 | 617 | Copyright (C) 618 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 619 | This is free software, and you are welcome to redistribute it 620 | under certain conditions; type `show c' for details. 621 | 622 | The hypothetical commands `show w` and `show c` should show the appropriate 623 | parts of the General Public License. Of course, your program's commands might 624 | be different; for a GUI interface, you would use an *about box*. 625 | 626 | You should also get your employer (if you work as a programmer) or school, if 627 | any, to sign a *copyright disclaimer* for the program, if necessary. For more 628 | information on this, and how to apply and follow the GNU GPL, see 629 | [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). 630 | 631 | The GNU General Public License does not permit incorporating your program into 632 | proprietary programs. If your program is a subroutine library, you may consider 633 | it more useful to permit linking proprietary applications with the library. If 634 | this is what you want to do, use the GNU Lesser General Public License instead 635 | of this License. But first, please read 636 | [http://www.gnu.org/philosophy/why-not-lgpl.html](http://www.gnu.org/philosophy/why-not-lgpl.html). 637 | -------------------------------------------------------------------------------- /MadgwickAHRS.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D3623B7B1D0C5B9B0015FFF3 /* CoreMotionMadgwickTestDriverDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = D3623B7A1D0C568C0015FFF3 /* CoreMotionMadgwickTestDriverDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | D38B14921D0B89DD00C88130 /* MadgwickAHRS.h in Headers */ = {isa = PBXBuildFile; fileRef = D38B14911D0B89DD00C88130 /* MadgwickAHRS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 12 | D38B14991D0B89DD00C88130 /* MadgwickAHRS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D38B148E1D0B89DD00C88130 /* MadgwickAHRS.framework */; }; 13 | D38B149E1D0B89DD00C88130 /* MadgwickAHRSTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D38B149D1D0B89DD00C88130 /* MadgwickAHRSTests.m */; }; 14 | D38B14AA1D0B8A0000C88130 /* MadgwickSensorFusion.h in Headers */ = {isa = PBXBuildFile; fileRef = D38B14A81D0B8A0000C88130 /* MadgwickSensorFusion.h */; settings = {ATTRIBUTES = (Public, ); }; }; 15 | D38B14AB1D0B8A0000C88130 /* MadgwickSensorFusion.m in Sources */ = {isa = PBXBuildFile; fileRef = D38B14A91D0B8A0000C88130 /* MadgwickSensorFusion.m */; }; 16 | D38B14AE1D0B8C7D00C88130 /* CoreMotionMadgwickTestDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = D38B14AC1D0B8C7D00C88130 /* CoreMotionMadgwickTestDriver.h */; settings = {ATTRIBUTES = (Public, ); }; }; 17 | D38B14AF1D0B8C7D00C88130 /* CoreMotionMadgwickTestDriver.m in Sources */ = {isa = PBXBuildFile; fileRef = D38B14AD1D0B8C7D00C88130 /* CoreMotionMadgwickTestDriver.m */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXContainerItemProxy section */ 21 | D38B149A1D0B89DD00C88130 /* PBXContainerItemProxy */ = { 22 | isa = PBXContainerItemProxy; 23 | containerPortal = D38B14851D0B89DD00C88130 /* Project object */; 24 | proxyType = 1; 25 | remoteGlobalIDString = D38B148D1D0B89DD00C88130; 26 | remoteInfo = MadgwickAHRS; 27 | }; 28 | /* End PBXContainerItemProxy section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | D3623B7A1D0C568C0015FFF3 /* CoreMotionMadgwickTestDriverDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CoreMotionMadgwickTestDriverDelegate.h; sourceTree = ""; }; 32 | D38B148E1D0B89DD00C88130 /* MadgwickAHRS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MadgwickAHRS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | D38B14911D0B89DD00C88130 /* MadgwickAHRS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MadgwickAHRS.h; sourceTree = ""; }; 34 | D38B14931D0B89DD00C88130 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | D38B14981D0B89DD00C88130 /* MadgwickAHRSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MadgwickAHRSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 36 | D38B149D1D0B89DD00C88130 /* MadgwickAHRSTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MadgwickAHRSTests.m; sourceTree = ""; }; 37 | D38B149F1D0B89DD00C88130 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 38 | D38B14A81D0B8A0000C88130 /* MadgwickSensorFusion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MadgwickSensorFusion.h; sourceTree = ""; }; 39 | D38B14A91D0B8A0000C88130 /* MadgwickSensorFusion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MadgwickSensorFusion.m; sourceTree = ""; }; 40 | D38B14AC1D0B8C7D00C88130 /* CoreMotionMadgwickTestDriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoreMotionMadgwickTestDriver.h; sourceTree = ""; }; 41 | D38B14AD1D0B8C7D00C88130 /* CoreMotionMadgwickTestDriver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CoreMotionMadgwickTestDriver.m; sourceTree = ""; }; 42 | /* End PBXFileReference section */ 43 | 44 | /* Begin PBXFrameworksBuildPhase section */ 45 | D38B148A1D0B89DD00C88130 /* Frameworks */ = { 46 | isa = PBXFrameworksBuildPhase; 47 | buildActionMask = 2147483647; 48 | files = ( 49 | ); 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | D38B14951D0B89DD00C88130 /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 2147483647; 55 | files = ( 56 | D38B14991D0B89DD00C88130 /* MadgwickAHRS.framework in Frameworks */, 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | /* End PBXFrameworksBuildPhase section */ 61 | 62 | /* Begin PBXGroup section */ 63 | D38B14841D0B89DD00C88130 = { 64 | isa = PBXGroup; 65 | children = ( 66 | D38B14901D0B89DD00C88130 /* MadgwickAHRS */, 67 | D38B149C1D0B89DD00C88130 /* MadgwickAHRSTests */, 68 | D38B148F1D0B89DD00C88130 /* Products */, 69 | ); 70 | sourceTree = ""; 71 | }; 72 | D38B148F1D0B89DD00C88130 /* Products */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | D38B148E1D0B89DD00C88130 /* MadgwickAHRS.framework */, 76 | D38B14981D0B89DD00C88130 /* MadgwickAHRSTests.xctest */, 77 | ); 78 | name = Products; 79 | sourceTree = ""; 80 | }; 81 | D38B14901D0B89DD00C88130 /* MadgwickAHRS */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | D38B14AC1D0B8C7D00C88130 /* CoreMotionMadgwickTestDriver.h */, 85 | D38B14AD1D0B8C7D00C88130 /* CoreMotionMadgwickTestDriver.m */, 86 | D3623B7A1D0C568C0015FFF3 /* CoreMotionMadgwickTestDriverDelegate.h */, 87 | D38B14931D0B89DD00C88130 /* Info.plist */, 88 | D38B14911D0B89DD00C88130 /* MadgwickAHRS.h */, 89 | D38B14A81D0B8A0000C88130 /* MadgwickSensorFusion.h */, 90 | D38B14A91D0B8A0000C88130 /* MadgwickSensorFusion.m */, 91 | ); 92 | path = MadgwickAHRS; 93 | sourceTree = ""; 94 | }; 95 | D38B149C1D0B89DD00C88130 /* MadgwickAHRSTests */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | D38B149D1D0B89DD00C88130 /* MadgwickAHRSTests.m */, 99 | D38B149F1D0B89DD00C88130 /* Info.plist */, 100 | ); 101 | path = MadgwickAHRSTests; 102 | sourceTree = ""; 103 | }; 104 | /* End PBXGroup section */ 105 | 106 | /* Begin PBXHeadersBuildPhase section */ 107 | D38B148B1D0B89DD00C88130 /* Headers */ = { 108 | isa = PBXHeadersBuildPhase; 109 | buildActionMask = 2147483647; 110 | files = ( 111 | D38B14921D0B89DD00C88130 /* MadgwickAHRS.h in Headers */, 112 | D38B14AE1D0B8C7D00C88130 /* CoreMotionMadgwickTestDriver.h in Headers */, 113 | D3623B7B1D0C5B9B0015FFF3 /* CoreMotionMadgwickTestDriverDelegate.h in Headers */, 114 | D38B14AA1D0B8A0000C88130 /* MadgwickSensorFusion.h in Headers */, 115 | ); 116 | runOnlyForDeploymentPostprocessing = 0; 117 | }; 118 | /* End PBXHeadersBuildPhase section */ 119 | 120 | /* Begin PBXNativeTarget section */ 121 | D38B148D1D0B89DD00C88130 /* MadgwickAHRS */ = { 122 | isa = PBXNativeTarget; 123 | buildConfigurationList = D38B14A21D0B89DD00C88130 /* Build configuration list for PBXNativeTarget "MadgwickAHRS" */; 124 | buildPhases = ( 125 | D38B14891D0B89DD00C88130 /* Sources */, 126 | D38B148A1D0B89DD00C88130 /* Frameworks */, 127 | D38B148B1D0B89DD00C88130 /* Headers */, 128 | D38B148C1D0B89DD00C88130 /* Resources */, 129 | ); 130 | buildRules = ( 131 | ); 132 | dependencies = ( 133 | ); 134 | name = MadgwickAHRS; 135 | productName = MadgwickAHRS; 136 | productReference = D38B148E1D0B89DD00C88130 /* MadgwickAHRS.framework */; 137 | productType = "com.apple.product-type.framework"; 138 | }; 139 | D38B14971D0B89DD00C88130 /* MadgwickAHRSTests */ = { 140 | isa = PBXNativeTarget; 141 | buildConfigurationList = D38B14A51D0B89DD00C88130 /* Build configuration list for PBXNativeTarget "MadgwickAHRSTests" */; 142 | buildPhases = ( 143 | D38B14941D0B89DD00C88130 /* Sources */, 144 | D38B14951D0B89DD00C88130 /* Frameworks */, 145 | D38B14961D0B89DD00C88130 /* Resources */, 146 | ); 147 | buildRules = ( 148 | ); 149 | dependencies = ( 150 | D38B149B1D0B89DD00C88130 /* PBXTargetDependency */, 151 | ); 152 | name = MadgwickAHRSTests; 153 | productName = MadgwickAHRSTests; 154 | productReference = D38B14981D0B89DD00C88130 /* MadgwickAHRSTests.xctest */; 155 | productType = "com.apple.product-type.bundle.unit-test"; 156 | }; 157 | /* End PBXNativeTarget section */ 158 | 159 | /* Begin PBXProject section */ 160 | D38B14851D0B89DD00C88130 /* Project object */ = { 161 | isa = PBXProject; 162 | attributes = { 163 | LastUpgradeCheck = 0730; 164 | ORGANIZATIONNAME = Softwarenerd; 165 | TargetAttributes = { 166 | D38B148D1D0B89DD00C88130 = { 167 | CreatedOnToolsVersion = 7.3.1; 168 | }; 169 | D38B14971D0B89DD00C88130 = { 170 | CreatedOnToolsVersion = 7.3.1; 171 | }; 172 | }; 173 | }; 174 | buildConfigurationList = D38B14881D0B89DD00C88130 /* Build configuration list for PBXProject "MadgwickAHRS" */; 175 | compatibilityVersion = "Xcode 3.2"; 176 | developmentRegion = English; 177 | hasScannedForEncodings = 0; 178 | knownRegions = ( 179 | en, 180 | ); 181 | mainGroup = D38B14841D0B89DD00C88130; 182 | productRefGroup = D38B148F1D0B89DD00C88130 /* Products */; 183 | projectDirPath = ""; 184 | projectRoot = ""; 185 | targets = ( 186 | D38B148D1D0B89DD00C88130 /* MadgwickAHRS */, 187 | D38B14971D0B89DD00C88130 /* MadgwickAHRSTests */, 188 | ); 189 | }; 190 | /* End PBXProject section */ 191 | 192 | /* Begin PBXResourcesBuildPhase section */ 193 | D38B148C1D0B89DD00C88130 /* Resources */ = { 194 | isa = PBXResourcesBuildPhase; 195 | buildActionMask = 2147483647; 196 | files = ( 197 | ); 198 | runOnlyForDeploymentPostprocessing = 0; 199 | }; 200 | D38B14961D0B89DD00C88130 /* Resources */ = { 201 | isa = PBXResourcesBuildPhase; 202 | buildActionMask = 2147483647; 203 | files = ( 204 | ); 205 | runOnlyForDeploymentPostprocessing = 0; 206 | }; 207 | /* End PBXResourcesBuildPhase section */ 208 | 209 | /* Begin PBXSourcesBuildPhase section */ 210 | D38B14891D0B89DD00C88130 /* Sources */ = { 211 | isa = PBXSourcesBuildPhase; 212 | buildActionMask = 2147483647; 213 | files = ( 214 | D38B14AB1D0B8A0000C88130 /* MadgwickSensorFusion.m in Sources */, 215 | D38B14AF1D0B8C7D00C88130 /* CoreMotionMadgwickTestDriver.m in Sources */, 216 | ); 217 | runOnlyForDeploymentPostprocessing = 0; 218 | }; 219 | D38B14941D0B89DD00C88130 /* Sources */ = { 220 | isa = PBXSourcesBuildPhase; 221 | buildActionMask = 2147483647; 222 | files = ( 223 | D38B149E1D0B89DD00C88130 /* MadgwickAHRSTests.m in Sources */, 224 | ); 225 | runOnlyForDeploymentPostprocessing = 0; 226 | }; 227 | /* End PBXSourcesBuildPhase section */ 228 | 229 | /* Begin PBXTargetDependency section */ 230 | D38B149B1D0B89DD00C88130 /* PBXTargetDependency */ = { 231 | isa = PBXTargetDependency; 232 | target = D38B148D1D0B89DD00C88130 /* MadgwickAHRS */; 233 | targetProxy = D38B149A1D0B89DD00C88130 /* PBXContainerItemProxy */; 234 | }; 235 | /* End PBXTargetDependency section */ 236 | 237 | /* Begin XCBuildConfiguration section */ 238 | D38B14A01D0B89DD00C88130 /* Debug */ = { 239 | isa = XCBuildConfiguration; 240 | buildSettings = { 241 | ALWAYS_SEARCH_USER_PATHS = NO; 242 | CLANG_ANALYZER_NONNULL = YES; 243 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 244 | CLANG_CXX_LIBRARY = "libc++"; 245 | CLANG_ENABLE_MODULES = YES; 246 | CLANG_ENABLE_OBJC_ARC = YES; 247 | CLANG_WARN_BOOL_CONVERSION = YES; 248 | CLANG_WARN_CONSTANT_CONVERSION = YES; 249 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 250 | CLANG_WARN_EMPTY_BODY = YES; 251 | CLANG_WARN_ENUM_CONVERSION = YES; 252 | CLANG_WARN_INT_CONVERSION = YES; 253 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 254 | CLANG_WARN_UNREACHABLE_CODE = YES; 255 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 256 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 257 | COPY_PHASE_STRIP = NO; 258 | CURRENT_PROJECT_VERSION = 1; 259 | DEBUG_INFORMATION_FORMAT = dwarf; 260 | ENABLE_STRICT_OBJC_MSGSEND = YES; 261 | ENABLE_TESTABILITY = YES; 262 | GCC_C_LANGUAGE_STANDARD = gnu99; 263 | GCC_DYNAMIC_NO_PIC = NO; 264 | GCC_NO_COMMON_BLOCKS = YES; 265 | GCC_OPTIMIZATION_LEVEL = 0; 266 | GCC_PREPROCESSOR_DEFINITIONS = ( 267 | "DEBUG=1", 268 | "$(inherited)", 269 | ); 270 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 271 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 272 | GCC_WARN_UNDECLARED_SELECTOR = YES; 273 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 274 | GCC_WARN_UNUSED_FUNCTION = YES; 275 | GCC_WARN_UNUSED_VARIABLE = YES; 276 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 277 | MTL_ENABLE_DEBUG_INFO = YES; 278 | ONLY_ACTIVE_ARCH = YES; 279 | SDKROOT = iphoneos; 280 | TARGETED_DEVICE_FAMILY = "1,2"; 281 | VERSIONING_SYSTEM = "apple-generic"; 282 | VERSION_INFO_PREFIX = ""; 283 | }; 284 | name = Debug; 285 | }; 286 | D38B14A11D0B89DD00C88130 /* Release */ = { 287 | isa = XCBuildConfiguration; 288 | buildSettings = { 289 | ALWAYS_SEARCH_USER_PATHS = NO; 290 | CLANG_ANALYZER_NONNULL = YES; 291 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 292 | CLANG_CXX_LIBRARY = "libc++"; 293 | CLANG_ENABLE_MODULES = YES; 294 | CLANG_ENABLE_OBJC_ARC = YES; 295 | CLANG_WARN_BOOL_CONVERSION = YES; 296 | CLANG_WARN_CONSTANT_CONVERSION = YES; 297 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 298 | CLANG_WARN_EMPTY_BODY = YES; 299 | CLANG_WARN_ENUM_CONVERSION = YES; 300 | CLANG_WARN_INT_CONVERSION = YES; 301 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 302 | CLANG_WARN_UNREACHABLE_CODE = YES; 303 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 304 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 305 | COPY_PHASE_STRIP = NO; 306 | CURRENT_PROJECT_VERSION = 1; 307 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 308 | ENABLE_NS_ASSERTIONS = NO; 309 | ENABLE_STRICT_OBJC_MSGSEND = YES; 310 | GCC_C_LANGUAGE_STANDARD = gnu99; 311 | GCC_NO_COMMON_BLOCKS = YES; 312 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 313 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 314 | GCC_WARN_UNDECLARED_SELECTOR = YES; 315 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 316 | GCC_WARN_UNUSED_FUNCTION = YES; 317 | GCC_WARN_UNUSED_VARIABLE = YES; 318 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 319 | MTL_ENABLE_DEBUG_INFO = NO; 320 | SDKROOT = iphoneos; 321 | TARGETED_DEVICE_FAMILY = "1,2"; 322 | VALIDATE_PRODUCT = YES; 323 | VERSIONING_SYSTEM = "apple-generic"; 324 | VERSION_INFO_PREFIX = ""; 325 | }; 326 | name = Release; 327 | }; 328 | D38B14A31D0B89DD00C88130 /* Debug */ = { 329 | isa = XCBuildConfiguration; 330 | buildSettings = { 331 | CODE_SIGN_IDENTITY = "iPhone Developer"; 332 | DEFINES_MODULE = YES; 333 | DYLIB_COMPATIBILITY_VERSION = 1; 334 | DYLIB_CURRENT_VERSION = 1; 335 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 336 | INFOPLIST_FILE = MadgwickAHRS/Info.plist; 337 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 338 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 339 | PRODUCT_BUNDLE_IDENTIFIER = org.softwarenerd.MadgwickAHRS; 340 | PRODUCT_NAME = "$(TARGET_NAME)"; 341 | SKIP_INSTALL = YES; 342 | }; 343 | name = Debug; 344 | }; 345 | D38B14A41D0B89DD00C88130 /* Release */ = { 346 | isa = XCBuildConfiguration; 347 | buildSettings = { 348 | CODE_SIGN_IDENTITY = "iPhone Developer"; 349 | DEFINES_MODULE = YES; 350 | DYLIB_COMPATIBILITY_VERSION = 1; 351 | DYLIB_CURRENT_VERSION = 1; 352 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 353 | INFOPLIST_FILE = MadgwickAHRS/Info.plist; 354 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 355 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 356 | PRODUCT_BUNDLE_IDENTIFIER = org.softwarenerd.MadgwickAHRS; 357 | PRODUCT_NAME = "$(TARGET_NAME)"; 358 | SKIP_INSTALL = YES; 359 | }; 360 | name = Release; 361 | }; 362 | D38B14A61D0B89DD00C88130 /* Debug */ = { 363 | isa = XCBuildConfiguration; 364 | buildSettings = { 365 | INFOPLIST_FILE = MadgwickAHRSTests/Info.plist; 366 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 367 | PRODUCT_BUNDLE_IDENTIFIER = org.softwarenerd.MadgwickAHRSTests; 368 | PRODUCT_NAME = "$(TARGET_NAME)"; 369 | }; 370 | name = Debug; 371 | }; 372 | D38B14A71D0B89DD00C88130 /* Release */ = { 373 | isa = XCBuildConfiguration; 374 | buildSettings = { 375 | INFOPLIST_FILE = MadgwickAHRSTests/Info.plist; 376 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 377 | PRODUCT_BUNDLE_IDENTIFIER = org.softwarenerd.MadgwickAHRSTests; 378 | PRODUCT_NAME = "$(TARGET_NAME)"; 379 | }; 380 | name = Release; 381 | }; 382 | /* End XCBuildConfiguration section */ 383 | 384 | /* Begin XCConfigurationList section */ 385 | D38B14881D0B89DD00C88130 /* Build configuration list for PBXProject "MadgwickAHRS" */ = { 386 | isa = XCConfigurationList; 387 | buildConfigurations = ( 388 | D38B14A01D0B89DD00C88130 /* Debug */, 389 | D38B14A11D0B89DD00C88130 /* Release */, 390 | ); 391 | defaultConfigurationIsVisible = 0; 392 | defaultConfigurationName = Release; 393 | }; 394 | D38B14A21D0B89DD00C88130 /* Build configuration list for PBXNativeTarget "MadgwickAHRS" */ = { 395 | isa = XCConfigurationList; 396 | buildConfigurations = ( 397 | D38B14A31D0B89DD00C88130 /* Debug */, 398 | D38B14A41D0B89DD00C88130 /* Release */, 399 | ); 400 | defaultConfigurationIsVisible = 0; 401 | defaultConfigurationName = Release; 402 | }; 403 | D38B14A51D0B89DD00C88130 /* Build configuration list for PBXNativeTarget "MadgwickAHRSTests" */ = { 404 | isa = XCConfigurationList; 405 | buildConfigurations = ( 406 | D38B14A61D0B89DD00C88130 /* Debug */, 407 | D38B14A71D0B89DD00C88130 /* Release */, 408 | ); 409 | defaultConfigurationIsVisible = 0; 410 | defaultConfigurationName = Release; 411 | }; 412 | /* End XCConfigurationList section */ 413 | }; 414 | rootObject = D38B14851D0B89DD00C88130 /* Project object */; 415 | } 416 | -------------------------------------------------------------------------------- /MadgwickAHRS.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MadgwickAHRS.xcodeproj/xcshareddata/xcschemes/MadgwickAHRS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /MadgwickAHRS/CoreMotionMadgwickTestDriver.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreMotionMadgwickTestDriver.h 3 | // MadgwickAHRS 4 | // 5 | // Created by Brian Lambert on 6/7/16. 6 | // 7 | // CoreMotionMadgwickTestDriver uses CoreMotion device motion updates as IMU input data to 8 | // MadgwickAHRS. It then uses the resulting quaternion to calculate Euler angles. 9 | // 10 | 11 | #import 12 | #import "CoreMotionMadgwickTestDriverDelegate.h" 13 | 14 | // CoreMotionMadgwickTestDriver interface. 15 | @interface CoreMotionMadgwickTestDriver : NSObject 16 | 17 | // Properties. 18 | @property (nonatomic, weak, nullable) id delegate; 19 | 20 | // Class initializer. 21 | - (nullable instancetype)initSampleFrequencyHz:(float)sampleFrequencyHz 22 | beta:(float)beta; 23 | 24 | // Starts the driver. 25 | - (void)start; 26 | 27 | // Stop the driver. 28 | - (void)stop; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /MadgwickAHRS/CoreMotionMadgwickTestDriver.m: -------------------------------------------------------------------------------- 1 | // 2 | // CoreMotionMadgwickTestDriver.m 3 | // MadgwickAHRS 4 | // 5 | // Created by Brian Lambert on 6/7/16. 6 | // 7 | // CoreMotionMadgwickTestDriver uses CoreMotion device motion updates as IMU input data to 8 | // MadgwickAHRS. It then uses the resulting quaternion to calculate Euler angles. 9 | // 10 | 11 | #import 12 | #import "CoreMotionMadgwickTestDriver.h" 13 | #import "MadgwickSensorFusion.h" 14 | 15 | // Converts radians to degrees. 16 | static inline float RadiansToDegrees(float radians) 17 | { 18 | return radians * 180.0f / (float)M_PI; 19 | } 20 | 21 | // Calculates Euler angles from quaternion. 22 | void CalculateEulerAnglesFromQuaternion(float q0, float q1, float q2, float q3, float * roll, float * pitch, float * yaw) 23 | { 24 | const float w2 = q0 * q0; 25 | const float x2 = q1 * q1; 26 | const float y2 = q2 * q2; 27 | const float z2 = q3 * q3; 28 | const float unitLength = w2 + x2 + y2 + z2; // Normalised == 1, otherwise correction divisor. 29 | const float abcd = q0 * q1 + q2 * q3; 30 | const float eps = 1e-7f; // TODO: pick from your math lib instead of hardcoding. 31 | if (abcd > (0.5f - eps) * unitLength) 32 | { 33 | *roll = 0.0f; 34 | *pitch = (float)M_PI; 35 | *yaw = 2.0f * atan2f(q2, q0); 36 | } 37 | else if (abcd < (-0.5f + eps) * unitLength) 38 | { 39 | *roll = 0.0f; 40 | *pitch = (float)-M_PI; 41 | *yaw = -2.0f * atan2(q2, q0); 42 | } 43 | else 44 | { 45 | const float adbc = q0 * q3 - q1 * q2; 46 | const float acbd = q0 * q2 - q1 * q3; 47 | *roll = atan2f(2.0f * acbd, 1.0f - 2.0f * (y2 + x2)); 48 | *pitch = asinf(2.0f * abcd / unitLength); 49 | *yaw = atan2f(2.0f * adbc, 1.0f - 2.0f * (z2 + x2)); 50 | } 51 | } 52 | 53 | // CoreMotionMadgwickTestDriver implementation. 54 | @implementation CoreMotionMadgwickTestDriver 55 | { 56 | @private 57 | // The motion manager. 58 | CMMotionManager * _motionManager; 59 | 60 | // The operation queue. 61 | NSOperationQueue * _operationQueue; 62 | 63 | // The Madgwick sensor fusion. 64 | MadgwickSensorFusion * _madgwickSensorFusion; 65 | } 66 | 67 | // Class initializer. 68 | - (nullable instancetype)initSampleFrequencyHz:(float)sampleFrequencyHz 69 | beta:(float)beta; 70 | { 71 | // Initialize superclass. 72 | self = [super init]; 73 | 74 | // Handle errors. 75 | if (!self) 76 | { 77 | return nil; 78 | } 79 | 80 | // Allocate and initialize the motion manager. 81 | _motionManager = [[CMMotionManager alloc] init]; 82 | [_motionManager setShowsDeviceMovementDisplay:YES]; 83 | [_motionManager setDeviceMotionUpdateInterval:1.0 / sampleFrequencyHz]; 84 | 85 | // Allocate and initialize the operation queue. 86 | _operationQueue = [[NSOperationQueue alloc] init]; 87 | [_operationQueue setName:@"DeviceMotion"]; 88 | [_operationQueue setMaxConcurrentOperationCount:1]; 89 | 90 | // Allocate and initialize the Madgwick sensor fusion. 91 | _madgwickSensorFusion = [[MadgwickSensorFusion alloc] initWithSampleFrequencyHz:sampleFrequencyHz 92 | beta:beta]; 93 | 94 | // Done. 95 | return self; 96 | } 97 | 98 | // Starts the driver. 99 | - (void)start 100 | { 101 | // The device motion handler. 102 | CMDeviceMotionHandler handler = ^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) 103 | { 104 | // Employ Madgwick AHRS sensor fusion. 105 | [_madgwickSensorFusion updateWithGyroscopeX:(float)[motion rotationRate].x 106 | gyroscopeY:(float)[motion rotationRate].y 107 | gyroscopeZ:(float)[motion rotationRate].z 108 | accelerometerX:(float)[motion gravity].x * -1.0f 109 | accelerometerY:(float)[motion gravity].y * -1.0f 110 | accelerometerZ:(float)[motion gravity].z * -1.0f 111 | magnetometerX:(float)[motion magneticField].field.x 112 | magnetometerY:(float)[motion magneticField].field.y 113 | magnetometerZ:(float)[motion magneticField].field.z]; 114 | 115 | // Calculate roll, pitch, yaw. 116 | float roll, pitch, yaw; 117 | CalculateEulerAnglesFromQuaternion([_madgwickSensorFusion q0], 118 | [_madgwickSensorFusion q1], 119 | [_madgwickSensorFusion q2], 120 | [_madgwickSensorFusion q3], 121 | &roll, 122 | &pitch, 123 | &yaw); 124 | roll = RadiansToDegrees(roll); 125 | pitch = RadiansToDegrees(pitch); 126 | yaw = RadiansToDegrees(yaw); 127 | 128 | // Obtain CoreMotion roll, pitch and yaw for comparison logging below. 129 | float coreMotionRoll = RadiansToDegrees([[motion attitude] roll]); 130 | float coreMotionPitch = RadiansToDegrees([[motion attitude] pitch]); 131 | float coreMotionYaw = RadiansToDegrees([[motion attitude] yaw]); 132 | 133 | // Notify the delegate. 134 | if ([[self delegate] respondsToSelector:@selector(coreMotionMadgwickTestDriver: 135 | didUpdateGyroscopeX: 136 | gyroscopeY: 137 | gyroscopeZ: 138 | accelerometerX: 139 | accelerometerY: 140 | accelerometerZ: 141 | magnetometerX: 142 | magnetometerY: 143 | magnetometerZ: 144 | quaternion0: 145 | quaternion1: 146 | quaternion2: 147 | quaternion3: 148 | roll: 149 | pitch: 150 | yaw: 151 | coreMotionRoll: 152 | coreMotionPitch: 153 | coreMotionYaw:)]) 154 | { 155 | [[self delegate] coreMotionMadgwickTestDriver:self 156 | didUpdateGyroscopeX:[motion rotationRate].x 157 | gyroscopeY:[motion rotationRate].y 158 | gyroscopeZ:[motion rotationRate].z 159 | accelerometerX:[motion gravity].x * -1.0f 160 | accelerometerY:[motion gravity].y * -1.0f 161 | accelerometerZ:[motion gravity].z * -1.0f 162 | magnetometerX:[motion magneticField].field.x 163 | magnetometerY:[motion magneticField].field.y 164 | magnetometerZ:[motion magneticField].field.z 165 | quaternion0:[_madgwickSensorFusion q0] 166 | quaternion1:[_madgwickSensorFusion q1] 167 | quaternion2:[_madgwickSensorFusion q2] 168 | quaternion3:[_madgwickSensorFusion q3] 169 | roll:roll 170 | pitch:pitch 171 | yaw:yaw 172 | coreMotionRoll:coreMotionRoll 173 | coreMotionPitch:coreMotionPitch 174 | coreMotionYaw:coreMotionYaw]; 175 | } 176 | }; 177 | 178 | // Start motion updates. 179 | [_motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXMagneticNorthZVertical 180 | toQueue:_operationQueue 181 | withHandler:handler]; 182 | } 183 | 184 | // Stops the driver. 185 | - (void)stop 186 | { 187 | // Stop motion updates. 188 | [_motionManager stopDeviceMotionUpdates]; 189 | } 190 | 191 | @end -------------------------------------------------------------------------------- /MadgwickAHRS/CoreMotionMadgwickTestDriverDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreMotionMadgwickTestDriverDelegate.h 3 | // MadgwickAHRS 4 | // 5 | // Created by Brian Lambert on 6/11/16. 6 | // Copyright © 2016 Softwarenerd. All rights reserved. 7 | // 8 | 9 | // Forward declarations. 10 | @class CoreMotionMadgwickTestDriver; 11 | 12 | // CoreMotionMadgwickTestDriverDelegate protocol. 13 | @protocol CoreMotionMadgwickTestDriverDelegate 14 | @required 15 | 16 | // Notifies the delegate of an update. 17 | - (void)coreMotionMadgwickTestDriver:(CoreMotionMadgwickTestDriver *)coreMotionMadgwickTestDriver 18 | didUpdateGyroscopeX:(float)gx 19 | gyroscopeY:(float)gy 20 | gyroscopeZ:(float)gz 21 | accelerometerX:(float)ax 22 | accelerometerY:(float)ay 23 | accelerometerZ:(float)az 24 | magnetometerX:(float)mx 25 | magnetometerY:(float)my 26 | magnetometerZ:(float)mz 27 | quaternion0:(float)q0 28 | quaternion1:(float)q1 29 | quaternion2:(float)q2 30 | quaternion3:(float)q3 31 | roll:(float)roll 32 | pitch:(float)pitch 33 | yaw:(float)yaw 34 | coreMotionRoll:(float)coreMotionRoll 35 | coreMotionPitch:(float)coreMotionPitch 36 | coreMotionYaw:(float)coreMotionYaw; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /MadgwickAHRS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /MadgwickAHRS/MadgwickAHRS.h: -------------------------------------------------------------------------------- 1 | // 2 | // MadgwickAHRS.h 3 | // MadgwickAHRS 4 | // 5 | // Created by Brian Lambert on 6/10/16. 6 | // Copyright © 2016 Softwarenerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for MadgwickAHRS. 12 | FOUNDATION_EXPORT double MadgwickAHRSVersionNumber; 13 | 14 | //! Project version string for MadgwickAHRS. 15 | FOUNDATION_EXPORT const unsigned char MadgwickAHRSVersionString[]; 16 | 17 | // Public headers. 18 | #import 19 | #import 20 | 21 | -------------------------------------------------------------------------------- /MadgwickAHRS/MadgwickSensorFusion.h: -------------------------------------------------------------------------------- 1 | // 2 | // MadgwickSensorFusion.h 3 | // MadgwickAHRS 4 | // 5 | // Implementation of Madgwick's IMU and AHRS algorithms. 6 | // See: http://www.x-io.co.uk/open-source-imu-and-ahrs-algorithms/ 7 | // 8 | // Date Author Notes 9 | // -------------------------------------------------------------------------------------------------- 10 | // 29/09/2011 SOH Madgwick Initial release 11 | // 02/10/2011 SOH Madgwick Optimised for reduced CPU load 12 | // 19/02/2012 SOH Madgwick Magnetometer measurement is normalised 13 | // 02/06/2016 Brian Lambert Ported to Objective-C. 14 | // 15 | 16 | @import Foundation; 17 | 18 | // MadgwickSensorFusion interface. 19 | @interface MadgwickSensorFusion : NSObject 20 | 21 | // Quaternion properties. 22 | @property (nonatomic, readonly) float q0; 23 | @property (nonatomic, readonly) float q1; 24 | @property (nonatomic, readonly) float q2; 25 | @property (nonatomic, readonly) float q3; 26 | 27 | // Class initializer. 28 | - (nullable instancetype)initWithSampleFrequencyHz:(float)sampleFrequencyHz 29 | beta:(float)beta; 30 | 31 | // Update with gyroscope and accelerometer. 32 | - (void)updateWithGyroscopeX:(float)gx 33 | gyroscopeY:(float)gy 34 | gyroscopeZ:(float)gz 35 | accelerometerX:(float)ax 36 | accelerometerY:(float)ay 37 | accelerometerZ:(float)az; 38 | 39 | // Update with gyroscope, accelerometer and magnetometer. 40 | - (void)updateWithGyroscopeX:(float)gx 41 | gyroscopeY:(float)gy 42 | gyroscopeZ:(float)gz 43 | accelerometerX:(float)ax 44 | accelerometerY:(float)ay 45 | accelerometerZ:(float)az 46 | magnetometerX:(float)mx 47 | magnetometerY:(float)my 48 | magnetometerZ:(float)mz; 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /MadgwickAHRS/MadgwickSensorFusion.m: -------------------------------------------------------------------------------- 1 | // 2 | // MadgwickSensorFusion.m 3 | // MadgwickAHRS 4 | // 5 | // Implementation of Madgwick's IMU and AHRS algorithms. 6 | // See: http://www.x-io.co.uk/open-source-imu-and-ahrs-algorithms/ 7 | // 8 | // Date Author Notes 9 | // -------------------------------------------------------------------------------------------------- 10 | // 29/09/2011 SOH Madgwick Initial release 11 | // 02/10/2011 SOH Madgwick Optimised for reduced CPU load 12 | // 19/02/2012 SOH Madgwick Magnetometer measurement is normalised 13 | // 02/06/2016 Brian Lambert Ported to Objective-C. 14 | // 15 | 16 | #include 17 | #import "MadgwickSensorFusion.h" 18 | 19 | // Inverse square root. 20 | static inline float invSqrt(float x) 21 | { 22 | float xhalf = 0.5f * x; 23 | int i = *(int*)&x; // get bits for floating value 24 | i = 0x5f375a86 - (i >> 1); // gives initial guess y0 25 | x = *(float*)&i; // convert bits back to float 26 | x = x * (1.5f - xhalf * x * x); // Newton step, repeating increases accuracy 27 | return x; 28 | } 29 | 30 | // MadgwickSensorFusion implementation. 31 | @implementation MadgwickSensorFusion 32 | { 33 | @private 34 | // Sample frequency. 35 | float _sampleFrequencyHz; 36 | 37 | // Beta. 38 | float _beta; 39 | } 40 | 41 | // Class initializer. 42 | - (nullable instancetype)initWithSampleFrequencyHz:(float)sampleFrequencyHz 43 | beta:(float)beta; 44 | { 45 | // Initialize superclass. 46 | self = [super init]; 47 | 48 | // Handle errors. 49 | if (!self) 50 | { 51 | return nil; 52 | } 53 | 54 | _sampleFrequencyHz = sampleFrequencyHz; 55 | _beta = beta; 56 | _q0 = 1.0f; 57 | _q1 = 0.0f; 58 | _q2 = 0.0f; 59 | _q3 = 0.0f; 60 | 61 | // Done. 62 | return self; 63 | } 64 | 65 | // Update with gyroscope and accelerometer. 66 | - (void)updateWithGyroscopeX:(float)gx 67 | gyroscopeY:(float)gy 68 | gyroscopeZ:(float)gz 69 | accelerometerX:(float)ax 70 | accelerometerY:(float)ay 71 | accelerometerZ:(float)az 72 | { 73 | float recipNorm; 74 | float s0, s1, s2, s3; 75 | float qDot1, qDot2, qDot3, qDot4; 76 | float _2q0, _2q1, _2q2, _2q3, _4q0, _4q1, _4q2 ,_8q1, _8q2, q0q0, q1q1, q2q2, q3q3; 77 | 78 | // Rate of change of quaternion from gyroscope 79 | qDot1 = 0.5f * (-_q1 * gx - _q2 * gy - _q3 * gz); 80 | qDot2 = 0.5f * (_q0 * gx + _q2 * gz - _q3 * gy); 81 | qDot3 = 0.5f * (_q0 * gy - _q1 * gz + _q3 * gx); 82 | qDot4 = 0.5f * (_q0 * gz + _q1 * gy - _q2 * gx); 83 | 84 | // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) 85 | if (!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) 86 | { 87 | // Normalise accelerometer measurement 88 | recipNorm = invSqrt(ax * ax + ay * ay + az * az); 89 | ax *= recipNorm; 90 | ay *= recipNorm; 91 | az *= recipNorm; 92 | 93 | // Auxiliary variables to avoid repeated arithmetic 94 | _2q0 = 2.0f * _q0; 95 | _2q1 = 2.0f * _q1; 96 | _2q2 = 2.0f * _q2; 97 | _2q3 = 2.0f * _q3; 98 | _4q0 = 4.0f * _q0; 99 | _4q1 = 4.0f * _q1; 100 | _4q2 = 4.0f * _q2; 101 | _8q1 = 8.0f * _q1; 102 | _8q2 = 8.0f * _q2; 103 | q0q0 = _q0 * _q0; 104 | q1q1 = _q1 * _q1; 105 | q2q2 = _q2 * _q2; 106 | q3q3 = _q3 * _q3; 107 | 108 | // Gradient decent algorithm corrective step 109 | s0 = _4q0 * q2q2 + _2q2 * ax + _4q0 * q1q1 - _2q1 * ay; 110 | s1 = _4q1 * q3q3 - _2q3 * ax + 4.0f * q0q0 * _q1 - _2q0 * ay - _4q1 + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * az; 111 | s2 = 4.0f * q0q0 * _q2 + _2q0 * ax + _4q2 * q3q3 - _2q3 * ay - _4q2 + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * az; 112 | s3 = 4.0f * q1q1 * _q3 - _2q1 * ax + 4.0f * q2q2 * _q3 - _2q2 * ay; 113 | recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude 114 | s0 *= recipNorm; 115 | s1 *= recipNorm; 116 | s2 *= recipNorm; 117 | s3 *= recipNorm; 118 | 119 | // Apply feedback step 120 | qDot1 -= _beta * s0; 121 | qDot2 -= _beta * s1; 122 | qDot3 -= _beta * s2; 123 | qDot4 -= _beta * s3; 124 | } 125 | 126 | // Integrate rate of change of quaternion to yield quaternion 127 | _q0 += qDot1 * (1.0f / _sampleFrequencyHz); 128 | _q1 += qDot2 * (1.0f / _sampleFrequencyHz); 129 | _q2 += qDot3 * (1.0f / _sampleFrequencyHz); 130 | _q3 += qDot4 * (1.0f / _sampleFrequencyHz); 131 | 132 | // Normalise quaternion 133 | recipNorm = invSqrt(_q0 * _q0 + _q1 * _q1 + _q2 * _q2 + _q3 * _q3); 134 | _q0 *= recipNorm; 135 | _q1 *= recipNorm; 136 | _q2 *= recipNorm; 137 | _q3 *= recipNorm; 138 | } 139 | 140 | // Update with gyroscope, accelerometer and magnetometer. 141 | - (void)updateWithGyroscopeX:(float)gx 142 | gyroscopeY:(float)gy 143 | gyroscopeZ:(float)gz 144 | accelerometerX:(float)ax 145 | accelerometerY:(float)ay 146 | accelerometerZ:(float)az 147 | magnetometerX:(float)mx 148 | magnetometerY:(float)my 149 | magnetometerZ:(float)mz 150 | { 151 | float recipNorm; 152 | float s0, s1, s2, s3; 153 | float qDot1, qDot2, qDot3, qDot4; 154 | float hx, hy; 155 | float _2q0mx, _2q0my, _2q0mz, _2q1mx, _2bx, _2bz, _4bx, _4bz, _2q0, _2q1, _2q2, _2q3, _2q0q2, _2q2q3, q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3; 156 | 157 | // Use IMU algorithm if magnetometer measurement invalid (avoids NaN in magnetometer normalisation) 158 | if ((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f)) 159 | { 160 | [self updateWithGyroscopeX:gx 161 | gyroscopeY:gy 162 | gyroscopeZ:gz 163 | accelerometerX:ax 164 | accelerometerY:ay 165 | accelerometerZ:az]; 166 | return; 167 | } 168 | 169 | // Rate of change of quaternion from gyroscope 170 | qDot1 = 0.5f * (-_q1 * gx - _q2 * gy - _q3 * gz); 171 | qDot2 = 0.5f * (_q0 * gx + _q2 * gz - _q3 * gy); 172 | qDot3 = 0.5f * (_q0 * gy - _q1 * gz + _q3 * gx); 173 | qDot4 = 0.5f * (_q0 * gz + _q1 * gy - _q2 * gx); 174 | 175 | // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) 176 | if (!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) 177 | { 178 | // Normalise accelerometer measurement 179 | recipNorm = invSqrt(ax * ax + ay * ay + az * az); 180 | ax *= recipNorm; 181 | ay *= recipNorm; 182 | az *= recipNorm; 183 | 184 | // Normalise magnetometer measurement 185 | recipNorm = invSqrt(mx * mx + my * my + mz * mz); 186 | mx *= recipNorm; 187 | my *= recipNorm; 188 | mz *= recipNorm; 189 | 190 | // Auxiliary variables to avoid repeated arithmetic 191 | _2q0mx = 2.0f * _q0 * mx; 192 | _2q0my = 2.0f * _q0 * my; 193 | _2q0mz = 2.0f * _q0 * mz; 194 | _2q1mx = 2.0f * _q1 * mx; 195 | _2q0 = 2.0f * _q0; 196 | _2q1 = 2.0f * _q1; 197 | _2q2 = 2.0f * _q2; 198 | _2q3 = 2.0f * _q3; 199 | _2q0q2 = 2.0f * _q0 * _q2; 200 | _2q2q3 = 2.0f * _q2 * _q3; 201 | q0q0 = _q0 * _q0; 202 | q0q1 = _q0 * _q1; 203 | q0q2 = _q0 * _q2; 204 | q0q3 = _q0 * _q3; 205 | q1q1 = _q1 * _q1; 206 | q1q2 = _q1 * _q2; 207 | q1q3 = _q1 * _q3; 208 | q2q2 = _q2 * _q2; 209 | q2q3 = _q2 * _q3; 210 | q3q3 = _q3 * _q3; 211 | 212 | // Reference direction of Earth's magnetic field 213 | hx = mx * q0q0 - _2q0my * _q3 + _2q0mz * _q2 + mx * q1q1 + _2q1 * my * _q2 + _2q1 * mz * _q3 - mx * q2q2 - mx * q3q3; 214 | hy = _2q0mx * _q3 + my * q0q0 - _2q0mz * _q1 + _2q1mx * _q2 - my * q1q1 + my * q2q2 + _2q2 * mz * _q3 - my * q3q3; 215 | _2bx = sqrt(hx * hx + hy * hy); 216 | _2bz = -_2q0mx * _q2 + _2q0my * _q1 + mz * q0q0 + _2q1mx * _q3 - mz * q1q1 + _2q2 * my * _q3 - mz * q2q2 + mz * q3q3; 217 | _4bx = 2.0f * _2bx; 218 | _4bz = 2.0f * _2bz; 219 | 220 | // Gradient decent algorithm corrective step 221 | s0 = -_2q2 * (2.0f * q1q3 - _2q0q2 - ax) + _2q1 * (2.0f * q0q1 + _2q2q3 - ay) - _2bz * _q2 * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (-_2bx * _q3 + _2bz * _q1) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + _2bx * _q2 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz); 222 | s1 = _2q3 * (2.0f * q1q3 - _2q0q2 - ax) + _2q0 * (2.0f * q0q1 + _2q2q3 - ay) - 4.0f * _q1 * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az) + _2bz * _q3 * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (_2bx * _q2 + _2bz * _q0) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + (_2bx * _q3 - _4bz * _q1) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz); 223 | s2 = -_2q0 * (2.0f * q1q3 - _2q0q2 - ax) + _2q3 * (2.0f * q0q1 + _2q2q3 - ay) - 4.0f * _q2 * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az) + (-_4bx * _q2 - _2bz * _q0) * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (_2bx * _q1 + _2bz * _q3) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + (_2bx * _q0 - _4bz * _q2) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz); 224 | s3 = _2q1 * (2.0f * q1q3 - _2q0q2 - ax) + _2q2 * (2.0f * q0q1 + _2q2q3 - ay) + (-_4bx * _q3 + _2bz * _q1) * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (-_2bx * _q0 + _2bz * _q2) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + _2bx * _q1 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz); 225 | recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude 226 | s0 *= recipNorm; 227 | s1 *= recipNorm; 228 | s2 *= recipNorm; 229 | s3 *= recipNorm; 230 | 231 | // Apply feedback step 232 | qDot1 -= _beta * s0; 233 | qDot2 -= _beta * s1; 234 | qDot3 -= _beta * s2; 235 | qDot4 -= _beta * s3; 236 | } 237 | 238 | // Integrate rate of change of quaternion to yield quaternion 239 | _q0 += qDot1 * (1.0f / _sampleFrequencyHz); 240 | _q1 += qDot2 * (1.0f / _sampleFrequencyHz); 241 | _q2 += qDot3 * (1.0f / _sampleFrequencyHz); 242 | _q3 += qDot4 * (1.0f / _sampleFrequencyHz); 243 | 244 | // Normalise quaternion 245 | recipNorm = invSqrt(_q0 * _q0 + _q1 * _q1 + _q2 * _q2 + _q3 * _q3); 246 | _q0 *= recipNorm; 247 | _q1 *= recipNorm; 248 | _q2 *= recipNorm; 249 | _q3 *= recipNorm; 250 | } 251 | 252 | @end -------------------------------------------------------------------------------- /MadgwickAHRSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /MadgwickAHRSTests/MadgwickAHRSTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // MadgwickAHRSTests.m 3 | // MadgwickAHRSTests 4 | // 5 | // Created by Brian Lambert on 6/10/16. 6 | // Copyright © 2016 Softwarenerd. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MadgwickSensorFusion.h" 11 | 12 | // Normalizes. 13 | float NormalizeAngle(float angle) 14 | { 15 | return fmodf(angle + 360.0f, 360.0f); 16 | } 17 | 18 | // Converts radians to degrees. 19 | static inline float RadiansToDegrees(float radians) 20 | { 21 | return radians * 180.0f / M_PI; 22 | } 23 | 24 | // Calculates Euler angles from quaternion. 25 | void CalculateEulerAnglesFromQuaternion(float q0, float q1, float q2, float q3, float * roll, float * pitch, float * yaw) 26 | { 27 | const float w2 = q0 * q0; 28 | const float x2 = q1 * q1; 29 | const float y2 = q2 * q2; 30 | const float z2 = q3 * q3; 31 | const float unitLength = w2 + x2 + y2 + z2; // Normalised == 1, otherwise correction divisor. 32 | const float abcd = q0 * q1 + q2 * q3; 33 | const float eps = 1e-7; // TODO: pick from your math lib instead of hardcoding. 34 | if (abcd > (0.5-eps) * unitLength) 35 | { 36 | *roll = 0; 37 | *pitch = M_PI; 38 | *yaw = 2.0f * atan2(q2, q0); 39 | } 40 | else if (abcd < (-0.5 + eps) * unitLength) 41 | { 42 | *roll = 0; 43 | *pitch = -M_PI; 44 | *yaw = -2.0f * atan2(q2, q0); 45 | } 46 | else 47 | { 48 | const float adbc = q0 * q3 - q1 * q2; 49 | const float acbd = q0 * q2 - q1 * q3; 50 | *roll = atan2(2.0f * acbd, 1.0f - 2.0f * (y2 + x2)); 51 | *pitch = asin(2.0f * abcd / unitLength); 52 | *yaw = atan2(2.0f * adbc, 1.0f - 2.0f * (z2 + x2)); 53 | } 54 | } 55 | 56 | // MadgwickAHRSTests interface. 57 | @interface MadgwickAHRSTests : XCTestCase 58 | @end 59 | 60 | // MadgwickAHRSTests implementation. 61 | @implementation MadgwickAHRSTests 62 | 63 | // Setup. 64 | - (void)setUp 65 | { 66 | [super setUp]; 67 | } 68 | 69 | // Teardown. 70 | - (void)tearDown 71 | { 72 | [super tearDown]; 73 | } 74 | 75 | // Madgwick test A. 76 | - (void)testMadgwickA 77 | { 78 | // Test. 79 | NSString * sampleJSON = @"[{\"pitch\":0.5264893,\"gz\":0.0004721961,\"my\":0,\"yaw\":0.03433228,\"coreMotionRoll\":359.509,\"mz\":0,\"ax\":0.00856893,\"coreMotionPitch\":0.03717041,\"coreMotionYaw\":0.0003051758,\"gx\":0.000979821,\"ay\":0.0006486682,\"gy\":0.0001413785,\"az\":0.9999631,\"mx\":0,\"roll\":353.1229},{\"pitch\":359.9064,\"gz\":-0.00058764,\"my\":0,\"yaw\":0.004882812,\"coreMotionRoll\":359.5904,\"mz\":0,\"ax\":0.007148615,\"coreMotionPitch\":359.9442,\"coreMotionYaw\":0.003265381,\"gx\":-9.922422e-05,\"ay\":-0.0009733105,\"gy\":0.0001388151,\"az\":0.999974,\"mx\":0,\"roll\":0.004669189},{\"pitch\":0.2915344,\"gz\":-0.001647469,\"my\":0,\"yaw\":0.007385254,\"coreMotionRoll\":359.6066,\"mz\":0,\"ax\":0.006866026,\"coreMotionPitch\":359.9293,\"coreMotionYaw\":0.003875732,\"gx\":-0.00117847,\"ay\":-0.001234906,\"gy\":0.000138258,\"az\":0.9999757,\"mx\":0,\"roll\":353.111},{\"pitch\":359.911,\"gz\":0.0004648018,\"my\":0,\"yaw\":359.9985,\"coreMotionRoll\":359.6366,\"mz\":0,\"ax\":0.00634326,\"coreMotionPitch\":359.9267,\"coreMotionYaw\":0.005981445,\"gx\":0.000960644,\"ay\":-0.001279598,\"gy\":0.001242075,\"az\":0.9999791,\"mx\":0,\"roll\":0.01568604},{\"pitch\":1.100098,\"gz\":0.0004716274,\"my\":-18.01436,\"yaw\":2.781006,\"coreMotionRoll\":359.6564,\"mz\":-21.21292,\"ax\":0.00599631,\"coreMotionPitch\":359.917,\"coreMotionYaw\":0.009277344,\"gx\":-0.0001210217,\"ay\":-0.001449067,\"gy\":0.001269948,\"az\":0.999981,\"mx\":-39.24414,\"roll\":353.7953},{\"pitch\":2.127441,\"gz\":0.0004861102,\"my\":-18.2394,\"yaw\":6.087921,\"coreMotionRoll\":359.6654,\"mz\":-21.13721,\"ax\":0.005840272,\"coreMotionPitch\":359.9029,\"coreMotionYaw\":155.4675,\"gx\":-0.001221335,\"ay\":-0.001695231,\"gy\":0.0002259741,\"az\":0.9999815,\"mx\":-39.39549,\"roll\":347.8245},{\"pitch\":2.918884,\"gz\":-0.0005725962,\"my\":-18.08928,\"yaw\":9.976746,\"coreMotionRoll\":359.6707,\"mz\":-21.3631,\"ax\":0.005747447,\"coreMotionPitch\":359.8967,\"coreMotionYaw\":155.469,\"gx\":-0.001241715,\"ay\":-0.001802874,\"gy\":-0.000834419,\"az\":0.9999819,\"mx\":-39.24484,\"roll\":342.2617},{\"pitch\":3.395905,\"gz\":-0.0005935672,\"my\":-18.16438,\"yaw\":14.8356,\"coreMotionRoll\":359.6769,\"mz\":-21.13829,\"ax\":0.005639632,\"coreMotionPitch\":359.8953,\"coreMotionYaw\":155.4705,\"gx\":0.0008934455,\"ay\":-0.001827041,\"gy\":0.0002295439,\"az\":0.9999824,\"mx\":-39.245,\"roll\":337.5668},{\"pitch\":3.261566,\"gz\":-0.0005935144,\"my\":-17.71436,\"yaw\":20.87393,\"coreMotionRoll\":359.673,\"mz\":-21.21283,\"ax\":0.005707813,\"coreMotionPitch\":359.8964,\"coreMotionYaw\":155.4746,\"gx\":0.0008834388,\"ay\":-0.001809077,\"gy\":0.0001997134,\"az\":0.9999821,\"mx\":-39.16719,\"roll\":334.5395},{\"pitch\":2.743958,\"gz\":0.001545258,\"my\":-18.01414,\"yaw\":27.57236,\"coreMotionRoll\":359.6851,\"mz\":-21.59238,\"ax\":0.005496477,\"coreMotionPitch\":359.9007,\"coreMotionYaw\":155.4771,\"gx\":-0.001224232,\"ay\":-0.001733401,\"gy\":0.001313187,\"az\":0.9999834,\"mx\":-38.71971,\"roll\":334.1277},{\"pitch\":1.631714,\"gz\":0.0004798245,\"my\":-18.01424,\"yaw\":34.12677,\"coreMotionRoll\":359.6827,\"mz\":-21.4341,\"ax\":0.005537265,\"coreMotionPitch\":359.8982,\"coreMotionYaw\":155.4827,\"gx\":-0.0001730853,\"ay\":-0.001777576,\"gy\":0.0002277463,\"az\":0.9999831,\"mx\":-39.69447,\"roll\":334.4159},{\"pitch\":0.5903931,\"gz\":0.001601837,\"my\":-17.93913,\"yaw\":40.5376,\"coreMotionRoll\":359.6805,\"mz\":-21.66147,\"ax\":0.005575487,\"coreMotionPitch\":359.9007,\"coreMotionYaw\":155.4879,\"gx\":0.002010253,\"ay\":-0.00173293,\"gy\":0.001289319,\"az\":0.999983,\"mx\":-39.39432,\"roll\":335.0559},{\"pitch\":359.626,\"gz\":-0.0005246151,\"my\":-18.23932,\"yaw\":46.78391,\"coreMotionRoll\":359.6854,\"mz\":-21.28784,\"ax\":0.00549029,\"coreMotionPitch\":359.8986,\"coreMotionYaw\":155.491,\"gx\":0.0009288067,\"ay\":-0.001770687,\"gy\":0.001273021,\"az\":0.9999834,\"mx\":-39.32071,\"roll\":335.781},{\"pitch\":358.6909,\"gz\":0.0005717687,\"my\":-18.23929,\"yaw\":52.84467,\"coreMotionRoll\":359.6847,\"mz\":-21.36411,\"ax\":0.005503466,\"coreMotionPitch\":359.9033,\"coreMotionYaw\":155.4957,\"gx\":-0.001196151,\"ay\":-0.001687269,\"gy\":0.001287353,\"az\":0.9999834,\"mx\":-39.17082,\"roll\":336.6324},{\"pitch\":357.7881,\"gz\":-0.0005003662,\"my\":-18.08939,\"yaw\":58.73987,\"coreMotionRoll\":359.6848,\"mz\":-21.13684,\"ax\":0.00550069,\"coreMotionPitch\":359.9014,\"coreMotionYaw\":155.4998,\"gx\":0.000935566,\"ay\":-0.001720674,\"gy\":0.000214548,\"az\":0.9999834,\"mx\":-39.39452,\"roll\":337.522},{\"pitch\":356.9998,\"gz\":-0.0004932038,\"my\":-18.16438,\"yaw\":64.45319,\"coreMotionRoll\":359.6867,\"mz\":-21.13893,\"ax\":0.005467175,\"coreMotionPitch\":359.8968,\"coreMotionYaw\":155.5027,\"gx\":-0.0001344203,\"ay\":-0.001801449,\"gy\":0.000212512,\"az\":0.9999834,\"mx\":-39.17,\"roll\":338.5226},{\"pitch\":356.2814,\"gz\":-0.0004721422,\"my\":-17.86435,\"yaw\":69.97742,\"coreMotionRoll\":359.6789,\"mz\":-21.21701,\"ax\":0.005604142,\"coreMotionPitch\":359.9073,\"coreMotionYaw\":155.5059,\"gx\":-0.002268021,\"ay\":-0.001617905,\"gy\":-0.0008509943,\"az\":0.999983,\"mx\":-38.71817,\"roll\":339.584},{\"pitch\":355.6748,\"gz\":0.001621265,\"my\":-18.01428,\"yaw\":75.33875,\"coreMotionRoll\":359.6771,\"mz\":-21.36546,\"ax\":0.005635374,\"coreMotionPitch\":359.9055,\"coreMotionYaw\":155.5076,\"gx\":-0.0001259915,\"ay\":-0.001649251,\"gy\":0.002344245,\"az\":0.9999828,\"mx\":-38.94437,\"roll\":340.7151},{\"pitch\":355.1684,\"gz\":0.00162953,\"my\":-18.31429,\"yaw\":80.51544,\"coreMotionRoll\":359.6812,\"mz\":-21.36429,\"ax\":0.00556452,\"coreMotionPitch\":359.9016,\"coreMotionYaw\":155.5114,\"gx\":-0.002267306,\"ay\":-0.001718301,\"gy\":0.002341616,\"az\":0.999983,\"mx\":-39.17131,\"roll\":341.8837},{\"pitch\":354.7627,\"gz\":-0.0005025471,\"my\":-18.31416,\"yaw\":85.48795,\"coreMotionRoll\":359.6765,\"mz\":-21.58929,\"ax\":0.00564519,\"coreMotionPitch\":359.9017,\"coreMotionYaw\":155.517,\"gx\":-0.001207108,\"ay\":-0.001714817,\"gy\":0.001260646,\"az\":0.9999826,\"mx\":-39.17165,\"roll\":343.0611},{\"pitch\":354.4624,\"gz\":0.0005554502,\"my\":-18.53928,\"yaw\":90.25879,\"coreMotionRoll\":359.6874,\"mz\":-21.36676,\"ax\":0.005455916,\"coreMotionPitch\":359.8995,\"coreMotionYaw\":155.5216,\"gx\":-0.003344004,\"ay\":-0.001753647,\"gy\":0.003388743,\"az\":0.9999835,\"mx\":-38.94778,\"roll\":344.2699},{\"pitch\":354.2736,\"gz\":0.001610477,\"my\":-18.53929,\"yaw\":94.83987,\"coreMotionRoll\":359.6895,\"mz\":-21.29303,\"ax\":0.005420057,\"coreMotionPitch\":359.8964,\"coreMotionYaw\":155.5253,\"gx\":0.001997071,\"ay\":-0.001808128,\"gy\":-0.0008544789,\"az\":0.9999837,\"mx\":-38.79767,\"roll\":345.4387},{\"pitch\":354.117,\"gz\":0.0005417952,\"my\":-18.2394,\"yaw\":99.22943,\"coreMotionRoll\":359.6873,\"mz\":-21.14102,\"ax\":0.005457308,\"coreMotionPitch\":359.9012,\"coreMotionYaw\":155.5299,\"gx\":-0.0001431877,\"ay\":-0.001725242,\"gy\":0.001259688,\"az\":0.9999836,\"mx\":-38.9455,\"roll\":346.5743},{\"pitch\":354.0229,\"gz\":0.0005318171,\"my\":-18.08939,\"yaw\":103.4232,\"coreMotionRoll\":359.6794,\"mz\":-21.14003,\"ax\":0.005596395,\"coreMotionPitch\":359.9007,\"coreMotionYaw\":155.5335,\"gx\":-0.001214946,\"ay\":-0.001733326,\"gy\":0.002314281,\"az\":0.9999828,\"mx\":-39.01952,\"roll\":347.6774},{\"pitch\":354.0078,\"gz\":0.0005451886,\"my\":-18.31447,\"yaw\":107.4103,\"coreMotionRoll\":359.6784,\"mz\":-20.98802,\"ax\":0.005612301,\"coreMotionPitch\":359.8974,\"coreMotionYaw\":155.5372,\"gx\":-0.003353131,\"ay\":-0.001791405,\"gy\":0.002314666,\"az\":0.9999827,\"mx\":-39.32076,\"roll\":348.7499},{\"pitch\":354.0503,\"gz\":0.0005181289,\"my\":-17.86432,\"yaw\":111.2149,\"coreMotionRoll\":359.6768,\"mz\":-21.28629,\"ax\":0.005639995,\"coreMotionPitch\":359.8927,\"coreMotionYaw\":155.5414,\"gx\":0.001984719,\"ay\":-0.001872927,\"gy\":0.0001839434,\"az\":0.9999824,\"mx\":-39.39328,\"roll\":349.7408},{\"pitch\":354.1326,\"gz\":0.001607992,\"my\":-17.93916,\"yaw\":114.7867,\"coreMotionRoll\":359.6785,\"mz\":-21.58838,\"ax\":0.005610745,\"coreMotionPitch\":359.8929,\"coreMotionYaw\":155.5467,\"gx\":-0.004424463,\"ay\":-0.001868801,\"gy\":0.001250984,\"az\":0.9999825,\"mx\":-39.16922,\"roll\":350.7054},{\"pitch\":354.2748,\"gz\":0.0005337178,\"my\":-18.01405,\"yaw\":118.1411,\"coreMotionRoll\":359.68,\"mz\":-21.81163,\"ax\":0.005585566,\"coreMotionPitch\":359.8969,\"coreMotionYaw\":155.5484,\"gx\":-0.004427614,\"ay\":-0.001799988,\"gy\":0.00230322,\"az\":0.9999828,\"mx\":-39.39503,\"roll\":351.6176},{\"pitch\":354.5161,\"gz\":0.001573929,\"my\":-18.31421,\"yaw\":121.2901,\"coreMotionRoll\":359.6844,\"mz\":-21.51047,\"ax\":0.005508173,\"coreMotionPitch\":359.8969,\"coreMotionYaw\":155.5528,\"gx\":0.001984259,\"ay\":-0.001798682,\"gy\":-0.0008820838,\"az\":0.9999832,\"mx\":-39.62154,\"roll\":352.4596},{\"pitch\":354.8075,\"gz\":0.000482962,\"my\":-18.53923,\"yaw\":124.1971,\"coreMotionRoll\":359.6952,\"mz\":-21.43793,\"ax\":0.00532046,\"coreMotionPitch\":359.8993,\"coreMotionYaw\":155.5574,\"gx\":0.003046888,\"ay\":-0.00175722,\"gy\":0.0001624246,\"az\":0.9999843,\"mx\":-39.39789,\"roll\":353.2589},{\"pitch\":355.1059,\"gz\":0.001561856,\"my\":-18.68939,\"yaw\":126.8858,\"coreMotionRoll\":359.6972,\"mz\":-21.14021,\"ax\":0.005284442,\"coreMotionPitch\":359.9057,\"coreMotionYaw\":155.5623,\"gx\":-0.0001542046,\"ay\":-0.001645855,\"gy\":0.001234441,\"az\":0.9999847,\"mx\":-39.17342,\"roll\":354.0023},{\"pitch\":355.3894,\"gz\":0.002603529,\"my\":-18.38936,\"yaw\":129.4217,\"coreMotionRoll\":359.6907,\"mz\":-21.21255,\"ax\":0.005397901,\"coreMotionPitch\":359.9117,\"coreMotionYaw\":155.5687,\"gx\":0.00198162,\"ay\":-0.001541039,\"gy\":0.001235588,\"az\":0.9999843,\"mx\":-39.39658,\"roll\":354.652},{\"pitch\":355.6687,\"gz\":0.0004847745,\"my\":-18.38939,\"yaw\":131.7621,\"coreMotionRoll\":359.6879,\"mz\":-21.13629,\"ax\":0.005446805,\"coreMotionPitch\":359.908,\"coreMotionYaw\":155.5718,\"gx\":0.0009046478,\"ay\":-0.001605289,\"gy\":0.0001566671,\"az\":0.9999839,\"mx\":-39.54646,\"roll\":355.2295},{\"pitch\":355.92,\"gz\":0.0005062941,\"my\":-18.08934,\"yaw\":133.9038,\"coreMotionRoll\":359.6873,\"mz\":-21.21692,\"ax\":0.005458171,\"coreMotionPitch\":359.9076,\"coreMotionYaw\":155.5754,\"gx\":-0.00444238,\"ay\":-0.001612683,\"gy\":0.0001536806,\"az\":0.9999838,\"mx\":-38.79463,\"roll\":355.7503},{\"pitch\":356.1986,\"gz\":0.001534431,\"my\":-18.16428,\"yaw\":135.8723,\"coreMotionRoll\":359.6863,\"mz\":-21.36647,\"ax\":0.00547462,\"coreMotionPitch\":359.911,\"coreMotionYaw\":155.5792,\"gx\":-0.001236772,\"ay\":-0.00155253,\"gy\":0.00121535,\"az\":0.9999838,\"mx\":-38.87035,\"roll\":356.2238},{\"pitch\":356.4715,\"gz\":0.0004678846,\"my\":-18.31416,\"yaw\":137.6733,\"coreMotionRoll\":359.687,\"mz\":-21.58865,\"ax\":0.005462487,\"coreMotionPitch\":359.9157,\"coreMotionYaw\":155.583,\"gx\":-0.001240588,\"ay\":-0.001470953,\"gy\":0.00120634,\"az\":0.999984,\"mx\":-39.24664,\"roll\":356.643},{\"pitch\":356.7129,\"gz\":0.001535555,\"my\":-18.23914,\"yaw\":139.3323,\"coreMotionRoll\":359.6805,\"mz\":-21.66347,\"ax\":0.005575384,\"coreMotionPitch\":359.9179,\"coreMotionYaw\":155.5877,\"gx\":-0.004444705,\"ay\":-0.001432535,\"gy\":0.002269549,\"az\":0.9999834,\"mx\":-39.24628,\"roll\":357.0155},{\"pitch\":356.9751,\"gz\":-0.0006070503,\"my\":-18.31413,\"yaw\":140.8083,\"coreMotionRoll\":359.6846,\"mz\":-21.6662,\"ax\":0.005504036,\"coreMotionPitch\":359.9132,\"coreMotionYaw\":155.5912,\"gx\":-0.002317743,\"ay\":-0.00151554,\"gy\":0.0001205732,\"az\":0.9999837,\"mx\":-38.94676,\"roll\":357.3406},{\"pitch\":357.2334,\"gz\":0.0004406889,\"my\":-18.31436,\"yaw\":142.1909,\"coreMotionRoll\":359.6828,\"mz\":-21.21237,\"ax\":0.005536242,\"coreMotionPitch\":359.9135,\"coreMotionYaw\":155.5945,\"gx\":0.00195963,\"ay\":-0.001510022,\"gy\":-0.0009344265,\"az\":0.9999835,\"mx\":-39.39609,\"roll\":357.6137},{\"pitch\":357.4207,\"gz\":-0.0006419985,\"my\":-17.78943,\"yaw\":143.5224,\"coreMotionRoll\":359.6808,\"mz\":-21.05855,\"ax\":0.005571826,\"coreMotionPitch\":359.915,\"coreMotionYaw\":155.5983,\"gx\":-0.0001831505,\"ay\":-0.00148295,\"gy\":0.001170302,\"az\":0.9999834,\"mx\":-39.69244,\"roll\":357.8459},{\"pitch\":357.6596,\"gz\":0.0004323749,\"my\":-18.31444,\"yaw\":144.6353,\"coreMotionRoll\":359.6833,\"mz\":-21.06493,\"ax\":0.005526522,\"coreMotionPitch\":359.9124,\"coreMotionYaw\":155.6019,\"gx\":-0.0001798495,\"ay\":-0.001528975,\"gy\":0.0001182057,\"az\":0.9999835,\"mx\":-39.09587,\"roll\":358.0772},{\"pitch\":357.8608,\"gz\":0.001488912,\"my\":-18.01443,\"yaw\":145.6737,\"coreMotionRoll\":359.6803,\"mz\":-21.06612,\"ax\":0.005579283,\"coreMotionPitch\":359.9117,\"coreMotionYaw\":155.606,\"gx\":-0.000177448,\"ay\":-0.001540831,\"gy\":0.0001198155,\"az\":0.9999833,\"mx\":-38.86893,\"roll\":358.2698},{\"pitch\":358.0075,\"gz\":0.0004088411,\"my\":-17.63916,\"yaw\":146.6653,\"coreMotionRoll\":359.6817,\"mz\":-21.58827,\"ax\":0.005555403,\"coreMotionPitch\":359.9109,\"coreMotionYaw\":155.611,\"gx\":-0.001252046,\"ay\":-0.001555962,\"gy\":0.001166102,\"az\":0.9999834,\"mx\":-39.09227,\"roll\":358.4285},{\"pitch\":358.1768,\"gz\":0.002557534,\"my\":-17.93916,\"yaw\":147.5289,\"coreMotionRoll\":359.6823,\"mz\":-21.58965,\"ax\":0.005545975,\"coreMotionPitch\":359.9076,\"coreMotionYaw\":155.6157,\"gx\":-0.001245,\"ay\":-0.00161348,\"gy\":-0.0009387675,\"az\":0.9999833,\"mx\":-39.01921,\"roll\":358.5721},{\"pitch\":358.3682,\"gz\":-0.0006760737,\"my\":-18.31421,\"yaw\":148.248,\"coreMotionRoll\":359.6824,\"mz\":-21.51492,\"ax\":0.005542397,\"coreMotionPitch\":359.9034,\"coreMotionYaw\":155.6165,\"gx\":0.000878058,\"ay\":-0.001686718,\"gy\":8.802882e-05,\"az\":0.9999832,\"mx\":-39.09654,\"roll\":358.7157},{\"pitch\":358.5306,\"gz\":0.001444385,\"my\":-18.23917,\"yaw\":148.9154,\"coreMotionRoll\":359.6871,\"mz\":-21.59038,\"ax\":0.00546077,\"coreMotionPitch\":359.9043,\"coreMotionYaw\":155.6199,\"gx\":0.0008839994,\"ay\":-0.001670488,\"gy\":9.921527e-05,\"az\":0.9999837,\"mx\":-39.02116,\"roll\":358.8377},{\"pitch\":358.6822,\"gz\":0.001452167,\"my\":-18.53928,\"yaw\":149.5044,\"coreMotionRoll\":359.6908,\"mz\":-21.36293,\"ax\":0.005395923,\"coreMotionPitch\":359.9009,\"coreMotionYaw\":155.6214,\"gx\":0.0008832296,\"ay\":-0.001730008,\"gy\":-0.0009614732,\"az\":0.999984,\"mx\":-39.39778,\"roll\":358.942},{\"pitch\":358.8116,\"gz\":0.0003710037,\"my\":-18.61444,\"yaw\":150.0167,\"coreMotionRoll\":359.6853,\"mz\":-21.06375,\"ax\":0.005493084,\"coreMotionPitch\":359.9046,\"coreMotionYaw\":155.6238,\"gx\":-0.00125836,\"ay\":-0.001664342,\"gy\":0.001146106,\"az\":0.9999835,\"mx\":-39.32281,\"roll\":359.0448},{\"pitch\":358.922,\"gz\":0.002490931,\"my\":-18.31439,\"yaw\":150.5208,\"coreMotionRoll\":359.6854,\"mz\":-21.1393,\"ax\":0.005490921,\"coreMotionPitch\":359.9072,\"coreMotionYaw\":155.6289,\"gx\":0.000886303,\"ay\":-0.001619029,\"gy\":0.001163056,\"az\":0.9999836,\"mx\":-39.17097,\"roll\":359.1237},{\"pitch\":359.0396,\"gz\":0.0003535832,\"my\":-18.38936,\"yaw\":150.9379,\"coreMotionRoll\":359.6839,\"mz\":-21.21638,\"ax\":0.005517023,\"coreMotionPitch\":359.9078,\"coreMotionYaw\":155.6321,\"gx\":0.001946289,\"ay\":-0.001608678,\"gy\":-0.0009843793,\"az\":0.9999835,\"mx\":-38.94658,\"roll\":359.1859},{\"pitch\":359.0986,\"gz\":-0.0007263452,\"my\":-17.93947,\"yaw\":151.3752,\"coreMotionRoll\":359.6841,\"mz\":-20.98965,\"ax\":0.005512783,\"coreMotionPitch\":359.9089,\"coreMotionYaw\":155.6332,\"gx\":-0.0001948564,\"ay\":-0.001589929,\"gy\":0.00112442,\"az\":0.9999835,\"mx\":-39.01831,\"roll\":359.2368},{\"pitch\":359.1959,\"gz\":0.001393586,\"my\":-18.31424,\"yaw\":151.7253,\"coreMotionRoll\":359.6833,\"mz\":-21.44057,\"ax\":0.00552692,\"coreMotionPitch\":359.9092,\"coreMotionYaw\":155.6384,\"gx\":0.001949256,\"ay\":-0.001585012,\"gy\":0.001141037,\"az\":0.9999835,\"mx\":-39.02142,\"roll\":359.2956},{\"pitch\":359.2708,\"gz\":0.0003224445,\"my\":-18.08926,\"yaw\":152.0519,\"coreMotionRoll\":359.6842,\"mz\":-21.36693,\"ax\":0.005511577,\"coreMotionPitch\":359.906,\"coreMotionYaw\":155.6406,\"gx\":0.00194362,\"ay\":-0.001640038,\"gy\":6.564402e-05,\"az\":0.9999835,\"mx\":-38.79486,\"roll\":359.3361},{\"pitch\":359.3327,\"gz\":0.0003183155,\"my\":-18.08928,\"yaw\":152.3552,\"coreMotionRoll\":359.6872,\"mz\":-21.36565,\"ax\":0.005459195,\"coreMotionPitch\":359.9019,\"coreMotionYaw\":155.6425,\"gx\":0.001941743,\"ay\":-0.001712768,\"gy\":-0.001000705,\"az\":0.9999836,\"mx\":-38.94485,\"roll\":359.3657},{\"pitch\":359.3968,\"gz\":0.000323965,\"my\":-18.31419,\"yaw\":152.5854,\"coreMotionRoll\":359.6831,\"mz\":-21.51749,\"ax\":0.005530021,\"coreMotionPitch\":359.8974,\"coreMotionYaw\":155.6455,\"gx\":-0.0001958435,\"ay\":-0.001790159,\"gy\":6.14348e-05,\"az\":0.9999831,\"mx\":-38.79654,\"roll\":359.4079},{\"pitch\":359.4584,\"gz\":0.0002978705,\"my\":-18.46431,\"yaw\":152.7927,\"coreMotionRoll\":359.6838,\"mz\":-21.2903,\"ax\":0.005518876,\"coreMotionPitch\":359.8971,\"coreMotionYaw\":155.649,\"gx\":0.0008709485,\"ay\":-0.001796427,\"gy\":0.001116991,\"az\":0.9999831,\"mx\":-39.09718,\"roll\":359.4492},{\"pitch\":359.4964,\"gz\":0.002430052,\"my\":-18.31444,\"yaw\":153.0076,\"coreMotionRoll\":359.6801,\"mz\":-21.06557,\"ax\":0.005582965,\"coreMotionPitch\":359.8929,\"coreMotionYaw\":155.655,\"gx\":-0.0001904502,\"ay\":-0.00186848,\"gy\":0.002196129,\"az\":0.9999827,\"mx\":-39.02087,\"roll\":359.4843},{\"pitch\":359.5302,\"gz\":0.0003003032,\"my\":-18.31436,\"yaw\":153.1934,\"coreMotionRoll\":359.6832,\"mz\":-21.21492,\"ax\":0.005528975,\"coreMotionPitch\":359.8905,\"coreMotionYaw\":155.6588,\"gx\":-0.000199997,\"ay\":-0.001911107,\"gy\":5.067863e-05,\"az\":0.9999829,\"mx\":-39.09608,\"roll\":359.5024},{\"pitch\":359.5507,\"gz\":0.001362351,\"my\":-18.16431,\"yaw\":153.3761,\"coreMotionRoll\":359.6797,\"mz\":-21.29083,\"ax\":0.005589877,\"coreMotionPitch\":359.8876,\"coreMotionYaw\":155.6641,\"gx\":-0.001266798,\"ay\":-0.00196175,\"gy\":5.469121e-05,\"az\":0.9999825,\"mx\":-38.94524,\"roll\":359.5161},{\"pitch\":359.5828,\"gz\":-0.001858426,\"my\":-18.08936,\"yaw\":153.5321,\"coreMotionRoll\":359.6801,\"mz\":-21.21565,\"ax\":0.005582666,\"coreMotionPitch\":359.8938,\"coreMotionYaw\":155.6668,\"gx\":0.00085936,\"ay\":-0.001853688,\"gy\":0.001088615,\"az\":0.9999827,\"mx\":-38.94463,\"roll\":359.5336},{\"pitch\":359.61,\"gz\":0.0002865542,\"my\":-18.01416,\"yaw\":153.6886,\"coreMotionRoll\":359.6766,\"mz\":-21.59111,\"ax\":0.005643997,\"coreMotionPitch\":359.8948,\"coreMotionYaw\":155.6696,\"gx\":0.00086443,\"ay\":-0.001836,\"gy\":-0.002083542,\"az\":0.9999824,\"mx\":-38.86971,\"roll\":359.5301},{\"pitch\":359.6421,\"gz\":0.0002677446,\"my\":-18.31416,\"yaw\":153.8206,\"coreMotionRoll\":359.6695,\"mz\":-21.58737,\"ax\":0.005768515,\"coreMotionPitch\":359.8997,\"coreMotionYaw\":155.672,\"gx\":0.0008621584,\"ay\":-0.001751178,\"gy\":-0.001028397,\"az\":0.9999818,\"mx\":-39.39665,\"roll\":359.5369},{\"pitch\":359.6776,\"gz\":0.001346652,\"my\":-18.53912,\"yaw\":153.8875,\"coreMotionRoll\":359.6727,\"mz\":-21.66612,\"ax\":0.005712711,\"coreMotionPitch\":359.8927,\"coreMotionYaw\":155.675,\"gx\":-0.002340297,\"ay\":-0.00187299,\"gy\":4.35768e-05,\"az\":0.9999819,\"mx\":-39.02322,\"roll\":359.564},{\"pitch\":359.7129,\"gz\":0.002374081,\"my\":-18.46428,\"yaw\":153.9758,\"coreMotionRoll\":359.6767,\"mz\":-21.36465,\"ax\":0.005642672,\"coreMotionPitch\":359.8937,\"coreMotionYaw\":155.678,\"gx\":0.0008655287,\"ay\":-0.001855152,\"gy\":0.001107736,\"az\":0.9999824,\"mx\":-39.17229,\"roll\":359.5866},{\"pitch\":359.7239,\"gz\":0.0002553217,\"my\":-18.31429,\"yaw\":154.0709,\"coreMotionRoll\":359.6729,\"mz\":-21.36365,\"ax\":0.005708193,\"coreMotionPitch\":359.8948,\"coreMotionYaw\":155.6818,\"gx\":-0.0002102108,\"ay\":-0.001835916,\"gy\":2.929562e-05,\"az\":0.999982,\"mx\":-39.24631,\"roll\":359.5916},{\"pitch\":359.7473,\"gz\":0.000242449,\"my\":-18.53938,\"yaw\":154.1187,\"coreMotionRoll\":359.674,\"mz\":-21.13985,\"ax\":0.005689398,\"coreMotionPitch\":359.8947,\"coreMotionYaw\":155.6855,\"gx\":-0.001281816,\"ay\":-0.001837701,\"gy\":0.001086296,\"az\":0.9999821,\"mx\":-39.17244,\"roll\":359.6113},{\"pitch\":359.7703,\"gz\":0.000219234,\"my\":-18.31429,\"yaw\":154.1891,\"coreMotionRoll\":359.6696,\"mz\":-21.36493,\"ax\":0.005766772,\"coreMotionPitch\":359.8937,\"coreMotionYaw\":155.6887,\"gx\":0.001920773,\"ay\":-0.001855326,\"gy\":1.864502e-05,\"az\":0.9999816,\"mx\":-39.09631,\"roll\":359.6132},{\"pitch\":359.7554,\"gz\":-0.0008262666,\"my\":-18.08928,\"yaw\":154.2985,\"coreMotionRoll\":359.6705,\"mz\":-21.36183,\"ax\":0.005750468,\"coreMotionPitch\":359.8961,\"coreMotionYaw\":155.6918,\"gx\":-0.0002199278,\"ay\":-0.001813869,\"gy\":-0.001049811,\"az\":0.9999818,\"mx\":-39.39485,\"roll\":359.5996},{\"pitch\":359.7643,\"gz\":-0.000852853,\"my\":-18.08928,\"yaw\":154.3638,\"coreMotionRoll\":359.6667,\"mz\":-21.36565,\"ax\":0.005817236,\"coreMotionPitch\":359.8947,\"coreMotionYaw\":155.6954,\"gx\":-0.0002223363,\"ay\":-0.001837735,\"gy\":0.001067633,\"az\":0.9999814,\"mx\":-38.94485,\"roll\":359.6096},{\"pitch\":359.7414,\"gz\":0.0002006195,\"my\":-17.86411,\"yaw\":154.4743,\"coreMotionRoll\":359.6642,\"mz\":-21.73819,\"ax\":0.005859886,\"coreMotionPitch\":359.8987,\"coreMotionYaw\":155.6987,\"gx\":-0.002357262,\"ay\":-0.001767978,\"gy\":0.003195216,\"az\":0.9999813,\"mx\":-39.16895,\"roll\":359.6188},{\"pitch\":359.7838,\"gz\":0.002313891,\"my\":-18.38916,\"yaw\":154.5129,\"coreMotionRoll\":359.6642,\"mz\":-21.58884,\"ax\":0.005861111,\"coreMotionPitch\":359.9065,\"coreMotionYaw\":155.7029,\"gx\":0.0008558103,\"ay\":-0.001631279,\"gy\":0.003211278,\"az\":0.9999815,\"mx\":-39.24713,\"roll\":359.6435},{\"pitch\":359.8412,\"gz\":0.001245286,\"my\":-18.46422,\"yaw\":154.5028,\"coreMotionRoll\":359.6617,\"mz\":-21.44284,\"ax\":0.005905428,\"coreMotionPitch\":359.9144,\"coreMotionYaw\":155.7062,\"gx\":0.001919213,\"ay\":-0.001493907,\"gy\":0.001075008,\"az\":0.9999815,\"mx\":-38.79741,\"roll\":359.6578},{\"pitch\":359.8787,\"gz\":0.000178749,\"my\":-18.53928,\"yaw\":154.4913,\"coreMotionRoll\":359.6616,\"mz\":-21.36676,\"ax\":0.005905708,\"coreMotionPitch\":359.9118,\"coreMotionYaw\":155.7085,\"gx\":0.001915198,\"ay\":-0.001538745,\"gy\":0.001066701,\"az\":0.9999814,\"mx\":-38.94778,\"roll\":359.6668},{\"pitch\":359.8863,\"gz\":0.0001884511,\"my\":-18.53935,\"yaw\":154.4988,\"coreMotionRoll\":359.6617,\"mz\":-21.21484,\"ax\":0.005903488,\"coreMotionPitch\":359.9173,\"coreMotionYaw\":155.7122,\"gx\":-0.0002242047,\"ay\":-0.001443823,\"gy\":2.554371e-06,\"az\":0.9999815,\"mx\":-39.17256,\"roll\":359.6633},{\"pitch\":359.8768,\"gz\":-0.0008971599,\"my\":-18.23938,\"yaw\":154.5172,\"coreMotionRoll\":359.6648,\"mz\":-21.1423,\"ax\":0.005849991,\"coreMotionPitch\":359.9123,\"coreMotionYaw\":155.7166,\"gx\":-0.001299684,\"ay\":-0.00153151,\"gy\":0.002113198,\"az\":0.9999817,\"mx\":-38.7955,\"roll\":359.6696},{\"pitch\":359.8603,\"gz\":0.001237156,\"my\":-18.08939,\"yaw\":154.5763,\"coreMotionRoll\":359.664,\"mz\":-21.14066,\"ax\":0.005864511,\"coreMotionPitch\":359.904,\"coreMotionYaw\":155.719,\"gx\":-0.0002242621,\"ay\":-0.001675481,\"gy\":0.001068724,\"az\":0.9999814,\"mx\":-38.94452,\"roll\":359.662},{\"pitch\":359.8472,\"gz\":-0.0008982651,\"my\":-18.08928,\"yaw\":154.6257,\"coreMotionRoll\":359.6601,\"mz\":-21.36438,\"ax\":0.00593221,\"coreMotionPitch\":359.9021,\"coreMotionYaw\":155.7214,\"gx\":-0.0002350071,\"ay\":-0.001708112,\"gy\":-1.464539e-05,\"az\":0.9999809,\"mx\":-39.09485,\"roll\":359.6491},{\"pitch\":359.8421,\"gz\":0.002284326,\"my\":-18.08916,\"yaw\":154.6852,\"coreMotionRoll\":359.667,\"mz\":-21.58937,\"ax\":0.005811661,\"coreMotionPitch\":359.906,\"coreMotionYaw\":155.7257,\"gx\":-0.000226808,\"ay\":-0.001640512,\"gy\":0.001068849,\"az\":0.9999818,\"mx\":-39.09518,\"roll\":359.6495},{\"pitch\":359.8734,\"gz\":0.002284387,\"my\":-18.4641,\"yaw\":154.6684,\"coreMotionRoll\":359.6665,\"mz\":-21.7422,\"ax\":0.005820593,\"coreMotionPitch\":359.9047,\"coreMotionYaw\":155.7283,\"gx\":-0.0002274263,\"ay\":-0.001663727,\"gy\":0.001069049,\"az\":0.9999817,\"mx\":-38.87286,\"roll\":359.6662},{\"pitch\":359.8829,\"gz\":0.001216387,\"my\":-18.38916,\"yaw\":154.6761,\"coreMotionRoll\":359.6671,\"mz\":-21.5901,\"ax\":0.005810787,\"coreMotionPitch\":359.9101,\"coreMotionYaw\":155.731,\"gx\":-0.0002337184,\"ay\":-0.001568523,\"gy\":-5.808123e-06,\"az\":0.9999819,\"mx\":-39.09714,\"roll\":359.6656},{\"pitch\":359.9116,\"gz\":0.0001565078,\"my\":-18.68915,\"yaw\":154.614,\"coreMotionRoll\":359.662,\"mz\":-21.5934,\"ax\":0.005899329,\"coreMotionPitch\":359.9053,\"coreMotionYaw\":155.7327,\"gx\":-0.001306321,\"ay\":-0.001652278,\"gy\":-1.414373e-05,\"az\":0.9999812,\"mx\":-38.79909,\"roll\":359.6776},{\"pitch\":359.9003,\"gz\":0.002294919,\"my\":-18.31438,\"yaw\":154.6218,\"coreMotionRoll\":359.6581,\"mz\":-21.14313,\"ax\":0.005966361,\"coreMotionPitch\":359.909,\"coreMotionYaw\":155.7365,\"gx\":-0.002370207,\"ay\":-0.001589088,\"gy\":-0.001062803,\"az\":0.9999809,\"mx\":-38.72098,\"roll\":359.6664},{\"pitch\":359.8978,\"gz\":0.001198698,\"my\":-18.31451,\"yaw\":154.6373,\"coreMotionRoll\":359.6576,\"mz\":-20.91621,\"ax\":0.005976182,\"coreMotionPitch\":359.9089,\"coreMotionYaw\":155.7399,\"gx\":-0.0002405035,\"ay\":-0.001589527,\"gy\":-1.635341e-05,\"az\":0.9999809,\"mx\":-38.94565,\"roll\":359.6612},{\"pitch\":359.8803,\"gz\":0.002249905,\"my\":-18.01439,\"yaw\":154.6942,\"coreMotionRoll\":359.6583,\"mz\":-21.14111,\"ax\":0.005963117,\"coreMotionPitch\":359.9108,\"coreMotionYaw\":155.7422,\"gx\":-0.0002367597,\"ay\":-0.001557356,\"gy\":0.002115191,\"az\":0.999981,\"mx\":-38.86903,\"roll\":359.6617},{\"pitch\":359.8997,\"gz\":0.0001169614,\"my\":-18.38951,\"yaw\":154.6834,\"coreMotionRoll\":359.6585,\"mz\":-20.9164,\"ax\":0.005960138,\"coreMotionPitch\":359.9127,\"coreMotionYaw\":155.7455,\"gx\":0.00082065,\"ay\":-0.00152324,\"gy\":-3.083424e-05,\"az\":0.9999811,\"mx\":-38.94614,\"roll\":359.6624},{\"pitch\":359.8754,\"gz\":0.0001087592,\"my\":-17.93921,\"yaw\":154.7589,\"coreMotionRoll\":359.6603,\"mz\":-21.51274,\"ax\":0.005928389,\"coreMotionPitch\":359.9172,\"coreMotionYaw\":155.7483,\"gx\":0.0008169377,\"ay\":-0.00144579,\"gy\":-3.622272e-05,\"az\":0.9999814,\"mx\":-39.24409,\"roll\":359.645},{\"pitch\":359.8825,\"gz\":0.0022508,\"my\":-18.01428,\"yaw\":154.8048,\"coreMotionRoll\":359.6567,\"mz\":-21.36546,\"ax\":0.00599105,\"coreMotionPitch\":359.9157,\"coreMotionYaw\":155.7526,\"gx\":0.001892513,\"ay\":-0.001470521,\"gy\":-0.002141378,\"az\":0.999981,\"mx\":-38.94437,\"roll\":359.6291},{\"pitch\":359.9279,\"gz\":0.001124281,\"my\":-18.38916,\"yaw\":154.7852,\"coreMotionRoll\":359.6555,\"mz\":-21.59138,\"ax\":0.006012325,\"coreMotionPitch\":359.921,\"coreMotionYaw\":155.7544,\"gx\":0.004022044,\"ay\":-0.001378863,\"gy\":0.00314972,\"az\":0.999981,\"mx\":-38.94714,\"roll\":359.6591},{\"pitch\":359.9285,\"gz\":0.0001142053,\"my\":-18.38928,\"yaw\":154.7657,\"coreMotionRoll\":359.6596,\"mz\":-21.36638,\"ax\":0.005941701,\"coreMotionPitch\":359.9223,\"coreMotionYaw\":155.7583,\"gx\":-0.001324355,\"ay\":-0.001356568,\"gy\":-3.943795e-05,\"az\":0.9999814,\"mx\":-38.94681,\"roll\":359.6627},{\"pitch\":359.9272,\"gz\":0.001159225,\"my\":-18.31424,\"yaw\":154.7803,\"coreMotionRoll\":359.6572,\"mz\":-21.43929,\"ax\":0.005982703,\"coreMotionPitch\":359.9214,\"coreMotionYaw\":155.761,\"gx\":0.0008127298,\"ay\":-0.001371237,\"gy\":-3.747539e-05,\"az\":0.9999812,\"mx\":-39.17143,\"roll\":359.6584},{\"pitch\":359.9293,\"gz\":0.00113701,\"my\":-18.2394,\"yaw\":154.7987,\"coreMotionRoll\":359.6617,\"mz\":-21.13976,\"ax\":0.005904581,\"coreMotionPitch\":359.9175,\"coreMotionYaw\":155.763,\"gx\":0.001877649,\"ay\":-0.001439381,\"gy\":0.001018284,\"az\":0.9999815,\"mx\":-39.09549,\"roll\":359.6617},{\"pitch\":359.9007,\"gz\":0.0001002991,\"my\":-17.8644,\"yaw\":154.868,\"coreMotionRoll\":359.664,\"mz\":-21.1382,\"ax\":0.005863473,\"coreMotionPitch\":359.9219,\"coreMotionYaw\":155.765,\"gx\":0.0008056783,\"ay\":-0.001363285,\"gy\":-0.002173202,\"az\":0.9999819,\"mx\":-39.16805,\"roll\":359.6357},{\"pitch\":359.902,\"gz\":-0.001005166,\"my\":-17.86438,\"yaw\":154.881,\"coreMotionRoll\":359.6636,\"mz\":-21.1433,\"ax\":0.00587072,\"coreMotionPitch\":359.9174,\"coreMotionYaw\":155.7661,\"gx\":0.0007983968,\"ay\":-0.001441308,\"gy\":0.002057342,\"az\":0.9999817,\"mx\":-38.56805,\"roll\":359.6506},{\"pitch\":359.8935,\"gz\":5.410878e-05,\"my\":-17.78923,\"yaw\":154.9343,\"coreMotionRoll\":359.6636,\"mz\":-21.43991,\"ax\":0.005870806,\"coreMotionPitch\":359.9207,\"coreMotionYaw\":155.7689,\"gx\":0.00186675,\"ay\":-0.00138456,\"gy\":0.0009994169,\"az\":0.9999818,\"mx\":-38.94301,\"roll\":359.6479},{\"pitch\":359.9095,\"gz\":6.854608e-05,\"my\":-18.01427,\"yaw\":154.9335,\"coreMotionRoll\":359.6608,\"mz\":-21.36739,\"ax\":0.005920298,\"coreMotionPitch\":359.9296,\"coreMotionYaw\":155.7714,\"gx\":0.0007986229,\"ay\":-0.001228037,\"gy\":-6.097496e-05,\"az\":0.9999817,\"mx\":-38.71938,\"roll\":359.6511},{\"pitch\":359.9266,\"gz\":8.220971e-05,\"my\":-18.2392,\"yaw\":154.9061,\"coreMotionRoll\":359.6626,\"mz\":-21.5173,\"ax\":0.005888144,\"coreMotionPitch\":359.9278,\"coreMotionYaw\":155.7736,\"gx\":-0.0002743814,\"ay\":-0.001260467,\"gy\":-0.002187825,\"az\":0.9999819,\"mx\":-38.79605,\"roll\":359.6481},{\"pitch\":359.9484,\"gz\":0.001127827,\"my\":-18.2392,\"yaw\":154.8887,\"coreMotionRoll\":359.6602,\"mz\":-21.5173,\"ax\":0.005930542,\"coreMotionPitch\":359.9287,\"coreMotionYaw\":155.7751,\"gx\":0.00186594,\"ay\":-0.001243927,\"gy\":-0.001118763,\"az\":0.9999816,\"mx\":-38.79605,\"roll\":359.6502},{\"pitch\":359.955,\"gz\":0.001124712,\"my\":-18.38921,\"yaw\":154.8632,\"coreMotionRoll\":359.6668,\"mz\":-21.51639,\"ax\":0.005815781,\"coreMotionPitch\":359.9264,\"coreMotionYaw\":155.7782,\"gx\":-0.0002766182,\"ay\":-0.001284062,\"gy\":-6.098098e-05,\"az\":0.9999822,\"mx\":-38.94702,\"roll\":359.661},{\"pitch\":359.9499,\"gz\":0.001109007,\"my\":-18.2394,\"yaw\":154.8578,\"coreMotionRoll\":359.6606,\"mz\":-21.14166,\"ax\":0.005922814,\"coreMotionPitch\":359.9247,\"coreMotionYaw\":155.7823,\"gx\":-0.0002823584,\"ay\":-0.001313822,\"gy\":0.0009953977,\"az\":0.9999816,\"mx\":-38.8705,\"roll\":359.6681},{\"pitch\":359.9657,\"gz\":4.913116e-05,\"my\":-18.53937,\"yaw\":154.7884,\"coreMotionRoll\":359.6642,\"mz\":-21.14432,\"ax\":0.005860441,\"coreMotionPitch\":359.9213,\"coreMotionYaw\":155.7842,\"gx\":-0.001354884,\"ay\":-0.001373942,\"gy\":0.0009879353,\"az\":0.9999819,\"mx\":-38.64745,\"roll\":359.6866},{\"pitch\":359.9386,\"gz\":2.78604e-05,\"my\":-17.86423,\"yaw\":154.8312,\"coreMotionRoll\":359.6661,\"mz\":-21.44202,\"ax\":0.005827811,\"coreMotionPitch\":359.9259,\"coreMotionYaw\":155.7871,\"gx\":0.0007762215,\"ay\":-0.00129347,\"gy\":0.0009824397,\"az\":0.9999822,\"mx\":-38.71851,\"roll\":359.6759},{\"pitch\":359.9365,\"gz\":0.001095574,\"my\":-17.93927,\"yaw\":154.852,\"coreMotionRoll\":359.6679,\"mz\":-21.36847,\"ax\":0.005795379,\"coreMotionPitch\":359.9203,\"coreMotionYaw\":155.7909,\"gx\":0.001841511,\"ay\":-0.001390649,\"gy\":-0.001136112,\"az\":0.9999822,\"mx\":-38.56888,\"roll\":359.6636},{\"pitch\":359.9454,\"gz\":3.569209e-05,\"my\":-18.08914,\"yaw\":154.8372,\"coreMotionRoll\":359.668,\"mz\":-21.59448,\"ax\":0.00579413,\"coreMotionPitch\":359.9279,\"coreMotionYaw\":155.7944,\"gx\":0.0007696724,\"ay\":-0.001259047,\"gy\":-0.001144375,\"az\":0.9999824,\"mx\":-38.49519,\"roll\":359.6614},{\"pitch\":359.9269,\"gz\":0.001081324,\"my\":-17.86421,\"yaw\":154.908,\"coreMotionRoll\":359.6652,\"mz\":-21.5132,\"ax\":0.005843141,\"coreMotionPitch\":359.9301,\"coreMotionYaw\":155.7946,\"gx\":0.002903674,\"ay\":-0.001219491,\"gy\":-0.001140548,\"az\":0.9999822,\"mx\":-39.16861,\"roll\":359.6419},{\"pitch\":359.9437,\"gz\":0.00108032,\"my\":-18.16411,\"yaw\":154.9007,\"coreMotionRoll\":359.6626,\"mz\":-21.66711,\"ax\":0.0058885,\"coreMotionPitch\":359.9286,\"coreMotionYaw\":155.7983,\"gx\":0.001834843,\"ay\":-0.001246833,\"gy\":-7.860897e-05,\"az\":0.9999819,\"mx\":-38.79579,\"roll\":359.65},{\"pitch\":359.9607,\"gz\":-0.001062647,\"my\":-18.5392,\"yaw\":154.8401,\"coreMotionRoll\":359.663,\"mz\":-21.51675,\"ax\":0.005882406,\"coreMotionPitch\":359.9214,\"coreMotionYaw\":155.8016,\"gx\":-0.0003168708,\"ay\":-0.001372168,\"gy\":0.002023863,\"az\":0.9999818,\"mx\":-38.948,\"roll\":359.676},{\"pitch\":359.9751,\"gz\":-3.725319e-06,\"my\":-18.38914,\"yaw\":154.7792,\"coreMotionRoll\":359.6585,\"mz\":-21.59584,\"ax\":0.005960548,\"coreMotionPitch\":359.9199,\"coreMotionYaw\":155.8051,\"gx\":-0.0003201356,\"ay\":-0.001398777,\"gy\":0.00202894,\"az\":0.9999813,\"mx\":-38.42215,\"roll\":359.6944},{\"pitch\":359.9478,\"gz\":0.001086104,\"my\":-18.16438,\"yaw\":154.8015,\"coreMotionRoll\":359.6562,\"mz\":-21.14084,\"ax\":0.006001029,\"coreMotionPitch\":359.913,\"coreMotionYaw\":155.8081,\"gx\":-0.0003170621,\"ay\":-0.001518569,\"gy\":-0.001145929,\"az\":0.9999809,\"mx\":-38.94501,\"roll\":359.6728},{\"pitch\":359.9492,\"gz\":-1.810729e-05,\"my\":-18.23935,\"yaw\":154.787,\"coreMotionRoll\":359.6555,\"mz\":-21.21793,\"ax\":0.006012845,\"coreMotionPitch\":359.9166,\"coreMotionYaw\":155.8105,\"gx\":0.0007412111,\"ay\":-0.001454916,\"gy\":0.002024856,\"az\":0.9999809,\"mx\":-38.72061,\"roll\":359.681},{\"pitch\":359.9413,\"gz\":-0.001069375,\"my\":-17.8643,\"yaw\":154.7874,\"coreMotionRoll\":359.6542,\"mz\":-21.29648,\"ax\":0.006035341,\"coreMotionPitch\":359.918,\"coreMotionYaw\":155.812,\"gx\":0.0007306023,\"ay\":-0.00143063,\"gy\":-0.001171363,\"az\":0.9999807,\"mx\":-38.19328,\"roll\":359.6646},{\"pitch\":359.908,\"gz\":0.002122753,\"my\":-17.78928,\"yaw\":154.8655,\"coreMotionRoll\":359.658,\"mz\":-21.36491,\"ax\":0.005969443,\"coreMotionPitch\":359.9176,\"coreMotionYaw\":155.8146,\"gx\":0.0007415022,\"ay\":-0.001438308,\"gy\":-8.313576e-05,\"az\":0.9999812,\"mx\":-38.9429,\"roll\":359.6474},{\"pitch\":359.9121,\"gz\":-2.616154e-05,\"my\":-18.08913,\"yaw\":154.8723,\"coreMotionRoll\":359.6625,\"mz\":-21.66629,\"ax\":0.005890884,\"coreMotionPitch\":359.9182,\"coreMotionYaw\":155.8158,\"gx\":0.0007270203,\"ay\":-0.001427203,\"gy\":0.0009576986,\"az\":0.9999816,\"mx\":-38.8703,\"roll\":359.655},{\"pitch\":359.8958,\"gz\":-2.050936e-05,\"my\":-18.01402,\"yaw\":154.8943,\"coreMotionRoll\":359.6563,\"mz\":-21.89046,\"ax\":0.005997957,\"coreMotionPitch\":359.9169,\"coreMotionYaw\":155.8181,\"gx\":-0.001410058,\"ay\":-0.001450792,\"gy\":0.002019742,\"az\":0.999981,\"mx\":-38.94514,\"roll\":359.6608},{\"pitch\":359.8979,\"gz\":-0.001088004,\"my\":-18.31416,\"yaw\":154.8795,\"coreMotionRoll\":359.6522,\"mz\":-21.58929,\"ax\":0.006070395,\"coreMotionPitch\":359.9136,\"coreMotionYaw\":155.8198,\"gx\":-0.001421549,\"ay\":-0.00150778,\"gy\":0.0009465707,\"az\":0.9999804,\"mx\":-39.17165,\"roll\":359.6646},{\"pitch\":359.8875,\"gz\":0.001032306,\"my\":-18.01428,\"yaw\":154.936,\"coreMotionRoll\":359.6476,\"mz\":-21.36165,\"ax\":0.006150594,\"coreMotionPitch\":359.9073,\"coreMotionYaw\":155.8235,\"gx\":0.00178377,\"ay\":-0.001617995,\"gy\":-0.001162973,\"az\":0.9999798,\"mx\":-39.39436,\"roll\":359.642},{\"pitch\":359.9281,\"gz\":0.001039025,\"my\":-18.6144,\"yaw\":154.8738,\"coreMotionRoll\":359.6471,\"mz\":-21.14131,\"ax\":0.00615899,\"coreMotionPitch\":359.9081,\"coreMotionYaw\":155.8264,\"gx\":0.0007152386,\"ay\":-0.00160405,\"gy\":-0.001162,\"az\":0.9999797,\"mx\":-39.02293,\"roll\":359.651},{\"pitch\":359.9289,\"gz\":-0.002163854,\"my\":-18.38931,\"yaw\":154.8312,\"coreMotionRoll\":359.6569,\"mz\":-21.29138,\"ax\":0.0059877,\"coreMotionPitch\":359.909,\"coreMotionYaw\":155.827,\"gx\":-0.001440003,\"ay\":-0.001588832,\"gy\":-0.0001279038,\"az\":0.9999808,\"mx\":-38.94669,\"roll\":359.658},{\"pitch\":359.9239,\"gz\":0.00100519,\"my\":-18.31429,\"yaw\":154.832,\"coreMotionRoll\":359.6603,\"mz\":-21.36493,\"ax\":0.005929435,\"coreMotionPitch\":359.9109,\"coreMotionYaw\":155.8292,\"gx\":-0.0003676236,\"ay\":-0.001554985,\"gy\":0.002018483,\"az\":0.9999812,\"mx\":-39.09631,\"roll\":359.67},{\"pitch\":359.9006,\"gz\":-3.04549e-05,\"my\":-18.0891,\"yaw\":154.8741,\"coreMotionRoll\":359.6591,\"mz\":-21.73746,\"ax\":0.005948895,\"coreMotionPitch\":359.9168,\"coreMotionYaw\":155.8313,\"gx\":-0.0003708867,\"ay\":-0.001451327,\"gy\":-0.002235075,\"az\":0.9999812,\"mx\":-39.3204,\"roll\":359.645},{\"pitch\":359.9078,\"gz\":-6.88315e-05,\"my\":-18.16428,\"yaw\":154.8736,\"coreMotionRoll\":359.6614,\"mz\":-21.36583,\"ax\":0.005908887,\"coreMotionPitch\":359.9109,\"coreMotionYaw\":155.8313,\"gx\":0.0006895815,\"ay\":-0.001554255,\"gy\":0.0009464303,\"az\":0.9999813,\"mx\":-38.94534,\"roll\":359.6544},{\"pitch\":359.8741,\"gz\":0.001019934,\"my\":-17.93921,\"yaw\":154.9464,\"coreMotionRoll\":359.6666,\"mz\":-21.51082,\"ax\":0.005818787,\"coreMotionPitch\":359.9037,\"coreMotionYaw\":155.8331,\"gx\":-0.0003755821,\"ay\":-0.001681595,\"gy\":-0.001166198,\"az\":0.9999816,\"mx\":-39.4691,\"roll\":359.6369},{\"pitch\":359.8997,\"gz\":-0.001128626,\"my\":-18.38913,\"yaw\":154.9127,\"coreMotionRoll\":359.6644,\"mz\":-21.66447,\"ax\":0.005857465,\"coreMotionPitch\":359.9039,\"coreMotionYaw\":155.8342,\"gx\":0.0006781357,\"ay\":-0.001677349,\"gy\":-0.001185907,\"az\":0.9999815,\"mx\":-39.17226,\"roll\":359.6441},{\"pitch\":359.8892,\"gz\":-6.672789e-05,\"my\":-18.53928,\"yaw\":154.8892,\"coreMotionRoll\":359.6684,\"mz\":-21.36229,\"ax\":0.005786981,\"coreMotionPitch\":359.8938,\"coreMotionYaw\":155.8386,\"gx\":-0.003598522,\"ay\":-0.001853216,\"gy\":0.002008032,\"az\":0.9999815,\"mx\":-39.47278,\"roll\":359.6664},{\"pitch\":359.891,\"gz\":-0.001137792,\"my\":-18.4642,\"yaw\":154.8833,\"coreMotionRoll\":359.6646,\"mz\":-21.51083,\"ax\":0.005854308,\"coreMotionPitch\":359.9018,\"coreMotionYaw\":155.8406,\"gx\":-0.0003965655,\"ay\":-0.001713317,\"gy\":-0.0001247618,\"az\":0.9999814,\"mx\":-39.62251,\"roll\":359.6645},{\"pitch\":359.8979,\"gz\":-8.093432e-05,\"my\":-18.46428,\"yaw\":154.8588,\"coreMotionRoll\":359.6733,\"mz\":-21.36401,\"ax\":0.005701552,\"coreMotionPitch\":359.9037,\"coreMotionYaw\":155.8414,\"gx\":-0.001467434,\"ay\":-0.001681254,\"gy\":0.0009459883,\"az\":0.9999824,\"mx\":-39.24728,\"roll\":359.6767},{\"pitch\":359.8862,\"gz\":0.0009794546,\"my\":-18.08939,\"yaw\":154.9023,\"coreMotionRoll\":359.6749,\"mz\":-21.13748,\"ax\":0.005673563,\"coreMotionPitch\":359.903,\"coreMotionYaw\":155.8415,\"gx\":0.0006673924,\"ay\":-0.00169191,\"gy\":-0.001168901,\"az\":0.9999825,\"mx\":-39.31952,\"roll\":359.6613},{\"pitch\":359.8816,\"gz\":0.002040521,\"my\":-17.93906,\"yaw\":154.9713,\"coreMotionRoll\":359.6729,\"mz\":-21.81145,\"ax\":0.005708294,\"coreMotionPitch\":359.9087,\"coreMotionYaw\":155.844,\"gx\":0.0028079,\"ay\":-0.001593561,\"gy\":-0.002222034,\"az\":0.9999824,\"mx\":-39.39455,\"roll\":359.6398},{\"pitch\":359.8874,\"gz\":-0.0001093571,\"my\":-18.08916,\"yaw\":154.9985,\"coreMotionRoll\":359.6671,\"mz\":-21.58682,\"ax\":0.005809215,\"coreMotionPitch\":359.9113,\"coreMotionYaw\":155.8464,\"gx\":0.001726137,\"ay\":-0.001548384,\"gy\":-0.0001169273,\"az\":0.9999819,\"mx\":-39.39519,\"roll\":359.6408},{\"pitch\":359.8742,\"gz\":0.0009871266,\"my\":-17.86417,\"yaw\":155.0607,\"coreMotionRoll\":359.6652,\"mz\":-21.58627,\"ax\":0.005843685,\"coreMotionPitch\":359.9178,\"coreMotionYaw\":155.8468,\"gx\":0.0006616887,\"ay\":-0.001435604,\"gy\":-0.00329125,\"az\":0.9999819,\"mx\":-39.39372,\"roll\":359.6176},{\"pitch\":359.8598,\"gz\":0.0009618782,\"my\":-17.86414,\"yaw\":155.1042,\"coreMotionRoll\":359.67,\"mz\":-21.66255,\"ax\":0.005758945,\"coreMotionPitch\":359.9113,\"coreMotionYaw\":155.8492,\"gx\":-0.001481076,\"ay\":-0.001548762,\"gy\":0.000955312,\"az\":0.9999822,\"mx\":-39.24384,\"roll\":359.6297},{\"pitch\":359.894,\"gz\":-0.0001161748,\"my\":-18.31416,\"yaw\":155.082,\"coreMotionRoll\":359.669,\"mz\":-21.58737,\"ax\":0.005776789,\"coreMotionPitch\":359.9093,\"coreMotionYaw\":155.8497,\"gx\":0.001716102,\"ay\":-0.001582565,\"gy\":-0.001177735,\"az\":0.9999821,\"mx\":-39.39665,\"roll\":359.639},{\"pitch\":359.9231,\"gz\":-0.001199222,\"my\":-18.4642,\"yaw\":155.0324,\"coreMotionRoll\":359.6638,\"mz\":-21.51338,\"ax\":0.00586744,\"coreMotionPitch\":359.9129,\"coreMotionYaw\":155.8518,\"gx\":0.0006439787,\"ay\":-0.001520748,\"gy\":0.001997693,\"az\":0.9999816,\"mx\":-39.32251,\"roll\":359.6658},{\"pitch\":359.9205,\"gz\":-0.001183938,\"my\":-18.08928,\"yaw\":155.0194,\"coreMotionRoll\":359.6635,\"mz\":-21.36565,\"ax\":0.005873903,\"coreMotionPitch\":359.9113,\"coreMotionYaw\":155.8521,\"gx\":-0.0004283994,\"ay\":-0.001548714,\"gy\":-0.0001248647,\"az\":0.9999815,\"mx\":-38.94485,\"roll\":359.6652},{\"pitch\":359.9661,\"gz\":-0.00134532,\"my\":-18.31432,\"yaw\":154.9901,\"coreMotionRoll\":359.6526,\"mz\":-21.28929,\"ax\":0.00606255,\"coreMotionPitch\":359.9108,\"coreMotionYaw\":155.8541,\"gx\":0.007046946,\"ay\":-0.001557158,\"gy\":0.01472897,\"az\":0.9999804,\"mx\":-39.1712,\"roll\":359.7451}]"; 80 | NSData * sampleData = [sampleJSON dataUsingEncoding:NSUTF8StringEncoding]; 81 | NSError * error; 82 | NSArray * samples = (NSArray *)[NSJSONSerialization JSONObjectWithData:sampleData 83 | options:0 84 | error:&error]; 85 | MadgwickSensorFusion * madgwickSensorFusion = [[MadgwickSensorFusion alloc] initWithSampleFrequencyHz:10.0 86 | beta:0.6045997880780726f]; 87 | for (NSDictionary * sample in samples) 88 | { 89 | [madgwickSensorFusion updateWithGyroscopeX:[sample[@"gx"] floatValue] 90 | gyroscopeY:[sample[@"gy"] floatValue] 91 | gyroscopeZ:[sample[@"gz"] floatValue] 92 | accelerometerX:[sample[@"ax"] floatValue] 93 | accelerometerY:[sample[@"ay"] floatValue] 94 | accelerometerZ:[sample[@"az"] floatValue] 95 | magnetometerX:[sample[@"mx"] floatValue] 96 | magnetometerY:[sample[@"my"] floatValue] 97 | magnetometerZ:[sample[@"mz"] floatValue]]; 98 | } 99 | 100 | // Calculate roll, pitch, yaw. 101 | float roll, pitch, yaw; 102 | CalculateEulerAnglesFromQuaternion([madgwickSensorFusion q0], 103 | [madgwickSensorFusion q1], 104 | [madgwickSensorFusion q2], 105 | [madgwickSensorFusion q3], 106 | &roll, 107 | &pitch, 108 | &yaw); 109 | roll = NormalizeAngle(RadiansToDegrees(roll)); 110 | pitch = NormalizeAngle(RadiansToDegrees(pitch)); 111 | yaw = NormalizeAngle(RadiansToDegrees(yaw)); 112 | 113 | // Test. 114 | XCTAssertTrue((NSInteger)(roll * 100.0) == (NSInteger)([[samples lastObject][@"roll"] floatValue] * 100.0)); 115 | XCTAssertTrue((NSInteger)(pitch * 100.0) == (NSInteger)([[samples lastObject][@"pitch"] floatValue] * 100.0)); 116 | XCTAssertTrue((NSInteger)(yaw * 100.0) == (NSInteger)([[samples lastObject][@"yaw"] floatValue] * 100.0)); 117 | } 118 | 119 | @end 120 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MadgwickAHRS 2 | 3 | [![GitHub license](https://img.shields.io/aur/license/yaourt.svg)](https://raw.githubusercontent.com/softwarenerd/MadgwickAHRS/master/LICENSE.md) ![platforms](https://img.shields.io/badge/platforms-iOS%20-lightgrey.svg) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 4 | 5 | [MadgwickAHRS](http://www.x-io.co.uk/open-source-imu-and-ahrs-algorithms/) is a port of the [C implementation](http://www.x-io.co.uk/res/sw/madgwick_algorithm_c.zip) of MadgwickAHRS to an iOS Framework written in Objective-C. 6 | 7 | ## Getting Started 8 | 9 | MadgwickAHRS should be used via [Carthage dependency manager](https://github.com/Carthage/Carthage). Follow the [Carthage build instructions](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos) for building for iOS. Essentially: 10 | 11 | #### Add MadgwickAHRS to your Cartfile 12 | 13 | ```github "softwarenerd/MadgwickAHRS"``` 14 | 15 | #### Add MadgwickAHRS.framework to Linked Frameworks and Libraries 16 | 17 | ![AddFramework](Documentation/AddFramework.png) 18 | 19 | #### Add Copy Frameworks Run Script 20 | 21 | Add a run script that uses the ```carthage copy-frameworks``` command to copy the ```MadgwickAHRS.framework``` 22 | 23 | ![RunScript](Documentation/RunScript.png) 24 | 25 | ## Usage 26 | 27 | See [CoreMotionMadgwickTestDriver](https://raw.githubusercontent.com/softwarenerd/MadgwickAHRS/master/MadgwickAHRS/CoreMotionMadgwickTestDriver.m) for a sample of how to use MadgwickAHRS. 28 | 29 | ## RawIMU Sample App 30 | 31 | The [RawIMU](https://github.com/softwarenerd/RawIMU) project contains a sample app that uses MadgwickAHRS. 32 | 33 | #### Clone Raw IMU 34 | 35 | `~/Code git clone git@github.com:softwarenerd/RawIMU.git` 36 | 37 | #### Optionally, Build Carthage Dependencies 38 | 39 | ```~/Code/RawIMU carthage bootstrap``` 40 | 41 | ## Known Issues 42 | 43 | * Additional unit tests would be nice. 44 | 45 | ## License 46 | 47 | MadgwickAHRS is released under the [GNU General Public License](LICENSE.md). 48 | --------------------------------------------------------------------------------