├── .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 |
10 |
11 |
12 |
13 |
14 | 🙌 Use [donations](#Sponsors-and-Donations) to help support your projects! 🙌
15 |
16 |
17 |
18 |
19 |
20 | [](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect)
21 | [](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect)
22 | [](LICENSE.txt)
23 | [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QYV4NEUSVWZCY&source=url)
24 | 
25 | 
26 | 
27 | [](https://doi.org/10.5281/zenodo.3960441)
28 | [](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/issues)
29 | [](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/network/members)
30 | [](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/stargazers)
31 | [](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/watchers)
32 | [](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect/graphs/contributors/)
33 | [](https://github.com/Intelligent-Vehicle-Perception/MPU-9250-Sensors-Data-Collect)
34 | [](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 | [](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 | )
--------------------------------------------------------------------------------