├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ ├── jekyll-gh-pages.yml │ └── publish-to-test-pypi.yml ├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── LICENSE.txt ├── README.md ├── _config.yml ├── doc ├── MPU-9250 Product Specification Revision 1.1.pdf └── MPU-9250 Register Map and Descriptions Revision 1.6.pdf ├── examples ├── basic-usage │ ├── master-only-mode.py │ └── master-slave-mode.py └── thread-sampling │ ├── run.py │ ├── sampling.py │ └── sensors.py ├── mpu9250_jmdev ├── __init__.py ├── fake_smbus.py ├── mpu_9250.py └── registers.py ├── requirements.txt └── setup.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [jefmenegazzo] 4 | custom: ['https://www.paypal.com/donate/?hosted_button_id=QA7BLD3X842W6'] 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/workflows/jekyll-gh-pages.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a Jekyll site to GitHub Pages 2 | name: Deploy Jekyll with GitHub Pages dependencies preinstalled 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["master"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow one concurrent deployment 19 | concurrency: 20 | group: "pages" 21 | cancel-in-progress: true 22 | 23 | jobs: 24 | # Build job 25 | build: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - name: Checkout 29 | uses: actions/checkout@v3 30 | - name: Setup Pages 31 | uses: actions/configure-pages@v3 32 | - name: Build with Jekyll 33 | uses: actions/jekyll-build-pages@v1 34 | with: 35 | source: ./ 36 | destination: ./_site 37 | - name: Upload artifact 38 | uses: actions/upload-pages-artifact@v1 39 | 40 | # Deployment job 41 | deploy: 42 | environment: 43 | name: github-pages 44 | url: ${{ steps.deployment.outputs.page_url }} 45 | runs-on: ubuntu-latest 46 | needs: build 47 | steps: 48 | - name: Deploy to GitHub Pages 49 | id: deployment 50 | uses: actions/deploy-pages@v1 51 | -------------------------------------------------------------------------------- /.github/workflows/publish-to-test-pypi.yml: -------------------------------------------------------------------------------- 1 | name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI 2 | 3 | on: push 4 | 5 | jobs: 6 | build-n-publish: 7 | name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@master 11 | - name: Set up Python 3.10 12 | uses: actions/setup-python@v3 13 | with: 14 | python-version: "3.10" 15 | - name: Install pypa/build 16 | run: >- 17 | python -m 18 | pip install 19 | build 20 | --user 21 | - name: Build a binary wheel and a source tarball 22 | run: >- 23 | python -m 24 | build 25 | --sdist 26 | --wheel 27 | --outdir dist/ 28 | . 29 | - name: Publish distribution 📦 to Test PyPI 30 | uses: pypa/gh-action-pypi-publish@release/v1 31 | with: 32 | password: ${{ secrets.TEST_PYPI_API_TOKEN }} 33 | repository_url: https://test.pypi.org/legacy/ 34 | - name: Publish distribution 📦 to PyPI 35 | if: startsWith(github.ref, 'refs/tags') 36 | uses: pypa/gh-action-pypi-publish@release/v1 37 | with: 38 | password: ${{ secrets.PYPI_API_TOKEN }} 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/__pycache__ 2 | build 3 | dist 4 | mpu9250_jmdev.egg-info -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-python.anaconda-extension-pack", 4 | "ms-python.python" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.git": true, 4 | "**/__pycache__": true, 5 | ".github": true, 6 | ".gitignore": true, 7 | "dist": true, 8 | "build": true, 9 | "mpu9250_jmdev.egg-info": true, 10 | }, 11 | "python.pythonPath": "C:\\ProgramData\\Anaconda3\\python.exe" 12 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Attribution-NonCommercial-NoDerivatives 4.0 International 2 | 3 | ======================================================================= 4 | 5 | Creative Commons Corporation ("Creative Commons") is not a law firm and 6 | does not provide legal services or legal advice. Distribution of 7 | Creative Commons public licenses does not create a lawyer-client or 8 | other relationship. Creative Commons makes its licenses and related 9 | information available on an "as-is" basis. Creative Commons gives no 10 | warranties regarding its licenses, any material licensed under their 11 | terms and conditions, or any related information. Creative Commons 12 | disclaims all liability for damages resulting from their use to the 13 | fullest extent possible. 14 | 15 | Using Creative Commons Public Licenses 16 | 17 | Creative Commons public licenses provide a standard set of terms and 18 | conditions that creators and other rights holders may use to share 19 | original works of authorship and other material subject to copyright 20 | and certain other rights specified in the public license below. The 21 | following considerations are for informational purposes only, are not 22 | exhaustive, and do not form part of our licenses. 23 | 24 | Considerations for licensors: Our public licenses are 25 | intended for use by those authorized to give the public 26 | permission to use material in ways otherwise restricted by 27 | copyright and certain other rights. Our licenses are 28 | irrevocable. Licensors should read and understand the terms 29 | and conditions of the license they choose before applying it. 30 | Licensors should also secure all rights necessary before 31 | applying our licenses so that the public can reuse the 32 | material as expected. Licensors should clearly mark any 33 | material not subject to the license. This includes other CC- 34 | licensed material, or material used under an exception or 35 | limitation to copyright. More considerations for licensors: 36 | wiki.creativecommons.org/Considerations_for_licensors 37 | 38 | Considerations for the public: By using one of our public 39 | licenses, a licensor grants the public permission to use the 40 | licensed material under specified terms and conditions. If 41 | the licensor's permission is not necessary for any reason--for 42 | example, because of any applicable exception or limitation to 43 | copyright--then that use is not regulated by the license. Our 44 | licenses grant only permissions under copyright and certain 45 | other rights that a licensor has authority to grant. Use of 46 | the licensed material may still be restricted for other 47 | reasons, including because others have copyright or other 48 | rights in the material. A licensor may make special requests, 49 | such as asking that all changes be marked or described. 50 | Although not required by our licenses, you are encouraged to 51 | respect those requests where reasonable. More considerations 52 | for the public: 53 | wiki.creativecommons.org/Considerations_for_licensees 54 | 55 | ======================================================================= 56 | 57 | Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 58 | International Public License 59 | 60 | By exercising the Licensed Rights (defined below), You accept and agree 61 | to be bound by the terms and conditions of this Creative Commons 62 | Attribution-NonCommercial-NoDerivatives 4.0 International Public 63 | License ("Public License"). To the extent this Public License may be 64 | interpreted as a contract, You are granted the Licensed Rights in 65 | consideration of Your acceptance of these terms and conditions, and the 66 | Licensor grants You such rights in consideration of benefits the 67 | Licensor receives from making the Licensed Material available under 68 | these terms and conditions. 69 | 70 | 71 | Section 1 -- Definitions. 72 | 73 | a. Adapted Material means material subject to Copyright and Similar 74 | Rights that is derived from or based upon the Licensed Material 75 | and in which the Licensed Material is translated, altered, 76 | arranged, transformed, or otherwise modified in a manner requiring 77 | permission under the Copyright and Similar Rights held by the 78 | Licensor. For purposes of this Public License, where the Licensed 79 | Material is a musical work, performance, or sound recording, 80 | Adapted Material is always produced where the Licensed Material is 81 | synched in timed relation with a moving image. 82 | 83 | b. Copyright and Similar Rights means copyright and/or similar rights 84 | closely related to copyright including, without limitation, 85 | performance, broadcast, sound recording, and Sui Generis Database 86 | Rights, without regard to how the rights are labeled or 87 | categorized. For purposes of this Public License, the rights 88 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 89 | Rights. 90 | 91 | c. Effective Technological Measures means those measures that, in the 92 | absence of proper authority, may not be circumvented under laws 93 | fulfilling obligations under Article 11 of the WIPO Copyright 94 | Treaty adopted on December 20, 1996, and/or similar international 95 | agreements. 96 | 97 | d. Exceptions and Limitations means fair use, fair dealing, and/or 98 | any other exception or limitation to Copyright and Similar Rights 99 | that applies to Your use of the Licensed Material. 100 | 101 | e. Licensed Material means the artistic or literary work, database, 102 | or other material to which the Licensor applied this Public 103 | License. 104 | 105 | f. Licensed Rights means the rights granted to You subject to the 106 | terms and conditions of this Public License, which are limited to 107 | all Copyright and Similar Rights that apply to Your use of the 108 | Licensed Material and that the Licensor has authority to license. 109 | 110 | g. Licensor means the individual(s) or entity(ies) granting rights 111 | under this Public License. 112 | 113 | h. NonCommercial means not primarily intended for or directed towards 114 | commercial advantage or monetary compensation. For purposes of 115 | this Public License, the exchange of the Licensed Material for 116 | other material subject to Copyright and Similar Rights by digital 117 | file-sharing or similar means is NonCommercial provided there is 118 | no payment of monetary compensation in connection with the 119 | exchange. 120 | 121 | i. Share means to provide material to the public by any means or 122 | process that requires permission under the Licensed Rights, such 123 | as reproduction, public display, public performance, distribution, 124 | dissemination, communication, or importation, and to make material 125 | available to the public including in ways that members of the 126 | public may access the material from a place and at a time 127 | individually chosen by them. 128 | 129 | j. Sui Generis Database Rights means rights other than copyright 130 | resulting from Directive 96/9/EC of the European Parliament and of 131 | the Council of 11 March 1996 on the legal protection of databases, 132 | as amended and/or succeeded, as well as other essentially 133 | equivalent rights anywhere in the world. 134 | 135 | k. You means the individual or entity exercising the Licensed Rights 136 | under this Public License. Your has a corresponding meaning. 137 | 138 | 139 | Section 2 -- Scope. 140 | 141 | a. License grant. 142 | 143 | 1. Subject to the terms and conditions of this Public License, 144 | the Licensor hereby grants You a worldwide, royalty-free, 145 | non-sublicensable, non-exclusive, irrevocable license to 146 | exercise the Licensed Rights in the Licensed Material to: 147 | 148 | a. reproduce and Share the Licensed Material, in whole or 149 | in part, for NonCommercial purposes only; and 150 | 151 | b. produce and reproduce, but not Share, Adapted Material 152 | for NonCommercial purposes only. 153 | 154 | 2. Exceptions and Limitations. For the avoidance of doubt, where 155 | Exceptions and Limitations apply to Your use, this Public 156 | License does not apply, and You do not need to comply with 157 | its terms and conditions. 158 | 159 | 3. Term. The term of this Public License is specified in Section 160 | 6(a). 161 | 162 | 4. Media and formats; technical modifications allowed. The 163 | Licensor authorizes You to exercise the Licensed Rights in 164 | all media and formats whether now known or hereafter created, 165 | and to make technical modifications necessary to do so. The 166 | Licensor waives and/or agrees not to assert any right or 167 | authority to forbid You from making technical modifications 168 | necessary to exercise the Licensed Rights, including 169 | technical modifications necessary to circumvent Effective 170 | Technological Measures. For purposes of this Public License, 171 | simply making modifications authorized by this Section 2(a) 172 | (4) never produces Adapted Material. 173 | 174 | 5. Downstream recipients. 175 | 176 | a. Offer from the Licensor -- Licensed Material. Every 177 | recipient of the Licensed Material automatically 178 | receives an offer from the Licensor to exercise the 179 | Licensed Rights under the terms and conditions of this 180 | Public License. 181 | 182 | b. No downstream restrictions. You may not offer or impose 183 | any additional or different terms or conditions on, or 184 | apply any Effective Technological Measures to, the 185 | Licensed Material if doing so restricts exercise of the 186 | Licensed Rights by any recipient of the Licensed 187 | Material. 188 | 189 | 6. No endorsement. Nothing in this Public License constitutes or 190 | may be construed as permission to assert or imply that You 191 | are, or that Your use of the Licensed Material is, connected 192 | with, or sponsored, endorsed, or granted official status by, 193 | the Licensor or others designated to receive attribution as 194 | provided in Section 3(a)(1)(A)(i). 195 | 196 | b. Other rights. 197 | 198 | 1. Moral rights, such as the right of integrity, are not 199 | licensed under this Public License, nor are publicity, 200 | privacy, and/or other similar personality rights; however, to 201 | the extent possible, the Licensor waives and/or agrees not to 202 | assert any such rights held by the Licensor to the limited 203 | extent necessary to allow You to exercise the Licensed 204 | Rights, but not otherwise. 205 | 206 | 2. Patent and trademark rights are not licensed under this 207 | Public License. 208 | 209 | 3. To the extent possible, the Licensor waives any right to 210 | collect royalties from You for the exercise of the Licensed 211 | Rights, whether directly or through a collecting society 212 | under any voluntary or waivable statutory or compulsory 213 | licensing scheme. In all other cases the Licensor expressly 214 | reserves any right to collect such royalties, including when 215 | the Licensed Material is used other than for NonCommercial 216 | purposes. 217 | 218 | 219 | Section 3 -- License Conditions. 220 | 221 | Your exercise of the Licensed Rights is expressly made subject to the 222 | following conditions. 223 | 224 | a. Attribution. 225 | 226 | 1. If You Share the Licensed Material, You must: 227 | 228 | a. retain the following if it is supplied by the Licensor 229 | with the Licensed Material: 230 | 231 | i. identification of the creator(s) of the Licensed 232 | Material and any others designated to receive 233 | attribution, in any reasonable manner requested by 234 | the Licensor (including by pseudonym if 235 | designated); 236 | 237 | ii. a copyright notice; 238 | 239 | iii. a notice that refers to this Public License; 240 | 241 | iv. a notice that refers to the disclaimer of 242 | warranties; 243 | 244 | v. a URI or hyperlink to the Licensed Material to the 245 | extent reasonably practicable; 246 | 247 | b. indicate if You modified the Licensed Material and 248 | retain an indication of any previous modifications; and 249 | 250 | c. indicate the Licensed Material is licensed under this 251 | Public License, and include the text of, or the URI or 252 | hyperlink to, this Public License. 253 | 254 | For the avoidance of doubt, You do not have permission under 255 | this Public License to Share Adapted Material. 256 | 257 | 2. You may satisfy the conditions in Section 3(a)(1) in any 258 | reasonable manner based on the medium, means, and context in 259 | which You Share the Licensed Material. For example, it may be 260 | reasonable to satisfy the conditions by providing a URI or 261 | hyperlink to a resource that includes the required 262 | information. 263 | 264 | 3. If requested by the Licensor, You must remove any of the 265 | information required by Section 3(a)(1)(A) to the extent 266 | reasonably practicable. 267 | 268 | 269 | Section 4 -- Sui Generis Database Rights. 270 | 271 | Where the Licensed Rights include Sui Generis Database Rights that 272 | apply to Your use of the Licensed Material: 273 | 274 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 275 | to extract, reuse, reproduce, and Share all or a substantial 276 | portion of the contents of the database for NonCommercial purposes 277 | only and provided You do not Share Adapted Material; 278 | 279 | b. if You include all or a substantial portion of the database 280 | contents in a database in which You have Sui Generis Database 281 | Rights, then the database in which You have Sui Generis Database 282 | Rights (but not its individual contents) is Adapted Material; and 283 | 284 | c. You must comply with the conditions in Section 3(a) if You Share 285 | all or a substantial portion of the contents of the database. 286 | 287 | For the avoidance of doubt, this Section 4 supplements and does not 288 | replace Your obligations under this Public License where the Licensed 289 | Rights include other Copyright and Similar Rights. 290 | 291 | 292 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 293 | 294 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 295 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 296 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 297 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 298 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 299 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 300 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 301 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 302 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 303 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 304 | 305 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 306 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 307 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 308 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 309 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 310 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 311 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 312 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 313 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 314 | 315 | c. The disclaimer of warranties and limitation of liability provided 316 | above shall be interpreted in a manner that, to the extent 317 | possible, most closely approximates an absolute disclaimer and 318 | waiver of all liability. 319 | 320 | 321 | Section 6 -- Term and Termination. 322 | 323 | a. This Public License applies for the term of the Copyright and 324 | Similar Rights licensed here. However, if You fail to comply with 325 | this Public License, then Your rights under this Public License 326 | terminate automatically. 327 | 328 | b. Where Your right to use the Licensed Material has terminated under 329 | Section 6(a), it reinstates: 330 | 331 | 1. automatically as of the date the violation is cured, provided 332 | it is cured within 30 days of Your discovery of the 333 | violation; or 334 | 335 | 2. upon express reinstatement by the Licensor. 336 | 337 | For the avoidance of doubt, this Section 6(b) does not affect any 338 | right the Licensor may have to seek remedies for Your violations 339 | of this Public License. 340 | 341 | c. For the avoidance of doubt, the Licensor may also offer the 342 | Licensed Material under separate terms or conditions or stop 343 | distributing the Licensed Material at any time; however, doing so 344 | will not terminate this Public License. 345 | 346 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 347 | License. 348 | 349 | 350 | Section 7 -- Other Terms and Conditions. 351 | 352 | a. The Licensor shall not be bound by any additional or different 353 | terms or conditions communicated by You unless expressly agreed. 354 | 355 | b. Any arrangements, understandings, or agreements regarding the 356 | Licensed Material not stated herein are separate from and 357 | independent of the terms and conditions of this Public License. 358 | 359 | 360 | Section 8 -- Interpretation. 361 | 362 | a. For the avoidance of doubt, this Public License does not, and 363 | shall not be interpreted to, reduce, limit, restrict, or impose 364 | conditions on any use of the Licensed Material that could lawfully 365 | be made without permission under this Public License. 366 | 367 | b. To the extent possible, if any provision of this Public License is 368 | deemed unenforceable, it shall be automatically reformed to the 369 | minimum extent necessary to make it enforceable. If the provision 370 | cannot be reformed, it shall be severed from this Public License 371 | without affecting the enforceability of the remaining terms and 372 | conditions. 373 | 374 | c. No term or condition of this Public License will be waived and no 375 | failure to comply consented to unless expressly agreed to by the 376 | Licensor. 377 | 378 | d. Nothing in this Public License constitutes or may be interpreted 379 | as a limitation upon, or waiver of, any privileges and immunities 380 | that apply to the Licensor or You, including from the legal 381 | processes of any jurisdiction or authority. 382 | 383 | ======================================================================= 384 | 385 | Creative Commons is not a party to its public 386 | licenses. Notwithstanding, Creative Commons may elect to apply one of 387 | its public licenses to material it publishes and in those instances 388 | will be considered the “Licensor.” The text of the Creative Commons 389 | public licenses is dedicated to the public domain under the CC0 Public 390 | Domain Dedication. Except for the limited purpose of indicating that 391 | material is shared under a Creative Commons public license or as 392 | otherwise permitted by the Creative Commons policies published at 393 | creativecommons.org/policies, Creative Commons does not authorize the 394 | use of the trademark "Creative Commons" or any other trademark or logo 395 | of Creative Commons without its prior written consent including, 396 | without limitation, in connection with any unauthorized modifications 397 | to any of its public licenses or any other arrangements, 398 | understandings, or agreements concerning use of licensed material. For 399 | the avoidance of doubt, this paragraph does not form part of the 400 | public licenses. 401 | 402 | Creative Commons may be contacted at creativecommons.org. 403 | 404 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | MPU-9250 10 | 11 | 12 |
13 | 14 | 🙌 Use [donations](#Sponsors-and-Donations) to help support your projects! 🙌 15 | 16 |
17 | 18 |
19 | 20 | [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://img.shields.io/badge/Project_Status-Active-green?style=flat-square&color=success)](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect) 21 | [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg?style=flat-square&color=success)](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect) 22 | [![License: CC BY-NC-ND 4.0](https://img.shields.io/badge/License-CC%20BY--NC--ND%204.0-lightgrey.svg?style=flat-square&color=success)](LICENSE.txt) 23 | [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QYV4NEUSVWZCY&source=url) 24 | ![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect?style=flat-square) 25 | ![pypi](https://img.shields.io/pypi/v/pybadges.svg?style=flat-square) 26 | ![versions](https://img.shields.io/pypi/pyversions/pybadges.svg?style=flat-square) 27 | [![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.3960441-blue?style=flat-square)](https://doi.org/10.5281/zenodo.3960441) 28 | [![GitHub issues](https://img.shields.io/github/issues/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect?style=flat-square)](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/issues) 29 | [![GitHub forks](https://img.shields.io/github/forks/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect?style=flat-square)](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/network/members) 30 | [![GitHub stars](https://img.shields.io/github/stars/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect?style=flat-square)](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/stargazers) 31 | [![GitHub watchers](https://img.shields.io/github/watchers/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect?style=flat-square)](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/watchers) 32 | [![GitHub contributors](https://img.shields.io/github/contributors/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect?style=flat-square&color=success)](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/graphs/contributors/) 33 | [![HitCount](http://hits.dwyl.io/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/badges.svg)](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect) 34 | [![PyPI - Downloads](https://img.shields.io/pypi/dm/mpu9250_jmdev?style=flat-square&color=success)](https://pypi.org/project/mpu9250_jmdev) 35 | 36 | # MPU-9250 (MPU-6500 + AK8963) I2C Driver in Python 37 | 38 | **MPU-9250** is a multi-chip module (MCM) consisting of two dies integrated into a single QFN package. One die the **MPU-6500** houses the 3-Axis gyroscope, the 3-Axis accelerometer and temperature sensor. The other die houses the **AK8963** 3-Axis magnetometer. Hence, the MPU-9250 is a 9-axis MotionTracking device that combines a 3-axis gyroscope, 3-axis accelerometer, 3-axis magnetometer and a Digital Motion Processor™ (DMP). The hardware documentation for MPU-9250 can be found at [Product Specification](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/blob/master/doc/MPU-9250%20Product%20Specification%20Revision%201.1.pdf) and [Register Map and Descriptions](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/blob/master/doc/MPU-9250%20Register%20Map%20and%20Descriptions%20Revision%201.6.pdf). 39 | 40 | ## Table of Contents 41 | - [Instalation](#Instalation) 42 | - [How To Use](#How-To-Use) 43 | - [Getting Data](#Getting-Data) 44 | - [Calibrating Sensors](#Calibrating-Sensors) 45 | - [Reset Registers](#Reset-Registers) 46 | - [Final Notes](#Final-Notes) 47 | - [Sponsors and Donations](#Sponsors-and-Donations) 48 | - [What We're Working on Now](#What-We're-Working-on-Now) 49 | - [How To Cite](#How-To-Cite) 50 | - [License](#License) 51 | 52 | ## Instalation 53 | 54 | To install via pip use: 55 | 56 | ```bash 57 | pip install mpu9250-jmdev 58 | ``` 59 | 60 | To use the package for development purposes use: 61 | 62 | ```bash 63 | git clone https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect.git MPU9250 64 | cd MPU9250 65 | pip install -e . 66 | pip install -r requirements.txt 67 | ``` 68 | 69 | ### Known Issues 70 | 71 | > :information_source: Notice that this package requires Python 3.6 or higher. 72 | 73 | > :warning: If you have both Python 2 and 3 installed on your machine, use ```pip3``` to install and ```python3``` to run instead. 74 | 75 | > :warning: If you run your python source-code with ```sudo```, remember to use ```sudo``` with ```pip install``` commands as well. 76 | 77 | > :warning: If you get zero values and the message **Using Fake SMBus**, the **smbus2** requirement has not been installed correctly. Try installing manually with the command ```pip install -r requirements.txt``` or ```python -mpip install smbus2```. 78 | 79 | > :exclamation: Any other problem or questions, **open an issue in this repository [clicking here](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/issues), do not send me an e-mail!** 80 | 81 | ## How To Use 82 | 83 | With I2C Bus, you can use the MPU-9250 in two ways: simple mode or advanced mode. The example source-codes are in **examples** folder. 84 | 85 | ### Simple Mode - Master Only 86 | 87 | In this mode, the MPU-9250 connects directly to Raspberry GPIOs. There are two physical addresses available for the MPU-9250, being 0x68 and 0x69. Therefore, on each I2C Bus you can have up to two MPU-9250 connected. The connection between GPIOs and MPU-9250 is as follows: 88 | 89 | | MPU9250 | Raspberry | Note | 90 | |---|---|---| 91 | | VDD | 3.3V | On some models of the MPU-9250 5V can be used. | 92 | | AD0 | 3.3V | If used, the MPU-9250's address is changed to 0x69. Otherwise, the address is 0x68. | 93 | | GND | GND | | 94 | | SDA | SDA | | 95 | | SCL | SCL | | 96 | 97 | Below simple code to test the execution with never ending loop: 98 | 99 | ```python 100 | import time 101 | from mpu9250_jmdev.registers import * 102 | from mpu9250_jmdev.mpu_9250 import MPU9250 103 | 104 | mpu = MPU9250( 105 | address_ak=AK8963_ADDRESS, 106 | address_mpu_master=MPU9050_ADDRESS_68, # In 0x68 Address 107 | address_mpu_slave=None, 108 | bus=1, 109 | gfs=GFS_1000, 110 | afs=AFS_8G, 111 | mfs=AK8963_BIT_16, 112 | mode=AK8963_MODE_C100HZ) 113 | 114 | mpu.configure() # Apply the settings to the registers. 115 | 116 | while True: 117 | 118 | print("|.....MPU9250 in 0x68 Address.....|") 119 | print("Accelerometer", mpu.readAccelerometerMaster()) 120 | print("Gyroscope", mpu.readGyroscopeMaster()) 121 | print("Magnetometer", mpu.readMagnetometerMaster()) 122 | print("Temperature", mpu.readTemperatureMaster()) 123 | print("\n") 124 | 125 | time.sleep(1) 126 | ``` 127 | 128 | ### Advanced Mode - Master-Slave 129 | 130 | If you want to have more than two MPU-9250 on one I2C Bus, you must use Master-Slave mode. In this case, first configure the MPU-9250 according to the previous section, they will be used as Master. To configure the MPU-9250 Slaves, connect as follows: 131 | 132 | | MPU9250 Slave | MPU9250 Master | Raspberry PI | Note | 133 | |---|---|---|---| 134 | | VDD | | 3.3V | On some models of the MPU-9250 5V can be used. | 135 | | AD0 | | 3.3V | If used, the MPU-9250's address is changed to 0x69. Otherwise, the address is 0x68. | 136 | | GND | | GND | | 137 | | SDA | EDA | | 138 | | SCL | ECL | | 139 | 140 | This way you will have an MPU-9250 Master connecting SDA and SLC directly to the GPIO in Raspberry PI, and an MPU-9250 Slave connecting SDA and SLC to the EDA and ELC in MPU-9250 Master. 141 | 142 | Below simple code to test the execution with never ending loop: 143 | 144 | ```python 145 | import time 146 | from mpu9250_jmdev.registers import * 147 | from mpu9250_jmdev.mpu_9250 import MPU9250 148 | 149 | mpu = MPU9250( 150 | address_ak=AK8963_ADDRESS, 151 | address_mpu_master=MPU9050_ADDRESS_68, # Master has 0x68 Address 152 | address_mpu_slave=MPU9050_ADDRESS_68, # Slave has 0x68 Address 153 | bus=1, 154 | gfs=GFS_1000, 155 | afs=AFS_8G, 156 | mfs=AK8963_BIT_16, 157 | mode=AK8963_MODE_C100HZ) 158 | 159 | mpu.configure() # Apply the settings to the registers. 160 | 161 | while True: 162 | 163 | print("|.....MPU9250 in 0x68 I2C Bus - Master.....|") 164 | print("Accelerometer", mpu.readAccelerometerMaster()) 165 | print("Gyroscope", mpu.readGyroscopeMaster()) 166 | print("Magnetometer", mpu.readMagnetometerMaster()) 167 | print("Temperature", mpu.readTemperatureMaster()) 168 | print("\n") 169 | 170 | print("|.....MPU9250 in 0x68 I2C Bus - Slave in 0x68 auxiliary sensor address.....|") 171 | print("Accelerometer", mpu.readAccelerometerSlave()) 172 | print("Gyroscope", mpu.readGyroscopeSlave()) 173 | print("Temperature", mpu.readTemperatureSlave()) 174 | print("\n") 175 | 176 | time.sleep(1) 177 | ``` 178 | 179 | ## Getting Data 180 | 181 | All sensors and measurement units of the MPU-9250 are described below: 182 | 183 | | Sensor | Unit | 184 | |---|---| 185 | | Accelerometer | g (1g = 9.80665 m/s²) | 186 | | Gyroscope | degrees per second (°/s) | 187 | | Magnetometer | microtesla (μT) | 188 | | Temperature | celsius degrees (°C) | 189 | 190 | Before read the sensor data, make sure that you have executed the command: 191 | 192 | ```python 193 | mpu.configure() # Apply the settings to the registers. 194 | ``` 195 | 196 | ### Reading Accelerometer 197 | 198 | The accelerometer measures acceleration in three axes (X, Y, Z). To read your data, use the commands: 199 | 200 | ```python 201 | masterData = mpu.readAccelerometerMaster() 202 | slaveData = mpu.readAccelerometerSlave() # If there is a slave 203 | ``` 204 | 205 | ### Reading Gyroscope 206 | 207 | The gyroscope measures rotation rate in three axes (X, Y, Z). To read your data, use the commands: 208 | 209 | ```python 210 | masterData = mpu.readGyroscopeMaster() 211 | slaveData = mpu.readGyroscopeSlave() # If there is a slave 212 | ``` 213 | 214 | ### Reading Magnetometer 215 | 216 | The magnetometer measures geomagnetic field in three axes (X, Y, Z). To read your data, use the command: 217 | 218 | ```python 219 | masterData = mpu.readMagnetometerMaster() 220 | ``` 221 | 222 | When used in Simple Mode (Master Only), the magnetometer will be available on the I2C Bus with address 0x0C. When in Advanced Mode (Master-Slave), the magnetometer will also behave as a slave, and address 0x0C will not appear on the I2C Bus, acting as an auxiliary sensor. 223 | 224 | ### Reading Temperature 225 | 226 | The temperature sensor measures data in Celsius degrees. To read your data, use the command: 227 | 228 | ```python 229 | masterData = mpu.readTemperatureMaster() 230 | slaveData = mpu.readTemperatureSlave() # If there is a slave 231 | ``` 232 | 233 | ### Reading All Data 234 | 235 | If you want to read data from all sensors (master and slave) at the same time, use the commands below (useful for saving to csv): 236 | 237 | ```python 238 | labels = mpu.getAllDataLabels() # return labels with data description for each array position 239 | data = mpu.getAllData() # returns a array with data from all sensors 240 | ``` 241 | 242 | ### Reading All Settings 243 | 244 | If you want to read settings (biases, resolutions, scale factors) from all sensors (master and slave) at the same time, use the commands below (useful for saving to csv): 245 | 246 | ```python 247 | labels = mpu.getAllSettingsLabels() # return labels with settings description for each array position 248 | data = mpu.getAllSettings() # returns a array with settings from all sensors 249 | ``` 250 | 251 | ## Calibrating Sensors 252 | 253 | This library has functions ready for calibration accelerometer, gyroscope and magnetometer sensors. To calibrate all sensors at once, use the command: 254 | 255 | ```python 256 | mpu.calibrate() # Calibrate sensors 257 | mpu.configure() # The calibration function resets the sensors, so you need to reconfigure them 258 | ``` 259 | 260 | ### Accelerometer and Gyroscope 261 | 262 | To calibrate the accelerometer and gyroscope sensors, make sure that the sensors remain fixed and stationary. Align the accelerometer's Z axis with gravity, i.e., gravity (1g) should only appear on the sensor's Z axis (place the sensor in a flat place). To perform calibration run the command: 263 | 264 | ```python 265 | mpu.calibrateMPU6500() # Calibrate sensors 266 | mpu.configure() # The calibration function resets the sensors, so you need to reconfigure them 267 | 268 | abias = mpu.abias # Get the master accelerometer biases 269 | abias_slave = mpu.abias_slave # Get the slave accelerometer biases 270 | gbias = mpu.gbias # Get the master gyroscope biases 271 | gbias_slave = mpu.gbias_slave # Get the slave gyroscope biases 272 | ``` 273 | 274 | The biases are programmatically applied to the sensor data. Therefore, when reading the sensor data, the biases will be applied internally, returning corrected data. If you have calculated the biases of these sensors once, and want the controller to use them, simply parameterize as follows: 275 | 276 | ```python 277 | mpu.abias = [0, 0, 0] # Set the master accelerometer biases 278 | mpu.abias_slave = [0, 0, 0] # Set the slave accelerometer biases 279 | mpu.gbias = [0, 0, 0] # Set the master gyroscope biases 280 | mpu.gbias_slave = [0, 0, 0] # Set the slave gyroscope biases 281 | ``` 282 | 283 | ### Magnetometer 284 | 285 | To perform calibration run the command: 286 | 287 | ```python 288 | mpu.calibrateAK8963() # Calibrate sensors 289 | mpu.configure() # The calibration function resets the sensors, so you need to reconfigure them 290 | 291 | magScale = mpu.magScale # Get magnetometer soft iron distortion 292 | mbias = mpu.mbias # Get magnetometer hard iron distortion 293 | ``` 294 | 295 | If you have calculated the biases of these sensor once, and want the controller to use them, simply parameterize as follows: 296 | 297 | ```python 298 | mpu.magScale = [0, 0, 0] # Set magnetometer soft iron distortion 299 | mpu.mbias = [0, 0, 0] # Set magnetometer hard iron distortion 300 | ``` 301 | 302 | ## Reset Registers 303 | 304 | If you want to reset the values in all registers of all sensors in all MPU-9250, execute the command below: 305 | 306 | ```python 307 | mpu.reset() # Reset sensors 308 | mpu.configure() # After resetting you need to reconfigure the sensors 309 | ``` 310 | 311 | ## Final Notes 312 | 313 | The folder **mpu9250** consist of the high level library. The folder **examples** contains files with basic execution and threaded examples. 314 | 315 | ## Sponsors and Donations 316 | 317 | This project does not have any funding. To help maintain the project, consider making a donation 🙌. 318 | 319 | [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QYV4NEUSVWZCY&source=url) 320 | 321 | ## What We're Working on Now 322 | 323 | New features are currently under development: 324 | - V2: new major version will be released soon, much more robust than the current one. It will supports several MPU models, such as 9250, 9150, 6050, 6500. 325 | - Complete support documentation for configuring RPi, I2C, VNC, SSH, etc. 326 | 327 | ## How To Cite 328 | 329 | To cite this repository, use the reference below: 330 | 331 | ```bibtex 332 | @software{menegazzo3960441, 333 | author = {Jeferson Menegazzo and Aldo von Wangenheim}, 334 | title = {{MPU-9250 Sensors Data Collect}}, 335 | month = jul, 336 | year = 2020, 337 | publisher = {Zenodo}, 338 | version = {1.0.12}, 339 | doi = {10.5281/zenodo.3960441}, 340 | url = {https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/} 341 | } 342 | ``` 343 | 344 | ## License 345 | 346 | This project is under Attribution-NonCommercial-NoDerivatives 4.0 International License (CC BY-NC-ND 4.0). Please see [License File](LICENSE.txt) for more information. 347 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman 2 | # remote_theme: chrisrhymes/bulma-clean-theme 3 | -------------------------------------------------------------------------------- /doc/MPU-9250 Product Specification Revision 1.1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jefmenegazzo/mpu-i2c-drivers-python/841b83ee5577667c1111b76b87e2f0f2070f0759/doc/MPU-9250 Product Specification Revision 1.1.pdf -------------------------------------------------------------------------------- /doc/MPU-9250 Register Map and Descriptions Revision 1.6.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jefmenegazzo/mpu-i2c-drivers-python/841b83ee5577667c1111b76b87e2f0f2070f0759/doc/MPU-9250 Register Map and Descriptions Revision 1.6.pdf -------------------------------------------------------------------------------- /examples/basic-usage/master-only-mode.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | # Author: Jeferson Menegazzo # 3 | # Year: 2020 # 4 | # License: CC BY-NC-ND 4.0 # 5 | ##################################################################### 6 | 7 | import sys 8 | sys.path.append("") 9 | 10 | import time 11 | from mpu9250_jmdev.registers import * 12 | from mpu9250_jmdev.mpu_9250 import MPU9250 13 | 14 | ################################################## 15 | # Create # 16 | ################################################## 17 | 18 | mpu = MPU9250( 19 | address_ak=AK8963_ADDRESS, 20 | address_mpu_master=MPU9050_ADDRESS_68, # In 0x68 Address 21 | address_mpu_slave=None, 22 | bus=1, 23 | gfs=GFS_1000, 24 | afs=AFS_8G, 25 | mfs=AK8963_BIT_16, 26 | mode=AK8963_MODE_C100HZ) 27 | 28 | ################################################## 29 | # Configure # 30 | ################################################## 31 | mpu.configure() # Apply the settings to the registers. 32 | 33 | ################################################## 34 | # Calibrate # 35 | ################################################## 36 | # mpu.calibrate() # Calibrate sensors 37 | # mpu.configure() # The calibration function resets the sensors, so you need to reconfigure them 38 | 39 | ################################################## 40 | # Get Calibration # 41 | ################################################## 42 | # abias = mpu.abias # Get the master accelerometer biases 43 | # gbias = mpu.gbias # Get the master gyroscope biases 44 | # magScale = mpu.magScale # Get magnetometer soft iron distortion 45 | # mbias = mpu.mbias # Get magnetometer hard iron distortion 46 | 47 | # print("|.....MPU9250 in 0x68 Biases.....|") 48 | # print("Accelerometer", abias) 49 | # print("Gyroscope", gbias) 50 | # print("Magnetometer SID", magScale) 51 | # print("Magnetometer HID", mbias) 52 | # print("\n") 53 | 54 | ################################################## 55 | # Set Calibration # 56 | ################################################## 57 | # mpu.abias = [-0.08004239710365854, 0.458740234375, 0.2116996951219512] 58 | # mpu.gbias = [0.8958025676448171, 0.45292551924542684, 0.866773651867378] 59 | # mpu.magScale = [1.0104166666666667, 0.9797979797979799, 1.0104166666666667] 60 | # mpu.mbias = [2.6989010989010986, 2.7832417582417586, 2.6989010989010986] 61 | 62 | ################################################## 63 | # Show Values # 64 | ################################################## 65 | while True: 66 | 67 | print("|.....MPU9250 in 0x68 Address.....|") 68 | print("Accelerometer", mpu.readAccelerometerMaster()) 69 | print("Gyroscope", mpu.readGyroscopeMaster()) 70 | print("Magnetometer", mpu.readMagnetometerMaster()) 71 | print("Temperature", mpu.readTemperatureMaster()) 72 | print("\n") 73 | 74 | time.sleep(1) 75 | -------------------------------------------------------------------------------- /examples/basic-usage/master-slave-mode.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | # Author: Jeferson Menegazzo # 3 | # Year: 2020 # 4 | # License: CC BY-NC-ND 4.0 # 5 | ##################################################################### 6 | 7 | import sys 8 | sys.path.append("") 9 | 10 | import time 11 | from mpu9250_jmdev.registers import * 12 | from mpu9250_jmdev.mpu_9250 import MPU9250 13 | 14 | ################################################## 15 | # Create # 16 | ################################################## 17 | 18 | mpu = MPU9250( 19 | address_ak=AK8963_ADDRESS, 20 | address_mpu_master=MPU9050_ADDRESS_68, # In 0x68 Address 21 | address_mpu_slave=MPU9050_ADDRESS_68, 22 | bus=1, 23 | gfs=GFS_1000, 24 | afs=AFS_8G, 25 | mfs=AK8963_BIT_16, 26 | mode=AK8963_MODE_C100HZ) 27 | 28 | ################################################## 29 | # Configure # 30 | ################################################## 31 | mpu.configure() # Apply the settings to the registers. 32 | 33 | ################################################## 34 | # Calibrate # 35 | ################################################## 36 | # mpu.calibrate() # Calibrate sensors 37 | # mpu.configure() # The calibration function resets the sensors, so you need to reconfigure them 38 | 39 | ################################################## 40 | # Get Calibration # 41 | ################################################## 42 | # abias = mpu.abias # Get the master accelerometer biases 43 | # abias_slave = mpu.abias_slave # Get the slave accelerometer biases 44 | # gbias = mpu.gbias # Get the master gyroscope biases 45 | # gbias_slave = mpu.gbias_slave # Get the slave gyroscope biases 46 | # magScale = mpu.magScale # Get magnetometer soft iron distortion 47 | # mbias = mpu.mbias # Get magnetometer hard iron distortion 48 | 49 | # print("|.....MPU9250 in 0x68 Biases.....|") 50 | # print("Accelerometer Master", abias) 51 | # print("Accelerometer Slave", abias_slave) 52 | # print("Gyroscope Master", gbias) 53 | # print("Gyroscope Slave", gbias_slave) 54 | # print("Magnetometer SID", magScale) 55 | # print("Magnetometer HID", mbias) 56 | # print("\n") 57 | 58 | ################################################## 59 | # Set Calibration # 60 | ################################################## 61 | # mpu.abias = [0.073846435546875, 0.104925537109375, -0.007580566406250044] 62 | # mpu.abias_slave = [-0.05669294084821429, -0.022966657366071428, 0.34601120721726186] 63 | # mpu.gbias = [0.6832122802734375, -0.2918243408203125, -0.7152557373046875] 64 | # mpu.gbias_slave = [-0.946044921875, -0.13242449079241073, -0.7113502139136905] 65 | # mpu.magScale = [0.6847826086956522, 1.0327868852459017, 1.75] 66 | # mpu.mbias = [8.19041514041514, 8.991651404151403, 14.696359890109889] 67 | 68 | ################################################## 69 | # Show Values # 70 | ################################################## 71 | while True: 72 | 73 | print("|.....MPU9250 in 0x68 I2C Bus - Master.....|") 74 | print("Accelerometer", mpu.readAccelerometerMaster()) 75 | print("Gyroscope", mpu.readGyroscopeMaster()) 76 | print("Magnetometer", mpu.readMagnetometerMaster()) 77 | print("Temperature", mpu.readTemperatureMaster()) 78 | print("\n") 79 | 80 | print("|.....MPU9250 in 0x68 I2C Bus - Slave in 0x68 auxiliary sensor address.....|") 81 | print("Accelerometer", mpu.readAccelerometerSlave()) 82 | print("Gyroscope", mpu.readGyroscopeSlave()) 83 | print("Temperature", mpu.readTemperatureSlave()) 84 | print("\n") 85 | 86 | time.sleep(1) 87 | -------------------------------------------------------------------------------- /examples/thread-sampling/run.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | # Author: Jeferson Menegazzo # 3 | # Year: 2020 # 4 | # License: CC BY-NC-ND 4.0 # 5 | ##################################################################### 6 | 7 | from sensors import Sensors 8 | 9 | # Simple comand-line interface 10 | def __init__(): 11 | 12 | sensors = None # type: Sensors 13 | 14 | while True: 15 | 16 | print(""" 17 | [1] Sensors - Create/Recreate 18 | [2] Sensors - Apply Configuration 19 | [3] Sensors - Reset Configuration 20 | [4] Sensors - Calibrate 21 | [5] Sampling - Start 22 | [6] Sampling - Stop 23 | [7] Sampling - View Current 24 | [0] Exit 25 | """) 26 | 27 | option = input("Choice: ") 28 | 29 | if option == "0": 30 | 31 | if not(sensors is None) and sensors.running: 32 | sensors.stop() 33 | 34 | print("Exiting") 35 | break 36 | 37 | elif option == "1": 38 | sensors = Sensors() 39 | print("Sensors created") 40 | 41 | elif sensors is None: 42 | print("Not created sensors") 43 | 44 | elif option == "2": 45 | sensors.configure() 46 | print("Configuration applied to sensors") 47 | 48 | elif option == "3": 49 | sensors.reset() 50 | print("Sensor configurations reseted") 51 | 52 | elif option == "4": 53 | sensors.calibrate() 54 | print("Calibrated sensors") 55 | 56 | elif option == "5": 57 | sensors.start() 58 | print("Sampling started") 59 | 60 | elif option == "6": 61 | sensors.stop() 62 | print("Sampling stoped") 63 | 64 | elif option == "7": 65 | sensors.showCurrent() 66 | 67 | else: 68 | print("Invalid Choice.") 69 | 70 | if __name__ == "__main__": 71 | 72 | try: 73 | __init__() 74 | except KeyboardInterrupt: 75 | print("Exit") 76 | -------------------------------------------------------------------------------- /examples/thread-sampling/sampling.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | # Author: Jeferson Menegazzo # 3 | # Year: 2020 # 4 | # License: CC BY-NC-ND 4.0 # 5 | ##################################################################### 6 | 7 | import csv 8 | import datetime 9 | import os 10 | import sys 11 | import time 12 | from threading import Thread 13 | import sys 14 | sys.path.append("") 15 | 16 | from mpu9250_jmdev.mpu_9250 import MPU9250 17 | 18 | class Sampling(Thread): 19 | 20 | mpu = None 21 | folder = "../data" 22 | file = None 23 | running = False 24 | sleepStart = 5 # In seconds 25 | # sampling_rate = 0.01 # 100 Hz 26 | 27 | def __init__(self, address_ak, address_mpu_master, address_mpu_slave, bus, gfs, afs, mfs, mode): 28 | Thread.__init__(self) 29 | self.mpu = MPU9250(address_ak, address_mpu_master, address_mpu_slave, bus, gfs, afs, mfs, mode) 30 | 31 | def configure(self): 32 | self.mpu.configure() 33 | 34 | def reset(self): 35 | self.mpu.reset() 36 | 37 | def calibrate(self): 38 | self.mpu.calibrate() 39 | 40 | def getAllData(self): 41 | return self.mpu.getAllData() 42 | 43 | def getAllDataLabels(self): 44 | return self.mpu.getAllDataLabels() 45 | 46 | def getAllSettings(self): 47 | return self.mpu.getAllSettings() 48 | 49 | def getAllSettingsLabels(self): 50 | return self.mpu.getAllSettingsLabels() 51 | 52 | def startSampling(self, timeSync): 53 | 54 | if not os.path.exists(self.folder): 55 | os.makedirs(self.folder) 56 | 57 | fileSuffix = str(hex(self.mpu.address_mpu_master)) + " " + datetime.datetime.fromtimestamp(timeSync).strftime('%d-%m-%Y %H-%M-%S') + ".csv" 58 | self.file = self.folder + "/data-set-mpu-" + fileSuffix 59 | settings = self.folder + "/settings-mpu-" + fileSuffix 60 | 61 | with open(settings, "w+") as csvfile: 62 | spamwriter = csv.writer(csvfile, quotechar='|', quoting=csv.QUOTE_MINIMAL) 63 | spamwriter.writerow(self.getAllSettingsLabels()) 64 | spamwriter.writerow(self.getAllSettings()) 65 | 66 | self.timeSync = timeSync 67 | self.running = True 68 | self.start() 69 | 70 | def stopSampling(self): 71 | self.running = False 72 | self.join() 73 | 74 | def run(self): 75 | 76 | with open(self.file, "w+") as csvfile: 77 | 78 | spamwriter = csv.writer(csvfile, quotechar='|', quoting=csv.QUOTE_MINIMAL) 79 | 80 | # Writing Labels 81 | row = self.getAllDataLabels() 82 | spamwriter.writerow(row) 83 | 84 | # Start threads at same time 85 | sleepTime = self.sleepStart + (self.timeSync - int(self.timeSync)) 86 | time.sleep(sleepTime) 87 | 88 | # lastTime = time.time() 89 | 90 | while self.running: 91 | 92 | row = self.getAllData() 93 | spamwriter.writerow(row) 94 | 95 | # sleepTime = self.sampling_rate - (row[0] - lastTime) 96 | 97 | # if(sleepTime > 0): 98 | # time.sleep(sleepTime) 99 | 100 | # lastTime = row[0] 101 | -------------------------------------------------------------------------------- /examples/thread-sampling/sensors.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | # Author: Jeferson Menegazzo # 3 | # Year: 2020 # 4 | # License: CC BY-NC-ND 4.0 # 5 | ##################################################################### 6 | 7 | import time 8 | import sys 9 | sys.path.append("") 10 | 11 | from sampling import Sampling 12 | from mpu9250_jmdev.registers import * 13 | 14 | # Class that handles the entire sensor network. 15 | class Sensors: 16 | 17 | sampling_mpu_0x68 = None 18 | sampling_mpu_0x69 = None 19 | 20 | running = False 21 | 22 | def __init__(self,): 23 | self.sampling_mpu_0x68 = Sampling(AK8963_ADDRESS, MPU9050_ADDRESS_68, MPU9050_ADDRESS_68, 1, GFS_1000, AFS_8G, AK8963_BIT_16, AK8963_MODE_C100HZ) 24 | self.sampling_mpu_0x69 = Sampling(AK8963_ADDRESS, MPU9050_ADDRESS_69, None, 1, GFS_1000, AFS_8G, AK8963_BIT_16, AK8963_MODE_C100HZ) 25 | # self.calibrate() 26 | 27 | def configure(self): 28 | self.sampling_mpu_0x68.configure() 29 | self.sampling_mpu_0x69.configure() 30 | 31 | def reset(self): 32 | self.sampling_mpu_0x68.reset() 33 | self.sampling_mpu_0x69.reset() 34 | # self.configure() 35 | 36 | def calibrate(self): 37 | self.sampling_mpu_0x68.calibrate() 38 | self.sampling_mpu_0x69.calibrate() 39 | # self.configure() 40 | 41 | def start(self): 42 | timeSync = time.time() 43 | self.sampling_mpu_0x68.startSampling(timeSync) 44 | self.sampling_mpu_0x69.startSampling(timeSync) 45 | self.running = True 46 | 47 | def stop(self): 48 | 49 | if self.running: 50 | self.sampling_mpu_0x68.stopSampling() 51 | self.sampling_mpu_0x69.stopSampling() 52 | self.running = False 53 | 54 | def showCurrent(self): 55 | 56 | def formatValue(array, index): 57 | 58 | format = "{: 4.17f}" 59 | 60 | if len(array) > index: 61 | return format.format(array[index]) 62 | else: 63 | " null " 64 | 65 | def formatLabel(value): 66 | return value.center(20) 67 | 68 | data_0x68 = self.sampling_mpu_0x68.getAllData() 69 | data_0x69 = self.sampling_mpu_0x69.getAllData() 70 | 71 | print( 72 | "----------------------------------------------------------------------------------------------------------", "\n", 73 | "Time: ", time.time(), "\n", 74 | "----------------------------------------------------------------------------------------------------------", "\n", 75 | "MPU = ", formatLabel("0x68_master"), " | ", formatLabel("0x68_slave_of_0x68"), " | ", formatLabel("0x69_master"), " | ", formatLabel("0x68_slave_of_0x69"), "\n", 76 | "----------------------------------------------------------------------------------------------------------", "\n", 77 | "A_X = ", formatValue(data_0x68, 1), " | ", formatValue(data_0x68, 7), " | ", formatValue(data_0x69, 1), " | ", formatValue(data_0x69, 7), "\n", 78 | "A_Y = ", formatValue(data_0x68, 2), " | ", formatValue(data_0x68, 8), " | ", formatValue(data_0x69, 2), " | ", formatValue(data_0x69, 8), "\n", 79 | "A_Z = ", formatValue(data_0x68, 3), " | ", formatValue(data_0x68, 9), " | ", formatValue(data_0x69, 3), " | ", formatValue(data_0x69, 9), "\n", 80 | "----------------------------------------------------------------------------------------------------------", "\n", 81 | "G_X = ", formatValue(data_0x68, 4), " | ", formatValue(data_0x68, 10), " | ", formatValue(data_0x69, 4), " | ", formatValue(data_0x69, 10), "\n", 82 | "G_Y = ", formatValue(data_0x68, 5), " | ", formatValue(data_0x68, 11), " | ", formatValue(data_0x69, 5), " | ", formatValue(data_0x69, 11), "\n", 83 | "G_Z = ", formatValue(data_0x68, 6), " | ", formatValue(data_0x68, 12), " | ", formatValue(data_0x69, 6), " | ", formatValue(data_0x69, 12), "\n", 84 | "----------------------------------------------------------------------------------------------------------", "\n", 85 | "M_X = ", formatValue(data_0x68, 13), " | ", " null ", " | " , formatValue(data_0x69, 13), " | ", " null ", "\n", 86 | "M_Y = ", formatValue(data_0x68, 14), " | ", " null ", " | " , formatValue(data_0x69, 14), " | ", " null ", "\n", 87 | "M_Z = ", formatValue(data_0x68, 15), " | ", " null ", " | " , formatValue(data_0x69, 15), " | ", " null ", "\n", 88 | "----------------------------------------------------------------------------------------------------------", "\n", 89 | ) 90 | -------------------------------------------------------------------------------- /mpu9250_jmdev/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jefmenegazzo/mpu-i2c-drivers-python/841b83ee5577667c1111b76b87e2f0f2070f0759/mpu9250_jmdev/__init__.py -------------------------------------------------------------------------------- /mpu9250_jmdev/fake_smbus.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | # Author: Jeferson Menegazzo # 3 | # Year: 2020 # 4 | # License: CC BY-NC-ND 4.0 # 5 | ##################################################################### 6 | 7 | # Class for code testing without I2C access. 8 | class FakeSmbus(object): 9 | 10 | class SMBus(object): 11 | 12 | def __init__(self, bus): 13 | pass 14 | 15 | def write_byte_data(self, a, b, c): 16 | pass 17 | 18 | def read_byte_data(self, a, b): 19 | return 0 20 | 21 | def read_i2c_block_data(self, a, b, c): 22 | return [0] * c 23 | 24 | def close(self): 25 | pass -------------------------------------------------------------------------------- /mpu9250_jmdev/mpu_9250.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | # Author: Jeferson Menegazzo # 3 | # Year: 2020 # 4 | # License: CC BY-NC-ND 4.0 # 5 | ##################################################################### 6 | 7 | """ 8 | Based on: 9 | https://github.com/nickcoutsos/MPU-6050-Python/blob/master/MPU6050.py 10 | https://github.com/Tijndagamer/mpu6050/blob/master/mpu6050/mpu6050.py 11 | https://github.com/FaBoPlatform/FaBo9AXIS-MPU9250-Python/blob/master/FaBo9Axis_MPU9250/MPU9250.py 12 | https://github.com/kriswiner/MPU6050/blob/master/MPU6050IMU.ino 13 | https://github.com/kriswiner/MPU6050/wiki/Simple-and-Effective-Magnetometer-Calibration 14 | https://github.com/kriswiner/MPU9250/blob/master/MPU9250_MS5637_AHRS_t3.ino 15 | """ 16 | 17 | try: 18 | # smbus2 is faster than smbus 19 | # import smbus 20 | import smbus2 as smbus 21 | except ImportError: 22 | print("\n", "Using Fake SMBus", "\n", "Install requirements.", "\n") 23 | from mpu9250_jmdev.fake_smbus import FakeSmbus as smbus 24 | 25 | from mpu9250_jmdev.registers import * 26 | import time 27 | 28 | class MPU9250: 29 | 30 | # Address Settings 31 | address_ak = None 32 | address_mpu_master = None 33 | address_mpu_slave = None 34 | bus = None 35 | 36 | # Sensor Full Scale 37 | gfs = None # Gyroscope 38 | afs = None # Accelerometer 39 | mfs = None # Magnetometer 40 | mode = None # Magnetometer Mode 41 | 42 | # Sensor Resolution - Scale Factor 43 | gres = None # Gyroscope 44 | ares = None # Accelerometer 45 | mres = None # Magnetometer 46 | 47 | # Factory Magnetometer Calibration and Bias 48 | magCalibration = [0, 0, 0] 49 | 50 | # Magnetometer Soft Iron Distortion 51 | magScale = [1, 1, 1] 52 | 53 | # Master and Slave Biases 54 | gbias = [0, 0, 0] # Gyroscope Master Bias 55 | gbias_slave = [0, 0, 0] # Gyroscope Slave Bias 56 | abias = [0, 0, 0] # Accelerometer Master Bias 57 | abias_slave = [0, 0, 0] # Accelerometer Slave Bias 58 | mbias = [0, 0, 0] # Magnetometer Hard Iron Distortion 59 | 60 | # Constructor 61 | # @param [in] self - The object pointer. 62 | # @param [in] address_ak - AK8963 I2C slave address (default:AK8963_ADDRESS[0x0C]). 63 | # @param [in] address_mpu_master - MPU-9250 I2C address (default:MPU9050_ADDRESS_68[0x68]). 64 | # @param [in] address_mpu_slave - MPU-9250 I2C slave address (default:[None]). 65 | # @param [in] bus - I2C bus board (default:Board Revision 2[1]). 66 | # @param [in] gfs - Gyroscope full scale select (default:GFS_2000[2000dps]). 67 | # @param [in] afs - Accelerometer full scale select (default:AFS_16G[16g]). 68 | # @param [in] mfs - Magnetometer scale select (default:AK8963_BIT_16[16bit]) 69 | # @param [in] mode - Magnetometer mode select (default:AK8963_MODE_C100HZ[Continous 100Hz]) 70 | def __init__(self, 71 | address_ak=AK8963_ADDRESS, 72 | address_mpu_master=MPU9050_ADDRESS_68, 73 | address_mpu_slave=None, 74 | bus=1, 75 | gfs=GFS_2000, 76 | afs=AFS_16G, 77 | mfs=AK8963_BIT_16, 78 | mode=AK8963_MODE_C100HZ 79 | ): 80 | self.address_ak = address_ak 81 | self.address_mpu_master = address_mpu_master 82 | self.address_mpu_slave = address_mpu_slave 83 | self.bus = smbus.SMBus(bus) 84 | self.gfs = gfs 85 | self.afs = afs 86 | self.mfs = mfs 87 | self.mode = mode 88 | 89 | # Configure MPU-9250 90 | # @param [in] self - The object pointer. 91 | # @param [in] retry - number of retries. 92 | def configure(self, retry=3): 93 | 94 | try: 95 | self.configureMPU6500(self.gfs, self.afs) 96 | self.configureAK8963(self.mfs, self.mode) 97 | 98 | except OSError as err: 99 | 100 | if(retry > 1): 101 | self.configure(retry - 1) 102 | 103 | else: 104 | raise err 105 | 106 | # Configure MPU-6500 107 | # @param [in] self - The object pointer. 108 | # @param [in] gfs - Gyroscope full scale select. 109 | # @param [in] afs - Accelerometer full scale select. 110 | def configureMPU6500(self, gfs, afs): 111 | 112 | if gfs == GFS_250: 113 | self.gres = GYRO_SCALE_MODIFIER_250DEG 114 | elif gfs == GFS_500: 115 | self.gres = GYRO_SCALE_MODIFIER_500DEG 116 | elif gfs == GFS_1000: 117 | self.gres = GYRO_SCALE_MODIFIER_1000DEG 118 | elif gfs == GFS_2000: 119 | self.gres = GYRO_SCALE_MODIFIER_2000DEG 120 | else: 121 | raise Exception('Gyroscope scale modifier not found.') 122 | 123 | if afs == AFS_2G: 124 | self.ares = ACCEL_SCALE_MODIFIER_2G 125 | elif afs == AFS_4G: 126 | self.ares = ACCEL_SCALE_MODIFIER_4G 127 | elif afs == AFS_8G: 128 | self.ares = ACCEL_SCALE_MODIFIER_8G 129 | elif afs == AFS_16G: 130 | self.ares = ACCEL_SCALE_MODIFIER_16G 131 | else: 132 | raise Exception('Accelerometer scale modifier not found.') 133 | 134 | # sleep off 135 | self.writeMaster(PWR_MGMT_1, 0x00, 0.1) 136 | 137 | # auto select clock source 138 | self.writeMaster(PWR_MGMT_1, 0x01, 0.1) 139 | 140 | # DLPF_CFG 141 | self.writeMaster(CONFIG, 0x00) 142 | # self.writeMaster(CONFIG, 0x03) 143 | 144 | # sample rate divider 145 | self.writeMaster(SMPLRT_DIV, 0x00) 146 | # self.writeMaster(SMPLRT_DIV, 0x04) 147 | 148 | # gyro full scale select 149 | self.writeMaster(GYRO_CONFIG, gfs << 3) 150 | 151 | # accel full scale select 152 | self.writeMaster(ACCEL_CONFIG, afs << 3) 153 | 154 | # A_DLPFCFG 155 | self.writeMaster(ACCEL_CONFIG_2, 0x00) 156 | # self.writeMaster(ACCEL_CONFIG_2, 0x03) 157 | 158 | if not(self.hasSlave()): 159 | 160 | # BYPASS_EN enable 161 | self.writeMaster(INT_PIN_CFG, 0x02, 0.1) 162 | 163 | # Disable master 164 | self.writeMaster(USER_CTRL, 0x00, 0.1) 165 | 166 | else: 167 | 168 | # BYPASS_EN disabled 169 | self.writeMaster(INT_PIN_CFG, 0x00, 0.1) 170 | # self.writeMaster(INT_PIN_CFG, 0x22, 0.1) 171 | 172 | # Enable Master 173 | self.writeMaster(USER_CTRL, 0x20, 0.1) 174 | 175 | # Write to MPU Slave 176 | self.setSlaveToWrite() 177 | 178 | # sleep off 179 | self.writeSlave(PWR_MGMT_1, 0x00, 0.1) 180 | 181 | # auto select clock source 182 | self.writeSlave(PWR_MGMT_1, 0x01, 0.1) 183 | 184 | # DLPF_CFG 185 | self.writeSlave(CONFIG, 0x00) 186 | # self.writeSlave(CONFIG, 0x03) 187 | 188 | # sample rate divider 189 | self.writeSlave(SMPLRT_DIV, 0x00) 190 | # self.writeSlave(SMPLRT_DIV, 0x04) 191 | 192 | # gyro full scale select 193 | self.writeSlave(GYRO_CONFIG, gfs << 3) 194 | 195 | # accel full scale select 196 | self.writeSlave(ACCEL_CONFIG, afs << 3) 197 | 198 | # A_DLPFCFG 199 | self.writeSlave(ACCEL_CONFIG_2, 0x00) 200 | # self.writeSlave(ACCEL_CONFIG_2, 0x03) 201 | # self.writeSlave(ACCEL_CONFIG_2, 0x05) 202 | 203 | # BYPASS_EN enable 204 | self.writeSlave(INT_PIN_CFG, 0x02, 0.1) 205 | 206 | # Disable master 207 | self.writeSlave(USER_CTRL, 0x00, 0.1) 208 | 209 | # Read from MPU Slave 210 | self.writeMaster(I2C_SLV0_ADDR, self.address_mpu_slave | 0x80) # 0xE8 211 | self.writeMaster(I2C_SLV0_REG, ACCEL_OUT) 212 | self.writeMaster(I2C_SLV0_CTRL, 0x8E) # read 14 bytes Acc(6) + Gyro(6) + Temp(2) 213 | 214 | # Configure AK8963 215 | # @param [in] self - The object pointer. 216 | # @param [in] mfs - Magnetometer full scale select. 217 | # @param [in] mode - Magnetometer mode select. 218 | def configureAK8963(self, mfs, mode): 219 | 220 | if mfs == AK8963_BIT_14: 221 | self.mres = MAGNOMETER_SCALE_MODIFIER_BIT_14 222 | elif mfs == AK8963_BIT_16: 223 | self.mres = MAGNOMETER_SCALE_MODIFIER_BIT_16 224 | else: 225 | raise Exception('Magnetometer scale modifier not found.') 226 | 227 | data = [] 228 | 229 | if not(self.hasSlave()): 230 | 231 | # set power down mode 232 | self.writeAK(AK8963_CNTL1, 0x00, 0.1) 233 | 234 | # set read FuseROM mode 235 | self.writeAK(AK8963_CNTL1, 0x0F, 0.1) 236 | 237 | # read coef data 238 | data = self.readAK(AK8963_ASAX, 3) 239 | 240 | # set power down mode 241 | self.writeAK(AK8963_CNTL1, 0x00, 0.1) 242 | 243 | # set scale and continous mode 244 | self.writeAK(AK8963_CNTL1, (mfs << 4 | mode), 0.1) 245 | 246 | else: 247 | 248 | # Set to write MPU Slave 249 | self.setSlaveToWrite(self.address_ak) 250 | 251 | # set power down mode 252 | self.writeSlave(AK8963_CNTL1, 0x00, 0.1) 253 | 254 | # set read FuseROM mode 255 | self.writeSlave(AK8963_CNTL1, 0x0F, 0.1) 256 | 257 | # Address to read MPU Slave 258 | self.setSlaveToRead(self.address_ak) 259 | 260 | # read coef data 261 | data.append(self.readSlave(AK8963_ASAX)) 262 | data.append(self.readSlave(AK8963_ASAY)) 263 | data.append(self.readSlave(AK8963_ASAZ)) 264 | 265 | # Set to write MPU Slave 266 | self.setSlaveToWrite(self.address_ak) 267 | 268 | # set power down mode 269 | self.writeSlave(AK8963_CNTL1, 0x00, 0.1) 270 | 271 | # set scale and continous mode 272 | self.writeSlave(AK8963_CNTL1, (mfs << 4 | mode), 0.1) 273 | 274 | # Read from MPU Slave 275 | self.writeMaster(I2C_SLV1_ADDR, self.address_ak | 0x80) 276 | self.writeMaster(I2C_SLV1_REG, AK8963_MAGNET_OUT) 277 | self.writeMaster(I2C_SLV1_CTRL, 0x87) # read 7 bytes 278 | 279 | self.magCalibration = [ 280 | (data[0] - 128) / 256.0 + 1.0, 281 | (data[1] - 128) / 256.0 + 1.0, 282 | (data[2] - 128) / 256.0 + 1.0 283 | ] 284 | 285 | # Resets the values of the sensor registers. 286 | # @param [in] self - The object pointer. 287 | # @param [in] retry - number of retries. 288 | def reset(self, retry=3): 289 | 290 | try: 291 | 292 | if self.hasSlave(): 293 | self.resetMPU9250Slave() 294 | 295 | self.resetMPU9250Master() 296 | 297 | except OSError as err: 298 | 299 | if(retry > 1): 300 | self.reset(retry - 1) 301 | 302 | else: 303 | raise err 304 | 305 | # Reset all master registers to default. 306 | # @param [in] self - The object pointer. 307 | def resetMPU9250Master(self): 308 | self.writeMaster(PWR_MGMT_1, 0x80, 0.1) 309 | 310 | # Reset all slave registers to default. 311 | # @param [in] self - The object pointer. 312 | def resetMPU9250Slave(self): 313 | self.setSlaveToWrite() 314 | self.writeSlave(PWR_MGMT_1, 0x80, 0.1) 315 | 316 | # Read accelerometer from master. 317 | # @param [in] self - The object pointer. 318 | # @retval [x, y, z] - acceleration data. 319 | def readAccelerometerMaster(self): 320 | 321 | try: 322 | 323 | data = self.readMaster(ACCEL_OUT, 6) 324 | return self.convertAccelerometer(data, self.abias) 325 | 326 | except OSError: 327 | return self.getDataError() 328 | 329 | # Read accelerometer from slave. 330 | # @param [in] self - The object pointer. 331 | # @retval [x, y, z] - acceleration data. 332 | def readAccelerometerSlave(self): 333 | 334 | if self.hasSlave(): 335 | 336 | try: 337 | 338 | data = self.readMaster(EXT_SENS_DATA_00, 6) 339 | return self.convertAccelerometer(data, self.abias_slave) 340 | 341 | except OSError: 342 | return self.getDataError() 343 | 344 | else: 345 | return self.getDataError() 346 | 347 | # Convert accelerometer byte block to apply scale factor and biases. 348 | # @param [in] self - The object pointer. 349 | # @param [in] data - accelerometer 6-byte block. 350 | # @param [in] abias - biases. 351 | # @retval [x, y, z] - acceleration data. 352 | def convertAccelerometer(self, data, abias): 353 | 354 | x = (self.dataConv(data[1], data[0]) * self.ares) - abias[0] 355 | y = (self.dataConv(data[3], data[2]) * self.ares) - abias[1] 356 | z = (self.dataConv(data[5], data[4]) * self.ares) - abias[2] 357 | 358 | return [x, y, z] 359 | 360 | # Read gyroscope from master. 361 | # @param [in] self - The object pointer. 362 | # @retval [x, y, z] - gyroscope data. 363 | def readGyroscopeMaster(self): 364 | 365 | try: 366 | 367 | data = self.readMaster(GYRO_OUT, 6) 368 | return self.convertGyroscope(data, self.gbias) 369 | 370 | except OSError: 371 | return self.getDataError() 372 | 373 | # Read gyroscope from slave. 374 | # @param [in] self - The object pointer. 375 | # @retval [x, y, z] - gyroscope data. 376 | def readGyroscopeSlave(self): 377 | 378 | if self.hasSlave(): 379 | 380 | try: 381 | 382 | data = self.readMaster(EXT_SENS_DATA_08, 6) 383 | return self.convertGyroscope(data, self.gbias_slave) 384 | 385 | except OSError: 386 | return self.getDataError() 387 | 388 | else: 389 | return self.getDataError() 390 | 391 | # Convert gyroscope byte block to apply scale factor and biases. 392 | # @param [in] self - The object pointer. 393 | # @param [in] data - gyroscope 6-byte block. 394 | # @param [in] gbias - biases. 395 | # @retval [x, y, z] - gyroscope data. 396 | def convertGyroscope(self, data, gbias): 397 | 398 | x = (self.dataConv(data[1], data[0]) * self.gres) - gbias[0] 399 | y = (self.dataConv(data[3], data[2]) * self.gres) - gbias[1] 400 | z = (self.dataConv(data[5], data[4]) * self.gres) - gbias[2] 401 | 402 | return [x, y, z] 403 | 404 | # Read magnetometer from master. 405 | # @param [in] self - The object pointer. 406 | # @retval [x, y, z] - magnetometer data. 407 | def readMagnetometerMaster(self): 408 | 409 | try: 410 | 411 | data = None 412 | 413 | if self.hasSlave(): 414 | data = self.readMaster(EXT_SENS_DATA_14, 7) 415 | 416 | else: 417 | data = self.readAK(AK8963_MAGNET_OUT, 7) 418 | 419 | return self.convertMagnetometer(data) 420 | 421 | except OSError: 422 | return self.getDataError() 423 | 424 | # Convert magnetometer byte block to apply scale factor, biases and coeficiente. 425 | # @param [in] self - The object pointer. 426 | # @param [in] data - magnetometer 7-byte block. 427 | # @retval [x, y, z] - magnetometer data. 428 | def convertMagnetometer(self, data): 429 | 430 | # check overflow 431 | if (data[6] & 0x08) != 0x08: 432 | x = (self.dataConv(data[0], data[1]) * self.mres * self.magCalibration[0]) - self.mbias[0] 433 | y = (self.dataConv(data[2], data[3]) * self.mres * self.magCalibration[1]) - self.mbias[1] 434 | z = (self.dataConv(data[4], data[5]) * self.mres * self.magCalibration[2]) - self.mbias[2] 435 | x *= self.magScale[0] 436 | y *= self.magScale[1] 437 | z *= self.magScale[2] 438 | return [x, y, z] 439 | 440 | else: 441 | return self.getDataError() 442 | 443 | # Read temperature from master. 444 | # @param [in] self - The object pointer. 445 | # @retval temperature - temperature(degrees C). 446 | def readTemperatureMaster(self): 447 | 448 | try: 449 | 450 | data = self.readMaster(TEMP_OUT, 2) 451 | return self.convertTemperature(data) 452 | 453 | except OSError: 454 | return 0 455 | 456 | # Read temperature from slave. 457 | # @param [in] self - The object pointer. 458 | # @retval temperature - temperature(degrees C). 459 | def readTemperatureSlave(self): 460 | 461 | try: 462 | 463 | data = self.readMaster(EXT_SENS_DATA_06, 2) 464 | return self.convertTemperature(data) 465 | 466 | except OSError: 467 | return 0 468 | 469 | # Convert temperature byte block to apply to a value in measure unit degrees Centigrade (º C). 470 | # @param [in] self - The object pointer. 471 | # @param [in] data - temperature 2-byte block. 472 | # @retval temperature - temperature data. 473 | def convertTemperature(self, data): 474 | temp = self.dataConv(data[1], data[0]) 475 | temp = (temp / 333.87 + 21.0) 476 | return temp 477 | 478 | # Get array with data from all sensors obtained at same time. 479 | # @param [in] self - The object pointer. 480 | # @retval [[timestamp], [accMaster], [gyroMaster], [accSlave], [gyroSlave], [dataAK], [tempMaster], [tempSlave] ] - all sensors data. 481 | def getAllData(self): 482 | 483 | timestamp = time.time() 484 | 485 | try: 486 | 487 | dataMPU = self.readMaster(FIRST_DATA_POSITION, 28) 488 | dataAK = self.readMagnetometerMaster() 489 | 490 | accMaster = self.convertAccelerometer(dataMPU[0:6], self.abias) 491 | tempMaster = self.convertTemperature(dataMPU[6:8]) 492 | gyroMaster = self.convertGyroscope(dataMPU[8:14], self.gbias) 493 | 494 | if self.hasSlave(): 495 | accSlave = self.convertAccelerometer(dataMPU[14:20], self.abias_slave) 496 | tempSlave = self.convertTemperature(dataMPU[20:22]) 497 | gyroSlave = self.convertGyroscope(dataMPU[22:28], self.gbias_slave) 498 | 499 | else: 500 | accSlave = self.getDataError() 501 | tempSlave = 0 502 | gyroSlave = self.getDataError() 503 | 504 | return [timestamp] + accMaster + gyroMaster + accSlave + gyroSlave + dataAK + [tempMaster] + [tempSlave] 505 | 506 | except OSError: 507 | return [timestamp] + self.getDataError() + self.getDataError() + self.getDataError() + self.getDataError() + self.getDataError() + [0, 0] 508 | 509 | # Get array with labels for data obtained from getAllData. 510 | # @param [in] self - The object pointer. 511 | # @retval labels. 512 | def getAllDataLabels(self): 513 | 514 | return [ 515 | "timestamp", 516 | "master_acc_x", 517 | "master_acc_y", 518 | "master_acc_z", 519 | "master_gyro_x", 520 | "master_gyro_y", 521 | "master_gyro_z", 522 | "slave_acc_x", 523 | "slave_acc_y", 524 | "slave_acc_z", 525 | "slave_gyro_x", 526 | "slave_gyro_y", 527 | "slave_gyro_z", 528 | "mag_x", 529 | "mag_y", 530 | "mag_z", 531 | "master_temp", 532 | "slave_temp" 533 | ] 534 | 535 | # When data is not available/error when read, is returned an array with 0. 536 | # @param [in] self - The object pointer. 537 | def getDataError(self): 538 | return [0, 0, 0] 539 | 540 | # Data Convert 541 | # @param [in] self - The object pointer. 542 | # @param [in] data1 - LSB 543 | # @param [in] data2 - MSB 544 | # @retval Value: MSB+LSB(int 16bit) 545 | def dataConv(self, data1, data2): 546 | 547 | value = data1 | (data2 << 8) 548 | 549 | if(value & (1 << 16 - 1)): 550 | value -= (1 << 16) 551 | 552 | return value 553 | 554 | # Search MPU Device master. 555 | # @param [in] self - The object pointer. 556 | # @retval true - device connected 557 | # @retval false - device error 558 | def searchMPUDevice(self): 559 | who_am_i = self.readMaster(WHO_AM_I, 1)[0] 560 | return who_am_i == DEVICE_ID 561 | 562 | # Check MPU data ready master. 563 | # @param [in] self - The object pointer. 564 | # @retval true - data is ready 565 | # @retval false - data is not ready 566 | def checkMPUDataReady(self): 567 | drdy = self.readMaster(INT_STATUS, 1)[0] 568 | return drdy & 0x01 569 | 570 | # Check AK data ready. 571 | # @param [in] self - The object pointer. 572 | # @retval true - data is ready 573 | # @retval false - data is not ready 574 | def checkAKDataReady(self): 575 | drdy = self.readAK(AK8963_ST1, 1)[0] 576 | return drdy & 0x01 577 | 578 | # Check if MPU has slave. 579 | # @param [in] self - The object pointer. 580 | # @retval true - if has slave (another MPU) 581 | # @retval false - if has not slave 582 | def hasSlave(self): 583 | return not(self.address_mpu_slave is None) 584 | 585 | # Calibrate all sensors. 586 | # @param [in] self - The object pointer. 587 | # @param [in] retry - number of retries. 588 | def calibrate(self, retry=3): 589 | 590 | try: 591 | print("Calibrating", hex(self.address_mpu_master), "- AK8963") 592 | self.calibrateAK8963() 593 | print("Calibrating", hex(self.address_mpu_master), "- MPU6500") 594 | self.calibrateMPU6500() 595 | 596 | except OSError as err: 597 | 598 | if(retry > 1): 599 | self.calibrate(retry - 1) 600 | 601 | else: 602 | raise err 603 | 604 | # This function calibrate MPU6500 and load biases to params in this class. 605 | # To calibrate, you must correctly position the MPU so that gravity is all along the z axis of the accelerometer. 606 | # This function accumulates gyro and accelerometer data after device initialization. It calculates the average 607 | # of the at-rest readings and then loads the resulting offsets into accelerometer and gyro bias registers. 608 | # This function reset sensor registers. Configure must be called after. 609 | # @param [in] self - The object pointer. 610 | def calibrateMPU6500(self): 611 | 612 | # reset device 613 | self.reset() 614 | 615 | # get stable time source; Auto select clock source to be PLL gyroscope reference if ready, else use the internal oscillator, bits 2:0 = 001 616 | self.writeMaster(PWR_MGMT_1, 0x01) 617 | self.writeMaster(PWR_MGMT_2, 0x00, 0.2) 618 | 619 | # Configure device for bias calculation 620 | self.writeMaster(INT_ENABLE, 0x00) # Disable all interrupts 621 | self.writeMaster(FIFO_EN, 0x00) # Disable FIFO 622 | self.writeMaster(PWR_MGMT_1, 0x00) # Turn on internal clock source 623 | self.writeMaster(I2C_MST_CTRL, 0x00) # Disable I2C master 624 | self.writeMaster(USER_CTRL, 0x00) # Disable FIFO and I2C master modes 625 | self.writeMaster(USER_CTRL, 0x0C, 0.015) # Reset FIFO and DMP 626 | 627 | # Configure MPU6500 gyro and accelerometer for bias calculation 628 | self.writeMaster(CONFIG, 0x01) # Set low-pass filter to 188 Hz 629 | self.writeMaster(SMPLRT_DIV, 0x00) # Set sample rate to 1 kHz 630 | self.writeMaster(GYRO_CONFIG, 0x00) # Set gyro full-scale to 250 degrees per second, maximum sensitivity 631 | self.writeMaster(ACCEL_CONFIG, 0x00) # Set accelerometer full-scale to 2G, maximum sensitivity 632 | 633 | # Configure FIFO to capture accelerometer and gyro data for bias calculation 634 | self.writeMaster(USER_CTRL, 0x40) # Enable FIFO 635 | self.writeMaster(FIFO_EN, 0x78, 0.04) # Enable gyro and accelerometer sensors for FIFO (max size 512 bytes in MPU-9150) # 0.4 - accumulate 40 samples in 40 milliseconds = 480 bytes 636 | 637 | # At end of sample accumulation, turn off FIFO sensor read 638 | self.writeMaster(FIFO_EN, 0x00) # Disable gyro and accelerometer sensors for FIFO 639 | 640 | # read FIFO sample count 641 | data = self.readMaster(FIFO_COUNTH, 2) 642 | fifo_count = self.dataConv(data[1], data[0]) 643 | packet_count = int(fifo_count / 12); # How many sets of full gyro and accelerometer data for averaging 644 | 645 | index = 0 646 | accel_bias = [0, 0, 0] 647 | gyro_bias = [0, 0, 0] 648 | 649 | while index < packet_count: 650 | 651 | # read data for averaging 652 | data = self.readMaster(FIFO_R_W, 12) 653 | 654 | # Form signed 16-bit integer for each sample in FIFO 655 | # Sum individual signed 16-bit biases to get accumulated signed 32-bit biases 656 | accel_bias[0] += self.dataConv(data[1], data[0]) 657 | accel_bias[1] += self.dataConv(data[3], data[2]) 658 | accel_bias[2] += self.dataConv(data[5], data[4]) 659 | gyro_bias[0] += self.dataConv(data[7], data[6]) 660 | gyro_bias[1] += self.dataConv(data[9], data[8]) 661 | gyro_bias[2] += self.dataConv(data[11], data[10]) 662 | 663 | index += 1 664 | 665 | # Normalize sums to get average count biases 666 | accel_bias[0] /= packet_count 667 | accel_bias[1] /= packet_count 668 | accel_bias[2] /= packet_count 669 | gyro_bias[0] /= packet_count 670 | gyro_bias[1] /= packet_count 671 | gyro_bias[2] /= packet_count 672 | 673 | # Remove gravity from the z-axis accelerometer bias calculation 674 | if accel_bias[2] > 0: 675 | accel_bias[2] -= ACCEL_SCALE_MODIFIER_2G_DIV 676 | else: 677 | accel_bias[2] += ACCEL_SCALE_MODIFIER_2G_DIV 678 | 679 | # Output scaled gyro biases for display in the main program 680 | self.gbias = [ 681 | (gyro_bias[0] / GYRO_SCALE_MODIFIER_250DEG_DIV), 682 | (gyro_bias[1] / GYRO_SCALE_MODIFIER_250DEG_DIV), 683 | (gyro_bias[2] / GYRO_SCALE_MODIFIER_250DEG_DIV) 684 | ] 685 | 686 | # Output scaled accelerometer biases for manual subtraction in the main program 687 | self.abias = [ 688 | (accel_bias[0] / ACCEL_SCALE_MODIFIER_2G_DIV), 689 | (accel_bias[1] / ACCEL_SCALE_MODIFIER_2G_DIV), 690 | (accel_bias[2] / ACCEL_SCALE_MODIFIER_2G_DIV) 691 | ] 692 | 693 | if self.hasSlave(): 694 | 695 | # Reset all 696 | self.reset() 697 | 698 | # BYPASS_EN disabled 699 | self.writeMaster(INT_PIN_CFG, 0x00, 0.1) 700 | 701 | # Enable Master 702 | self.writeMaster(USER_CTRL, 0x20, 0.1) 703 | 704 | # Address to write MPU Slave 705 | self.setSlaveToWrite() 706 | 707 | # get stable time source; Auto select clock source to be PLL gyroscope reference if ready, else use the internal oscillator, bits 2:0 = 001 708 | self.writeSlave(PWR_MGMT_1, 0x01) 709 | self.writeSlave(PWR_MGMT_2, 0x00, 0.2) 710 | 711 | # Configure device for bias calculation 712 | self.writeSlave(INT_ENABLE, 0x00) # Disable all interrupts 713 | self.writeSlave(FIFO_EN, 0x00) # Disable FIFO 714 | self.writeSlave(PWR_MGMT_1, 0x00) # Turn on internal clock source 715 | self.writeSlave(I2C_MST_CTRL, 0x00) # Disable I2C master 716 | self.writeSlave(USER_CTRL, 0x00) # Disable FIFO and I2C master modes 717 | self.writeSlave(USER_CTRL, 0x0C, 0.015) # Reset FIFO and DMP 718 | 719 | # Configure MPU6500 gyro and accelerometer for bias calculation 720 | self.writeSlave(CONFIG, 0x01) # Set low-pass filter to 188 Hz 721 | self.writeSlave(SMPLRT_DIV, 0x00) # Set sample rate to 1 kHz 722 | self.writeSlave(GYRO_CONFIG, 0x00) # Set gyro full-scale to 250 degrees per second, maximum sensitivity 723 | self.writeSlave(ACCEL_CONFIG, 0x00) # Set accelerometer full-scale to 2G, maximum sensitivity 724 | 725 | # Configure FIFO to capture accelerometer and gyro data for bias calculation 726 | self.writeSlave(USER_CTRL, 0x40) # Enable FIFO 727 | self.writeSlave(FIFO_EN, 0x78, 0.04) # Enable gyro and accelerometer sensors for FIFO (max size 512 bytes in MPU-9150) # 0.4 - accumulate 40 samples in 40 milliseconds = 480 bytes 728 | 729 | # At end of sample accumulation, turn off FIFO sensor read 730 | self.writeSlave(FIFO_EN, 0x00) # Disable gyro and accelerometer sensors for FIFO 731 | 732 | # Slave to read 733 | self.setSlaveToRead() 734 | 735 | # read FIFO sample count 736 | data = [ 737 | self.readSlave(FIFO_COUNTH), 738 | self.readSlave(FIFO_COUNTL) 739 | ] 740 | 741 | fifo_count = self.dataConv(data[1], data[0]) 742 | packet_count = int(fifo_count / 12); # How many sets of full gyro and accelerometer data for averaging 743 | 744 | if fifo_count == 0: 745 | print("Could not connect to slave to calibrate") 746 | 747 | else: 748 | 749 | index = 0 750 | accel_bias = [0, 0, 0] 751 | gyro_bias = [0, 0, 0] 752 | 753 | while index < packet_count: 754 | 755 | i = 0 756 | data = [] 757 | 758 | while i < 12: 759 | data.append(self.readSlave(FIFO_R_W)) # read data for averaging 760 | i += 1 761 | 762 | # Form signed 16-bit integer for each sample in FIFO 763 | # Sum individual signed 16-bit biases to get accumulated signed 32-bit biases 764 | accel_bias[0] += self.dataConv(data[1], data[0]) 765 | accel_bias[1] += self.dataConv(data[3], data[2]) 766 | accel_bias[2] += self.dataConv(data[5], data[4]) 767 | gyro_bias[0] += self.dataConv(data[7], data[6]) 768 | gyro_bias[1] += self.dataConv(data[9], data[8]) 769 | gyro_bias[2] += self.dataConv(data[11], data[10]) 770 | 771 | index += 1 772 | 773 | # Normalize sums to get average count biases 774 | accel_bias[0] /= packet_count 775 | accel_bias[1] /= packet_count 776 | accel_bias[2] /= packet_count 777 | gyro_bias[0] /= packet_count 778 | gyro_bias[1] /= packet_count 779 | gyro_bias[2] /= packet_count 780 | 781 | # Remove gravity from the z-axis accelerometer bias calculation 782 | if accel_bias[2] > 0: 783 | accel_bias[2] -= ACCEL_SCALE_MODIFIER_2G_DIV 784 | else: 785 | accel_bias[2] += ACCEL_SCALE_MODIFIER_2G_DIV 786 | 787 | self.abias_slave = [ 788 | (accel_bias[0] / ACCEL_SCALE_MODIFIER_2G_DIV), 789 | (accel_bias[1] / ACCEL_SCALE_MODIFIER_2G_DIV), 790 | (accel_bias[2] / ACCEL_SCALE_MODIFIER_2G_DIV) 791 | ] 792 | 793 | self.gbias_slave = [ 794 | (gyro_bias[0] / GYRO_SCALE_MODIFIER_250DEG_DIV), 795 | (gyro_bias[1] / GYRO_SCALE_MODIFIER_250DEG_DIV), 796 | (gyro_bias[2] / GYRO_SCALE_MODIFIER_250DEG_DIV) 797 | ] 798 | 799 | self.reset() 800 | 801 | # This function calibrate AK8963 and load biases to params in this class. 802 | # This function reset sensor registers. Configure must be called after. 803 | # @param [in] self - The object pointer. 804 | def calibrateAK8963(self): 805 | 806 | self.configureAK8963(self.mfs, self.mode) 807 | 808 | index = 0 809 | sample_count = 0 810 | mag_bias = [0, 0, 0] 811 | mag_scale = [0, 0, 0] 812 | mag_max = [-32767, -32767, -32767] 813 | mag_min = [32767, 32767, 32767] 814 | mag_temp = [0, 0, 0] 815 | 816 | # shoot for ~fifteen seconds of mag data 817 | if (self.mode == AK8963_MODE_C8HZ): 818 | sample_count = 128; # at 8 Hz ODR, new mag data is available every 125 ms 819 | 820 | if (self.mode == AK8963_MODE_C100HZ): 821 | sample_count = 1500; # at 100 Hz ODR, new mag data is available every 10 ms 822 | 823 | index = 0 824 | 825 | while index < sample_count: 826 | 827 | index += 1 828 | data = None 829 | 830 | if self.hasSlave(): 831 | data = self.readMaster(EXT_SENS_DATA_14, 7) 832 | 833 | else: 834 | data = self.readAK(AK8963_MAGNET_OUT, 7) 835 | 836 | # check overflow 837 | if (data[6] & 0x08) != 0x08: 838 | 839 | mag_temp = [ 840 | self.dataConv(data[0], data[1]), 841 | self.dataConv(data[2], data[3]), 842 | self.dataConv(data[4], data[5]) 843 | ] 844 | 845 | else: 846 | mag_temp = self.getDataError() 847 | 848 | indexAxes = 0 849 | 850 | while indexAxes < 3: 851 | 852 | if (mag_temp[indexAxes] > mag_max[indexAxes]): 853 | mag_max[indexAxes] = mag_temp[indexAxes] 854 | 855 | if (mag_temp[indexAxes] < mag_min[indexAxes]): 856 | mag_min[indexAxes] = mag_temp[indexAxes] 857 | 858 | indexAxes += 1 859 | 860 | if (self.mode == AK8963_MODE_C8HZ): 861 | time.sleep(0.135) # at 8 Hz ODR, new mag data is available every 125 ms 862 | 863 | if (self.mode == AK8963_MODE_C100HZ): 864 | time.sleep(0.012); # at 100 Hz ODR, new mag data is available every 10 ms 865 | 866 | # Get hard iron correction 867 | mag_bias[0] = (mag_max[0] + mag_min[0]) / 2 # get average x mag bias in counts 868 | mag_bias[1] = (mag_max[1] + mag_min[1]) / 2 # get average y mag bias in counts 869 | mag_bias[2] = (mag_max[2] + mag_min[2]) / 2 # get average z mag bias in counts 870 | 871 | # save mag biases in G for main program 872 | self.mbias = [ 873 | mag_bias[0] * self.mres * self.magCalibration[0], 874 | mag_bias[1] * self.mres * self.magCalibration[1], 875 | mag_bias[2] * self.mres * self.magCalibration[2] 876 | ] 877 | 878 | # Get soft iron correction estimate 879 | mag_scale[0] = (mag_max[0] - mag_min[0]) / 2 # get average x axis max chord length in counts 880 | mag_scale[1] = (mag_max[1] - mag_min[1]) / 2 # get average y axis max chord length in counts 881 | mag_scale[2] = (mag_max[2] - mag_min[2]) / 2 # get average z axis max chord length in counts 882 | 883 | avg_rad = mag_scale[0] + mag_scale[1] + mag_scale[2] 884 | avg_rad /= 3.0 885 | 886 | self.magScale = [ 887 | avg_rad / mag_scale[0], 888 | avg_rad / mag_scale[1], 889 | avg_rad / mag_scale[2] 890 | ] 891 | 892 | # Get array with settings from all sensors obtained at same time. 893 | # @param [in] self - The object pointer. 894 | # @retval [[timestamp], [addresses], [fullScale], [resolution], [gbias], [gbias_slave], [abias], [abias_slave], [magCalibration], [magScale], [mbias] ] - all sensors settings. 895 | def getAllSettings(self): 896 | 897 | data = [ 898 | time.time(), 899 | 900 | None if self.address_mpu_master is None else str(hex(self.address_mpu_master)), 901 | None if self.address_mpu_slave is None else str(hex(self.address_mpu_slave)), 902 | None if self.address_ak is None else str(hex(self.address_ak)), 903 | 904 | self.getGyroscoleFullScaleLabel(), 905 | self.getAccelerometerFullScaleLabel(), 906 | self.getMagnetometerFullScaleLabel(), 907 | 908 | self.gres, 909 | self.ares, 910 | self.mres 911 | ] + self.gbias + self.gbias_slave + self.abias + self.abias_slave + self.magCalibration + self.magScale + self.mbias 912 | 913 | return data 914 | 915 | # Get array with labels for settings obtained from getAllSettings. 916 | # @param [in] self - The object pointer. 917 | # @retval labels. 918 | def getAllSettingsLabels(self): 919 | 920 | return [ 921 | "timestamp", 922 | 923 | "address_mpu_master", 924 | "address_mpu_slave", 925 | "address_ak", 926 | 927 | "gyroscope_full_scale", 928 | "accelerometer_full_scale", 929 | "magnetometer_full_scale", 930 | 931 | "gyroscope_resolution", 932 | "accelerometer_resolution", 933 | "magnetometer_resolution", 934 | 935 | "gyroscope_master_bias_x", 936 | "gyroscope_master_bias_y", 937 | "gyroscope_master_bias_z", 938 | 939 | "gyroscope_slave_bias_x", 940 | "gyroscope_slave_bias_y", 941 | "gyroscope_slave_bias_z", 942 | 943 | "accelerometer_master_bias_x", 944 | "accelerometer_master_bias_y", 945 | "accelerometer_master_bias_z", 946 | 947 | "accelerometer_slave_bias_x", 948 | "accelerometer_slave_bias_y", 949 | "accelerometer_slave_bias_z", 950 | 951 | "magnetometer_factory_sensitivity_x", 952 | "magnetometer_factory_sensitivity_y", 953 | "magnetometer_factory_sensitivity_z", 954 | 955 | "magnetometer_soft_iron_distortion_x", 956 | "magnetometer_soft_iron_distortion_y", 957 | "magnetometer_soft_iron_distortion_z", 958 | 959 | "magnetometer_hard_iron_distortion_x", 960 | "magnetometer_hard_iron_distortion_y", 961 | "magnetometer_hard_iron_distortion_z" 962 | ] 963 | 964 | # Get label for gyroscope full scale value. 965 | # @param [in] self - The object pointer. 966 | # @retval label. 967 | def getGyroscoleFullScaleLabel(self): 968 | 969 | if self.gfs == GFS_250: 970 | return "GFS_250" 971 | elif self.gfs == GFS_500: 972 | return "GFS_500" 973 | elif self.gfs == GFS_1000: 974 | return "GFS_1000" 975 | elif self.gfs == GFS_2000: 976 | return "GFS_2000" 977 | else: 978 | return None 979 | 980 | # Get label for accelerometer full scale value. 981 | # @param [in] self - The object pointer. 982 | # @retval label. 983 | def getAccelerometerFullScaleLabel(self): 984 | 985 | if self.afs == AFS_2G: 986 | return "AFS_2G" 987 | elif self.afs == AFS_4G: 988 | return "AFS_4G" 989 | elif self.afs == AFS_8G: 990 | return "AFS_8G" 991 | elif self.afs == AFS_16G: 992 | return "AFS_16G" 993 | else: 994 | return None 995 | 996 | # Get label for magnetometer full scale value. 997 | # @param [in] self - The object pointer. 998 | # @retval label. 999 | def getMagnetometerFullScaleLabel(self): 1000 | 1001 | if self.mfs == AK8963_BIT_14: 1002 | return "AK8963_BIT_14" 1003 | elif self.mfs == AK8963_BIT_16: 1004 | return "AK8963_BIT_16" 1005 | else: 1006 | return None 1007 | 1008 | ################################################################## Master Methods ################################################################## 1009 | 1010 | def writeAK(self, register, value, sleep = 0): 1011 | 1012 | self.bus.write_byte_data(self.address_ak, register, value) 1013 | 1014 | if sleep > 0: 1015 | time.sleep(sleep) 1016 | 1017 | def readAK(self, register, quantity): 1018 | return self.bus.read_i2c_block_data(self.address_ak, register, quantity) 1019 | 1020 | def writeMaster(self, register, value, sleep = 0): 1021 | 1022 | self.bus.write_byte_data(self.address_mpu_master, register, value) 1023 | 1024 | if sleep > 0: 1025 | time.sleep(sleep) 1026 | 1027 | def readMaster(self, register, quantity): 1028 | return self.bus.read_i2c_block_data(self.address_mpu_master, register, quantity) 1029 | 1030 | ################################################################## Slave Methods ################################################################## 1031 | 1032 | # Set to write MPU Slave 1033 | def setSlaveToWrite(self, address=None): 1034 | 1035 | if address is None: 1036 | address = self.address_mpu_slave 1037 | 1038 | self.bus.write_byte_data(self.address_mpu_master, I2C_SLV4_ADDR, address) 1039 | 1040 | # Write in slave 1041 | def writeSlave(self, register, value, sleep = 0): 1042 | self.bus.write_byte_data(self.address_mpu_master, I2C_SLV4_REG, register) 1043 | self.bus.write_byte_data(self.address_mpu_master, I2C_SLV4_DO, value) 1044 | self.bus.write_byte_data(self.address_mpu_master, I2C_SLV4_CTRL, 0x80) 1045 | 1046 | if sleep > 0: 1047 | time.sleep(sleep) 1048 | 1049 | # Set to read MPU Slave 1050 | def setSlaveToRead(self, address=None): 1051 | 1052 | if address is None: 1053 | address = self.address_mpu_slave 1054 | 1055 | self.bus.write_byte_data(self.address_mpu_master, I2C_SLV4_ADDR, address | 0x80) 1056 | 1057 | # Read from slave 1058 | def readSlave(self, register): 1059 | self.bus.write_byte_data(self.address_mpu_master, I2C_SLV4_REG, register) 1060 | self.bus.write_byte_data(self.address_mpu_master, I2C_SLV4_CTRL, 0x80) 1061 | return self.bus.read_byte_data(self.address_mpu_master, I2C_SLV4_DI) 1062 | -------------------------------------------------------------------------------- /mpu9250_jmdev/registers.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | # Author: Jeferson Menegazzo # 3 | # Year: 2020 # 4 | # License: CC BY-NC-ND 4.0 # 5 | ##################################################################### 6 | 7 | ########################################################### 8 | # Register Map for Gyroscope and Accelerometer - MPU 9250 9 | ########################################################### 10 | 11 | # Gyroscope Self-Test Registers 12 | SELF_TEST_X_GYRO = 0x00 13 | SELF_TEST_Y_GYRO = 0x01 14 | SELF_TEST_Z_GYRO = 0x02 15 | 16 | # Accelerometer Self-Test Registers 17 | SELF_TEST_X_ACCEL = 0x0D 18 | SELF_TEST_Y_ACCEL = 0x0E 19 | SELF_TEST_Z_ACCEL = 0x0F 20 | 21 | # Gyro Offset Registers 22 | XG_OFFSET_H = 0x13 23 | XG_OFFSET_L = 0x14 24 | YG_OFFSET_H = 0x15 25 | YG_OFFSET_L = 0x16 26 | ZG_OFFSET_H = 0x17 27 | ZG_OFFSET_L = 0x18 28 | 29 | # Accelerometer Offset Registers 30 | XA_OFFSET_H = 0x77 31 | XA_OFFSET_L = 0x78 32 | YA_OFFSET_H = 0x7A 33 | YA_OFFSET_L = 0x7B 34 | ZA_OFFSET_H = 0x7D 35 | ZA_OFFSET_L = 0x7E 36 | 37 | # Sample Rate Divider 38 | SMPLRT_DIV = 0x19 39 | 40 | # Configuration 41 | CONFIG = 0x1A 42 | 43 | # Gyroscope Configuration 44 | GYRO_CONFIG = 0x1B 45 | 46 | # Accelerometer Configuration 47 | ACCEL_CONFIG = 0x1C 48 | 49 | # Accelerometer Configuration 2 50 | ACCEL_CONFIG_2 = 0x1D 51 | 52 | # Low Power Accelerometer ODR Control 53 | LP_ACCEL_ODR = 0x1E 54 | 55 | # Wake-on Motion Threshold 56 | WOM_THR = 0x1F 57 | 58 | # FIFO Enable 59 | FIFO_EN = 0x23 60 | 61 | # I2C Master Control 62 | I2C_MST_CTRL = 0x24 63 | 64 | # I2C Slave 0 Control 65 | I2C_SLV0_ADDR = 0x25 66 | I2C_SLV0_REG = 0x26 67 | I2C_SLV0_DO = 0x63 68 | I2C_SLV0_CTRL = 0x27 69 | 70 | # I2C Slave 1 Control 71 | I2C_SLV1_ADDR = 0x28 72 | I2C_SLV1_REG = 0x29 73 | I2C_SLV1_DO = 0x64 74 | I2C_SLV1_CTRL = 0x2A 75 | 76 | # I2C Slave 2 Control 77 | I2C_SLV2_ADDR = 0x2B 78 | I2C_SLV2_REG = 0x2C 79 | I2C_SLV2_DO = 0x65 80 | I2C_SLV2_CTRL = 0x2D 81 | 82 | # I2C Slave 3 Control 83 | I2C_SLV3_ADDR = 0x2E 84 | I2C_SLV3_REG = 0x2F 85 | I2C_SLV3_DO = 0x66 86 | I2C_SLV3_CTRL = 0x30 87 | 88 | # I2C Slave 4 Control 89 | I2C_SLV4_ADDR = 0x31 90 | I2C_SLV4_REG = 0x32 91 | I2C_SLV4_DO = 0x33 92 | I2C_SLV4_CTRL = 0x34 93 | I2C_SLV4_DI = 0x35 94 | 95 | # I2C Master Status 96 | I2C_MST_STATUS = 0x36 97 | 98 | # INT Pin / Bypass Enable Configuration 99 | ## BYPASS_EN[1]: 100 | ### When asserted, the i2c_master interface pins(ES_CL and ES_DA) will go into ‘bypass mode’ when the i2c master interface is disabled. 101 | ### The pins will float high due to the internal pull-up if not enabled and the i2c master interface is disabled. 102 | INT_PIN_CFG = 0x37 103 | 104 | # Interrupt Enable 105 | INT_ENABLE = 0x38 106 | 107 | # Interrupt Status 108 | INT_STATUS = 0x3A 109 | 110 | # Accelerometer Measurements - High byte and low byte 111 | ACCEL_XOUT_H = 0x3B 112 | ACCEL_XOUT_L = 0x3C 113 | ACCEL_YOUT_H = 0x3D 114 | ACCEL_YOUT_L = 0x3E 115 | ACCEL_ZOUT_H = 0x3F 116 | ACCEL_ZOUT_L = 0x40 117 | 118 | # Temperature Measurement 119 | TEMP_OUT_H = 0x41 120 | TEMP_OUT_L = 0x42 121 | 122 | # Gyroscope Measurements - High byte and low byte 123 | GYRO_XOUT_H = 0x43 124 | GYRO_XOUT_L = 0x44 125 | GYRO_YOUT_H = 0x45 126 | GYRO_YOUT_L = 0x46 127 | GYRO_ZOUT_H = 0x47 128 | GYRO_ZOUT_L = 0x48 129 | 130 | # External Sensor Data 131 | EXT_SENS_DATA_00 = 0x49 132 | EXT_SENS_DATA_01 = 0x4A 133 | EXT_SENS_DATA_02 = 0x4B 134 | EXT_SENS_DATA_03 = 0x4C 135 | EXT_SENS_DATA_04 = 0x4D 136 | EXT_SENS_DATA_05 = 0x4E 137 | EXT_SENS_DATA_06 = 0x4F 138 | EXT_SENS_DATA_07 = 0x50 139 | EXT_SENS_DATA_08 = 0x51 140 | EXT_SENS_DATA_09 = 0x52 141 | EXT_SENS_DATA_10 = 0x53 142 | EXT_SENS_DATA_11 = 0x54 143 | EXT_SENS_DATA_12 = 0x55 144 | EXT_SENS_DATA_13 = 0x56 145 | EXT_SENS_DATA_14 = 0x57 146 | EXT_SENS_DATA_15 = 0x58 147 | EXT_SENS_DATA_16 = 0x59 148 | EXT_SENS_DATA_17 = 0x5A 149 | EXT_SENS_DATA_18 = 0x5B 150 | EXT_SENS_DATA_19 = 0x5C 151 | EXT_SENS_DATA_20 = 0x5D 152 | EXT_SENS_DATA_21 = 0x5E 153 | EXT_SENS_DATA_22 = 0x5F 154 | EXT_SENS_DATA_23 = 0x60 155 | 156 | # I2C Master Delay Control 157 | I2C_MST_DELAY_CTRL = 0x67 158 | 159 | # Signal Path Reset 160 | SIGNAL_PATH_RESET = 0x68 161 | 162 | # Accelerometer Interrupt Control 163 | MOT_DETECT_CTRL = 0x69 164 | 165 | # User Control 166 | ## I2C_MST_EN[5]: 167 | ### 1 – Enable the I2C Master I/F module; pins ES_DA and ES_SCL are isolated from pins SDA/SDI and SCL/ SCLK. 168 | ### 0 – Disable I2C Master I/F module; pins ES_DA and ES_SCL are logically driven by pins SDA/SDI and SCL/ SCLK. 169 | USER_CTRL = 0x6A 170 | 171 | # Power Management 1 172 | PWR_MGMT_1 = 0x6B 173 | 174 | # Power Management 2 175 | PWR_MGMT_2 = 0x6C 176 | 177 | # FIFO Count Registers 178 | FIFO_COUNTH = 0x72 179 | FIFO_COUNTL = 0x73 180 | 181 | # FIFO Read Write 182 | FIFO_R_W = 0x74 183 | 184 | # Who Am I 185 | WHO_AM_I = 0x75 186 | 187 | # Gyro Full Scale Select 188 | GFS_250 = 0x00 # 250dps 189 | GFS_500 = 0x01 # 500dps 190 | GFS_1000 = 0x02 # 1000dps 191 | GFS_2000 = 0x03 # 2000dps 192 | 193 | # Accel Full Scale Select 194 | AFS_2G = 0x00 # 2G 195 | AFS_4G = 0x01 # 4G 196 | AFS_8G = 0x02 # 8G 197 | AFS_16G = 0x03 # 16G 198 | 199 | ########################################################### 200 | # Register Map for Magnetometer - AK8963 201 | ########################################################### 202 | 203 | # Device ID 204 | AK8963_WIA = 0x00 205 | 206 | # Information 207 | AK8963_INFO = 0x01 208 | 209 | # Status 1 210 | AK8963_ST1 = 0x02 211 | 212 | # Measurement Data 213 | AK8963_HXL = 0x03 214 | AK8963_HXH = 0x04 215 | AK8963_HYL = 0x05 216 | AK8963_HYH = 0x06 217 | AK8963_HZL = 0x07 218 | AK8963_HZH = 0x08 219 | 220 | # Status 2 221 | AK8963_ST2 = 0x09 222 | 223 | # Control 1 224 | #AK8963_CNTL = 0x0A 225 | AK8963_CNTL1 = 0x0A 226 | # Control 2 227 | # AK8963_RSV = 0x0B 228 | AK8963_CNTL2 = 0x0B 229 | 230 | # Self-Test Control 231 | AK8963_ASTC = 0x0C 232 | 233 | # Test 1, 2 234 | AK8963_TS1 = 0x0D 235 | AK8963_TS2 = 0x0E 236 | 237 | # I2C Disable 238 | AK8963_I2CDIS = 0x0F 239 | 240 | # Sensitivity Adjustment values 241 | AK8963_ASAX = 0x10 242 | AK8963_ASAY = 0x11 243 | AK8963_ASAZ = 0x12 244 | 245 | # CNTL1 Mode select 246 | # Power down mode 247 | AK8963_MODE_DOWN = 0x00 248 | 249 | # One shot data output 250 | AK8963_MODE_ON = 0x01 251 | 252 | # Magneto Scale Select 253 | AK8963_BIT_14 = 0x00 # 14bit output 254 | AK8963_BIT_16 = 0x01 # 16bit output 255 | 256 | # Continous data output 257 | AK8963_MODE_C8HZ = 0x02 # 8Hz 258 | AK8963_MODE_C100HZ = 0x06 # 100Hz 259 | 260 | ########################################################### 261 | # Others 262 | ########################################################### 263 | 264 | FIRST_DATA_POSITION = ACCEL_XOUT_H 265 | ACCEL_OUT = ACCEL_XOUT_H 266 | GYRO_OUT = GYRO_XOUT_H 267 | TEMP_OUT = TEMP_OUT_H 268 | AK8963_MAGNET_OUT = AK8963_HXL 269 | 270 | # Device ID 271 | DEVICE_ID = 0x71 272 | 273 | # Accelerometer Scale Modifiers 274 | ACCEL_SCALE_MODIFIER_2G = 2.0/32768.0 275 | ACCEL_SCALE_MODIFIER_4G = 4.0/32768.0 276 | ACCEL_SCALE_MODIFIER_8G = 8.0/32768.0 277 | ACCEL_SCALE_MODIFIER_16G = 16.0/32768.0 278 | 279 | ACCEL_SCALE_MODIFIER_2G_DIV = 32768.0/2.0 280 | ACCEL_SCALE_MODIFIER_4G_DIV = 32768.0/4.0 281 | ACCEL_SCALE_MODIFIER_8G_DIV = 32768.0/8.0 282 | ACCEL_SCALE_MODIFIER_16G_DIV = 32768.0/16.0 283 | 284 | # Gyroscope Scale Modifiers 285 | GYRO_SCALE_MODIFIER_250DEG = 250.0/32768.0 286 | GYRO_SCALE_MODIFIER_500DEG = 500.0/32768.0 287 | GYRO_SCALE_MODIFIER_1000DEG = 1000.0/32768.0 288 | GYRO_SCALE_MODIFIER_2000DEG = 2000.0/32768.0 289 | 290 | GYRO_SCALE_MODIFIER_250DEG_DIV = 32768.0/250.0 291 | GYRO_SCALE_MODIFIER_500DEG_DIV = 32768.0/500.0 292 | GYRO_SCALE_MODIFIER_1000DEG_DIV = 32768.0/1000.0 293 | GYRO_SCALE_MODIFIER_2000DEG_DIV = 32768.0/2000.0 294 | 295 | # Magnetometer Scale Modifiers 296 | MAGNOMETER_SCALE_MODIFIER_BIT_14 = 4912.0/8190.0 297 | MAGNOMETER_SCALE_MODIFIER_BIT_16 = 4912.0/32760.0 298 | 299 | MAGNOMETER_SCALE_MODIFIER_BIT_14_DIV = 8190.0/4912.0 300 | MAGNOMETER_SCALE_MODIFIER_BIT_16_DIV = 32760.0/4912.0 301 | 302 | # Gravity 303 | GRAVITY = 9.80665 304 | 305 | # Default I2C Address 306 | MPU9050_ADDRESS_68 = 0x68 307 | MPU9050_ADDRESS_69 = 0x69 308 | AK8963_ADDRESS = 0x0C -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | smbus2==0.3.0 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r") as fh: 4 | long_description = fh.read() 5 | 6 | # Remove Emojis 7 | long_description = long_description.replace(":information_source: ", "") 8 | long_description = long_description.replace(":warning: ", "") 9 | long_description = long_description.replace(":exclamation: ", "") 10 | 11 | setuptools.setup( 12 | name="mpu9250_jmdev", 13 | version="1.0.12", 14 | author="Jeferson Menegazzo", 15 | author_email="jef.menegazzo@outlook.com", 16 | description="MPU-9250 (MPU-6500 + AK8963) I2C Driver in Python for Raspbery PI", 17 | long_description=long_description, 18 | long_description_content_type="text/markdown", 19 | url="https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect", 20 | packages=setuptools.find_packages(), 21 | classifiers=[ 22 | "Programming Language :: Python :: 3", 23 | "License :: OSI Approved :: CC BY-NC-ND 4.0 License", 24 | "Operating System :: OS Independent", 25 | ], 26 | python_requires='>=3.6', 27 | install_requires=[ 28 | "smbus2>=0.3.0", 29 | ] 30 | ) --------------------------------------------------------------------------------