first commit
This commit is contained in:
commit
e6a42e28e9
4355 changed files with 4626605 additions and 0 deletions
|
|
@ -0,0 +1,168 @@
|
|||
## How to add new messages to the SparkFun u-blox GNSS Arduino Library
|
||||
|
||||
Based on [this issue](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/issues/97), here is a summary of how to add new messages to the SparkFun u-blox GNSS Arduino Library with full "auto" support (for callbacks, logging, etc.).
|
||||
|
||||
Looking at the issue, we see that the library is not supporting the UBX-NAV-PVAT (Navigation Position Velocity Attitude Time solution).
|
||||
PVAT is a new message added in version 1.21 of the HPS (High Precision Fusion) firmware and version 33.21 of the F9 Interface Description.
|
||||
This makes us wonder if more new messages have been added which should also be included?
|
||||
|
||||
### Step 1: Check the Interface Description for new keys
|
||||
|
||||
* Download the latest [interface description](https://www.u-blox.com/sites/default/files/F9-HPS-1.21_InterfaceDescription_UBX-21019746.pdf) from the [u-blox website](https://www.u-blox.com/en/product/zed-f9r-module#tab-documentation-resources)
|
||||
* Open the interface description in Adobe Acrobat Reader DC (the free version)
|
||||
* Do a ```File \ Save as Text...```
|
||||
* Save the file in ```Text (Accessible) (*.txt)``` format
|
||||
* Go make a cup of tea - this takes a while
|
||||
* Open the txt file in Notepad++ or another editor which supports Regular Expressions
|
||||
* The keys will have been saved as individual lines in the format: 0xnnnnnnnn space CR LF
|
||||
* So all we need to do is use a regex to delete everything else
|
||||
* Open Search \ Replace
|
||||
* Click the Search Mode - Regular Expression button
|
||||
* In the "Find what :" box enter: ```^(?!.*0x[\dabcdefABCDEF]{8}\s\r\n).*```
|
||||
* Clear the "Replace with :" box
|
||||
* Click "Replace All"
|
||||
* You are left with just the keys - and a bunch of empty lines, some of which contain form feeds (\f)
|
||||
* Delete the empty lines (\r\n) by replacing \r\n with nothing - don't panic, this takes a few seconds
|
||||
* Delete the form feeds by replacing \f with nothing
|
||||
* Finally replace the remaining spaces (\s) with \r\n
|
||||
* Delete any spurious lines left at the start of the file. E.g. ROM and BASE and 0x118B2060. These came from the General information section
|
||||
* The following line (0x10340014) is the first key from the "Configuration Reference" section
|
||||
* Search for that key number and you will find it again half way through the file. This second copy came from "Configuration Defaults"
|
||||
* Delete the duplicate keys from that line onwards
|
||||
* Save the file
|
||||
* Open it in a spreadsheet, e.g. LibreOffice Calc
|
||||
* Select the "A" column and click "Sort Ascending A-Z"
|
||||
* Save the file (as Text CSV)
|
||||
* Use KDiff3 or another diff package to see the new additions
|
||||
|
||||
You can find the keys in the [keys folder](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/tree/main/keys), saved as sorted text files.
|
||||
There are separate files for the P, R and T interfaces, plus a combined list (also sorted in ascending order).
|
||||
|
||||
Comparing HPS 1.21 to HPS 1.20, we can see that the following keys have been added:
|
||||
|
||||
* 0x10340014 CFG-BDS-USE_GEO_PRN
|
||||
* 0x10710005 CFG-I2CINPROT-SPARTN
|
||||
* 0x10730005 CFG-UART1INPROT-SPARTN
|
||||
* 0x10750005 CFG-UART2INPROT-SPARTN
|
||||
* 0x10770005 CFG-USBINPROT-SPARTN
|
||||
* 0x10790005 CFG-SPIINPROT-SPARTN
|
||||
* 0x20050035 CFG-TP-DRSTR_TP1
|
||||
* 0x20910605 CFG-MSGOUT-UBX_RXM_SPARTN_I2C
|
||||
* 0x20910606 CFG-MSGOUT-UBX_RXM_SPARTN_UART1
|
||||
* 0x20910607 CFG-MSGOUT-UBX_RXM_SPARTN_UART2
|
||||
* 0x20910608 CFG-MSGOUT-UBX_RXM_SPARTN_USB
|
||||
* 0x20910609 CFG-MSGOUT-UBX_RXM_SPARTN_SPI
|
||||
* 0x2091062a CFG-MSGOUT-UBX_NAV_PVAT_I2C
|
||||
* 0x2091062b CFG-MSGOUT-UBX_NAV_PVAT_UART1
|
||||
* 0x2091062c CFG-MSGOUT-UBX_NAV_PVAT_UART2
|
||||
* 0x2091062d CFG-MSGOUT-UBX_NAV_PVAT_USB
|
||||
* 0x2091062e CFG-MSGOUT-UBX_NAV_PVAT_SPI
|
||||
* 0x20910634 CFG-MSGOUT-UBX_SEC_SIG_I2C
|
||||
* 0x20910635 CFG-MSGOUT-UBX_SEC_SIG_UART1
|
||||
* 0x20910636 CFG-MSGOUT-UBX_SEC_SIG_UART2
|
||||
* 0x20910637 CFG-MSGOUT-UBX_SEC_SIG_USB
|
||||
* 0x20910638 CFG-MSGOUT-UBX_SEC_SIG_SPI
|
||||
|
||||
Interestingly, we can also see that one key has been deleted:
|
||||
|
||||
* 0x10530006 CFG-UART2-REMAP
|
||||
|
||||
From this we can confirm - as documented by u-blox in the [Release Notes](https://www.u-blox.com/sites/default/files/ZED-F9R-02B_FW1.00HPS1.21_RN_UBX-21035491_1.3.pdf) -
|
||||
that HPS 1.21:
|
||||
|
||||
* adds support for SPARTN (Safe Position Augmentation for Real-Time Navigation) correction messages
|
||||
* enables the use of BeiDou geostationary satellites (previously, this configuration item had a different name)
|
||||
* enables UBX-SEC-SIG message (signal security measures) as output across the different interfaces
|
||||
* enables UBX_NAV_PVAT message (navigation and altitude position) as output across the different interfaces
|
||||
|
||||
There are also two new dynamic models, robotic lawn mower (11) and e-scooter model (12), which we need to add to the library.
|
||||
|
||||
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/805aab18b6656513bfee473487a437754cd3965d) for the changes.
|
||||
|
||||
### Step 2: Update the combined keys file
|
||||
|
||||
Update [u-blox_config_keys_sorted.txt](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/blob/main/keys/u-blox_config_keys_sorted.txt)
|
||||
to include the new keys.
|
||||
|
||||
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/8895764f237ae494dcd0fa1ae942d487d2e1557f) for the changes.
|
||||
|
||||
### Step 3: Update u-blox_config_keys.h
|
||||
|
||||
Update [u-blox_config_keys.h](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/blob/main/src/u-blox_config_keys.h) to include the new keys.
|
||||
Include the descriptions as defined in the Interface Description.
|
||||
|
||||
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/3609da15f90a7a66b41524e77c6dc3dd76cd362c) for the changes.
|
||||
|
||||
### Step 4: Add the new message struct to u-blox_struct.h
|
||||
|
||||
The next step is to add the new struct for UBX-NAV-PVAT to u-blox_struct.h.
|
||||
|
||||
The messages are in ascending class and ID order. So we add UBX-NAV-PVAT (0x01 0x17) after UBX-NAV-HPPOSLLH (0x01 0x14).
|
||||
|
||||
The names and widths of the fields are taken directly from the interface definition.
|
||||
|
||||
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/a4ba440c6240e0974c27f40b976a5ddf0fbdb9b6) for the changes.
|
||||
|
||||
### Step 5: Update SparkFun_u-blox_GNSS_Arduino_Library.h
|
||||
|
||||
Add the new message ID: ```const uint8_t UBX_NAV_PVAT = 0x17;```
|
||||
|
||||
Add the new functions to provide "auto" support for UBX-NAV-PVAT: ```getNAVPVAT```, ```setAutoNAVPVAT```, ..., ```logNAVPVAT```
|
||||
|
||||
Add new helper functions to access the most important fields: ```getVehicleRoll```, ..., ```getMotionHeading```
|
||||
|
||||
Add the pointer to the struct storage: ```UBX_NAV_PVAT_t *packetUBXNAVPVAT = NULL;```
|
||||
|
||||
Add the private init function: ```bool initPacketUBXNAVPVAT();```
|
||||
|
||||
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/423a1e2ccd418dd679257edc6edeec0bd3029052) for the changes.
|
||||
|
||||
### Step 6: Update SparkFun_u-blox_GNSS_Arduino_Library.cpp
|
||||
|
||||
Now we need to update SparkFun_u-blox_GNSS_Arduino_Library.cpp:
|
||||
|
||||
#### Step 6.1: Update end()
|
||||
|
||||
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/35d225e3f1abb316eda3becb7f8e2eb04ff1d17c) for the changes.
|
||||
|
||||
#### Step 6.2: Update checkAutomatic()
|
||||
|
||||
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/b746d8e2742961ede95e2d06d5db3a3a557e571d) for the changes.
|
||||
|
||||
#### Step 6.3: Update getMaxPayloadSize()
|
||||
|
||||
#### Step 6.4: Update processUBXpacket()
|
||||
|
||||
Take time to double-check that you have used the correct data width, signed/unsigned and position for each field.
|
||||
|
||||
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/8eecdd5044f810b0e2b567150ff63a17c219fe8e) for the changes.
|
||||
|
||||
#### Step 6.5: Update checkCallbacks()
|
||||
|
||||
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/b53bffaa3ae12482cfb268f23796963d0b8519c9) for the changes.
|
||||
|
||||
#### Step 6.6: Add the "auto" functions
|
||||
|
||||
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/e394ae003ad38117d150598774d0552059416473) for the changes.
|
||||
|
||||
#### Step 6.7: Add the helper functions (if any)
|
||||
|
||||
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/318e76383e96d6676bbb57294c25e665c0d4a31f) for the changes.
|
||||
|
||||
### Step 7: Add an example
|
||||
|
||||
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/06014dc95f1b9ffae4876fbacfb9390541d7c31d) for the changes.
|
||||
|
||||
### Step 8: Update keywords.txt
|
||||
|
||||
Add the new "auto" and helper functions to keywords.txt.
|
||||
|
||||
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/4f0a0ca3c5e6420be9064b91702947c23104bd1b) for the changes.
|
||||
|
||||
### Step 9: Update Theory.md
|
||||
|
||||
Add the new message to the list of "auto" messages.
|
||||
|
||||
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/57f133259245d8071c73797e4be2ff630c2720ab) for the changes.
|
||||
|
||||
That's all folks!
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
file(GLOB SOURCES src/*.cpp)
|
||||
idf_component_register(
|
||||
SRCS ${SOURCES}
|
||||
INCLUDE_DIRS src
|
||||
REQUIRES arduino
|
||||
)
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# How to Contribute
|
||||
|
||||
Thank you so *much* for offering to help out. We truly appreciate it.
|
||||
|
||||
If you'd like to contribute, start by searching through the [issues](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/issues) and [pull requests](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/pulls) to see whether someone else has raised a similar idea or question.
|
||||
Please check the [closed issues](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/issues?q=is%3Aissue+is%3Aclosed)
|
||||
and [closed pull requests](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/pulls?q=is%3Apr+is%3Aclosed) too - you may find that your issue or feature has already been discussed.
|
||||
|
||||
If you decide to add a feature to this library, please create a PR and follow these best practices:
|
||||
|
||||
* Change as little as possible. Do not submit a PR that changes 100 lines of whitespace. Break up into multiple PRs if necessary.
|
||||
* If you've added a new feature document it with a simple example sketch. This serves both as a test of your PR and as a quick way for users to quickly learn how to use your new feature.
|
||||
* If you add new functions also add them to _keywords.txt_ so that they are properly highlighted in Arduino. [Read more](https://www.arduino.cc/en/Hacking/libraryTutorial).
|
||||
* **Important:** Please submit your PR using the [release_candidate branch](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/tree/release_candidate). That way, we can merge and test your PR quickly without changing the _master_ branch
|
||||
|
||||

|
||||
|
||||
## Style guide
|
||||
|
||||
Please read and follow the [Arduino API style guide](https://www.arduino.cc/en/Reference/APIStyleGuide). Also read and consider the [Arduino style guide](https://www.arduino.cc/en/Reference/StyleGuide).
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
### Subject of the issue
|
||||
Describe your issue here. If you reference a datasheet please specify which one and in which section (ie, the protocol manual, section 5.1.2). Additionally, screenshots are easy to paste into github.
|
||||
|
||||
### Your workbench
|
||||
* What development board or microcontroller are you using?
|
||||
* What version of hardware or breakout board are you using?
|
||||
* How is the breakout board wired to your microcontroller?
|
||||
* How is everything being powered?
|
||||
* Are there any additional details that may help us help you?
|
||||
|
||||
### Steps to reproduce
|
||||
Tell us how to reproduce this issue. Please post stripped down example code demonstrating your issue.
|
||||
|
||||
### Expected behavior
|
||||
Tell us what should happen
|
||||
|
||||
### Actual behavior
|
||||
Tell us what happens instead
|
||||
55
libraries/SparkFun_u-blox_GNSS_Arduino_Library/LICENSE.md
Normal file
55
libraries/SparkFun_u-blox_GNSS_Arduino_Library/LICENSE.md
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
SparkFun License Information
|
||||
============================
|
||||
|
||||
SparkFun uses two different licenses for our files — one for hardware and one for code.
|
||||
|
||||
Hardware
|
||||
---------
|
||||
|
||||
**SparkFun hardware is released under [Creative Commons Share-alike 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/).**
|
||||
|
||||
Note: This is a human-readable summary of (and not a substitute for) the [license](http://creativecommons.org/licenses/by-sa/4.0/legalcode).
|
||||
|
||||
You are free to:
|
||||
|
||||
Share — copy and redistribute the material in any medium or format
|
||||
Adapt — remix, transform, and build upon the material
|
||||
for any purpose, even commercially.
|
||||
The licensor cannot revoke these freedoms as long as you follow the license terms.
|
||||
Under the following terms:
|
||||
|
||||
Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
|
||||
ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
|
||||
No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
|
||||
Notices:
|
||||
|
||||
You do not have to comply with the license for elements of the material in the public domain or where your use is permitted by an applicable exception or limitation.
|
||||
No warranties are given. The license may not give you all of the permissions necessary for your intended use. For example, other rights such as publicity, privacy, or moral rights may limit how you use the material.
|
||||
|
||||
|
||||
Code
|
||||
--------
|
||||
|
||||
**SparkFun code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT).**
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 SparkFun Electronics
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
166
libraries/SparkFun_u-blox_GNSS_Arduino_Library/README.md
Normal file
166
libraries/SparkFun_u-blox_GNSS_Arduino_Library/README.md
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
# SparkFun u-blox Arduino GNSS Library
|
||||
|
||||
<table class="table table-hover table-striped table-bordered">
|
||||
<tr align="center">
|
||||
<td><a href="https://www.sparkfun.com/products/15136"><img src="https://cdn.sparkfun.com//assets/parts/1/3/5/1/4/15136-SparkFun_GPS-RTK2_Board_-_ZED-F9P__Qwiic_-03.jpg"></a></td>
|
||||
<td><a href="https://www.sparkfun.com/products/15005"><img src="https://cdn.sparkfun.com//assets/parts/1/3/3/2/0/15005-SparkFun_GPS-RTK__Qwiic__-_NEO-M8P-2-00.jpg"></a></td>
|
||||
<td><a href="https://www.sparkfun.com/products/15193"><img src="https://cdn.sparkfun.com//assets/parts/1/3/6/1/4/15193-SparkFun_GPS_Breakout_-_U.FL__ZOE-M8__Qwiic_-01.jpg"></a></td>
|
||||
<td><a href="https://www.sparkfun.com/products/15210"><img src="https://cdn.sparkfun.com//assets/parts/1/3/6/4/8/15210-SparkFun_GPS_Breakout_-_Chip_Antenna__SAM-M8Q__Qwiic_-01.jpg"></a></td>
|
||||
<td><a href="https://www.sparkfun.com/products/15733"><img src="https://cdn.sparkfun.com//assets/parts/1/4/3/2/2/15733-SparkFun_GPS_Breakout_-_NEO-M9N__Chip_Antenna__Qwiic_-01.jpg"></a></td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td><a href="https://www.sparkfun.com/products/15136">SparkFun GPS-RTK2 - ZED-F9P (GPS-15136)</a></td>
|
||||
<td><a href="https://www.sparkfun.com/products/15005">SparkFun GPS-RTK - NEO-M8P-2 (GPS-15005)</a></td>
|
||||
<td><a href="https://www.sparkfun.com/products/15193">SparkFun ZOE-M8Q Breakout (GPS-15193)</a></td>
|
||||
<td><a href="https://www.sparkfun.com/products/15210">SparkFun SAM-M8Q Breakout (GPS-15210)</a></td>
|
||||
<td><a href="https://www.sparkfun.com/products/15733">SparkFun NEO-M9N Breakout (GPS-15733)</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
u-blox makes some incredible GNSS receivers covering everything from low-cost, highly configurable modules such as the SAM-M8Q all the way up to the surveyor grade ZED-F9P with precision of the diameter of a dime. This library supports configuration and control of u-blox devices over I<sup>2</sup>C (called DDC by u-blox), Serial and - as of v2.0.8 (thank you @aberridg) - SPI too! The UBX protocol is a much easier and lighterweight interface to a GNSS module. Stop polling messages and parsing NMEA data! Simply ask for the datums you need and receive an automatic callback when they arrive.
|
||||
|
||||
This library can be installed via the Arduino Library manager. Search for **SparkFun u-blox GNSS**.
|
||||
|
||||
## Automatic support for correction services like PointPerfect (u-blox), RTK2go, Emlid Caster and Skylark (Swift Navigation)
|
||||
|
||||
u-blox's PointPerfect GNSS augmentation service uses the secure MQTT protocol to download SPARTN format correction data, providing "3-6 cm accuracy and convergence within seconds". Please see the new [PointPerfect Client example](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/tree/main/examples/ZED-F9P/Example18_PointPerfectClient) for more details.
|
||||
|
||||
v2.2.1 also supports L-band correction services using the new u-blox NEO-D9S correction data receiver. Please see the new [L-band Corrections example](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/tree/main/examples/ZED-F9P/Example19_LBand_Corrections_with_NEO-D9S) for more details.
|
||||
|
||||
Other RTK NTRIP corrections services often require you to send them your location in NMEA GPGGA format. v2.2 of the library makes this easy by providing get functions and automatic callbacks
|
||||
for both GPGGA and GNGGA messages. You can now instruct your module to output GPGGA (e.g.) every 10 seconds and then push it to the correction server directly from the callback. No more polling, no more parsing!
|
||||
|
||||
v2.2 also includes two new functions useful for correction services:
|
||||
|
||||
* ```setMainTalkerID``` : lets you change the NMEA Talker ID (prefix) from "GN" to "GP" - just in case your correction service really does need GPGGA, not GNGGA
|
||||
* ```setHighPrecisionMode``` : adds extra decimal places in the GGA messages, increasing the resolution of latitude, longitude and altitude
|
||||
|
||||
Please see the new [Automatic_NMEA examples](./examples/Automatic_NMEA) for more details.
|
||||
|
||||
We've also added a new [NTRIP Caster Client example](./examples/ZED-F9P/Example17_NTRIPClient_With_GGA_Callback) showing how to use these new features to full effect.
|
||||
|
||||
## AssistNow<sup>TM</sup>
|
||||
|
||||
v2.1 of the library adds support for u-blox AssistNow<sup>TM</sup> Assisted GNSS (A-GNSS) which can dramatically reduce the time-to-first-fix. You can find further details in the [AssistNow Examples folder](./examples/AssistNow).
|
||||
|
||||
## v2 vs. v1
|
||||
|
||||
This library is the new and improved version of the very popular SparkFun u-blox GNSS Arduino Library. v2.0 contains some big changes and improvements:
|
||||
|
||||
* Seamless support for "automatic" message delivery:
|
||||
* In v1.8, you could ask for the NAV PVT (Navigation Position Velocity Time) message to be delivered _automatically_, without polling. v2.0 adds automatic support for [**29 messages**](./Theory.md#auto-messages), covering the full range of: standard and High Precision position, velocity, attitude and time information; relative positioning; event capture with nanosecond time resolution; raw GNSS signal data including carrier phase; Sensor Fusion; and High Navigation Rate data.
|
||||
* Don't see the message you really need? [Adding_New_Messages](./Adding_New_Messages.md) provides details on how to add "auto" support for your favourite message.
|
||||
* Dynamic memory allocation with clearly-defined data storage structs for each message:
|
||||
* There are no static 'global' variables to eat up your RAM. v2.0 automatically allocates memory for the automatic messages when they are enabled. You may find your total RAM use is lower with v2.0 than with v1.8.
|
||||
* Each "auto" message has a clearly-defined [data storage struct](./src/u-blox_structs.h) which follows the u-blox protocol specification precisely.
|
||||
* Callbacks:
|
||||
* No more polling! Simply request the "auto" messages you need and receive an automatic callback when each message arrives.
|
||||
* Please see the [callback examples](./examples/Callbacks) for more details.
|
||||
* Built-in support for data logging:
|
||||
* Want to log RXM SFRBX and RAWX data for Post-Processed Kinematics or Precise Point Positioning? You can absolutely do that! v2.0 provides built-in support for data logging, allowing you to log **any** of the "auto" messages simply and easily.
|
||||
* Incoming "auto" data can be stored in a configurable ring buffer. You can then extract the data from the buffer and write it to (e.g.) SD card using your favorite SD library.
|
||||
* Data is logged in u-blox UBX format which is compact and efficient. You can replay the data using [u-center](https://www.u-blox.com/en/product/u-center).
|
||||
* Please see the [data logging examples](./examples/Data_Logging) for more details.
|
||||
|
||||
## Migrating to v2.0
|
||||
|
||||
Migrating to v2.0 is easy. There are two small changes all users will need to make:
|
||||
|
||||
* The name of the library class has changed from ```SFE_UBLOX_GPS``` to ```SFE_UBLOX_GNSS``` to reflect that the library supports all of the Global Navigation Satellite Systems:
|
||||
* As a minimum, you need to change: ```SFE_UBLOX_GPS myGPS;```
|
||||
* to: ```SFE_UBLOX_GNSS myGPS;```
|
||||
* But we would encourage you to use ```SFE_UBLOX_GNSS myGNSS;```. You will see that all of the library examples now use ```myGNSS``` instead of ```myGPS```.
|
||||
* The name of the library header and C++ files have changed too:
|
||||
* Change: ```#include <SparkFun_Ublox_Arduino_Library.h>```
|
||||
* to: ```#include <SparkFun_u-blox_GNSS_Arduino_Library.h>```
|
||||
|
||||
If you are using the Dead Reckoning Sensor Fusion or High Dynamic Rate messages, you will need to make more small changes to your code. Please see the [dead reckoning examples](./examples/Dead_Reckoning) for more details. There is more detail available in [Theory.md](./Theory.md#migrating-your-code-to-v20) if you need it.
|
||||
|
||||
There is a [new example](./examples/Dead_Reckoning/Example8_getNAVPVAT) showing how to read the UBX-NAV-PVAT (Position, Velocity, Attitude, Time) with a single function call. UBX-NAV-PVAT has full "auto" callback and data-logging support too!
|
||||
|
||||
## Memory Usage
|
||||
|
||||
The u-blox GNSS library has grown considerably over the years and now exceeds the available program memory on platforms like the ATmega328 (Arduino Uno).
|
||||
If you want to reduce the amount of memory used by the library, you can edit the header file (_SparkFun_u-blox_GNSS_Arduino_Library.h_) and uncomment lines 60 and 63:
|
||||
|
||||
```
|
||||
#define SFE_UBLOX_REDUCED_PROG_MEM // Uncommenting this line will delete the minor debug messages to save memory
|
||||
```
|
||||
|
||||
```
|
||||
#define SFE_UBLOX_DISABLE_AUTO_NMEA // Uncommenting this line will disable auto-NMEA support to save memory
|
||||
```
|
||||
|
||||
**Please note:** the debug messages are automatically deleted and auto-NMEA support is automatically disabled on ARDUINO_AVR_UNO platforms. For other platforms, you will need to uncomment those lines manually.
|
||||
|
||||
On Windows, you will normally find _SparkFun_u-blox_GNSS_Arduino_Library.h_ in:
|
||||
- Documents\Arduino\libraries\SparkFun_u-blox_GNSS_Arduino_Library\src
|
||||
|
||||
## SPI Support
|
||||
|
||||
In v2.0.8 we added support for SPI, based on a contribution by @aberridg. Thank you Andrew!
|
||||
|
||||
We have tested the SPI interface on as many platforms and modules as we could pull together. It works perfectly on most but not quite all combinations.
|
||||
For reasons we don't understand yet, the ZED-F9P and Teensy 3.2 don't seem to get along. But Teensy 3.2 and the ZOE-M8Q do play nicely together.
|
||||
If you notice a combination that does not seem to work, please raise an [issue](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/issues) and we will investigate.
|
||||
|
||||
The SPI examples have their [own folder](./examples/SPI).
|
||||
|
||||
Please check the module datasheets for details on what clock speeds and data rates each module supports. The maximum clock speed is typically 5.5MHz and the maximum transfer rate is typically 125kBytes/s.
|
||||
|
||||
## I<sup>2</sup>C Support
|
||||
|
||||
For I<sup>2</sup>C communication, please be sure to remove all additional pull-ups on the I<sup>2</sup>C bus. u-blox modules include internal pull-ups on the I<sup>2</sup>C lines (sometimes called DDC in their manuals). Cut all I<sup>2</sup>C pull-up jumpers and/or remove them from peripheral boards. Otherwise, various data glitches can occur. See issues [38](https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/issues/38) and [40](https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/issues/40) for more information. We recommend running the I<sup>2</sup>C bus at 100kHz.
|
||||
|
||||
## Compatibility
|
||||
|
||||
v2 of the library provides support for generation 8, 9 and 10 u-blox GNSS modules. For generation 6 and 7, please see [this example (deprecated)](https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/tree/master/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7).
|
||||
|
||||
## Contributing
|
||||
|
||||
If you would like to contribute to this library: please do, we truly appreciate it, but please follow [these guidelines](./CONTRIBUTING.md). Thanks!
|
||||
|
||||
## Repository Contents
|
||||
|
||||
* [**/examples**](./examples) - Example sketches for the library (.ino). Run these from the Arduino IDE.
|
||||
* [**/src**](./src) - Source files for the library (.cpp, .h).
|
||||
* [**keywords.txt**](./keywords.txt) - Keywords from this library that will be highlighted in the Arduino IDE.
|
||||
* [**library.properties**](./library.properties) - General library properties for the Arduino package manager.
|
||||
* [**CONTRIBUTING.md**](./CONTRIBUTING.md) - Guidelines on how to contribute to this library.
|
||||
* [**Theory.md**](./Theory.md) - provides detail on how data is processed by the library.
|
||||
* [**/Utils**](./Utils) - contains a Python utility which can check the contents of UBX log files.
|
||||
|
||||
## Documentation
|
||||
|
||||
* [**Installing an Arduino Library Guide**](https://learn.sparkfun.com/tutorials/installing-an-arduino-library) - Basic information on how to install an Arduino library.
|
||||
|
||||
## Theory
|
||||
|
||||
If you would like to learn more about how this library works, including the big changes we made in version 2.0, please see [**Theory.md**](./Theory.md) for full details.
|
||||
|
||||
## Products That Use This Library
|
||||
|
||||
* [GPS-16481](https://www.sparkfun.com/products/16481) - SparkFun GPS-RTK-SMA Breakout - ZED-F9P (Qwiic)
|
||||
* [GPS-15136](https://www.sparkfun.com/products/15136) - SparkFun GPS-RTK2 Board - ZED-F9P (Qwiic)
|
||||
* [GPS-16344](https://www.sparkfun.com/products/16344) - SparkFun GPS-RTK Dead Reckoning Breakout - ZED-F9R (Qwiic)
|
||||
* [GPS-15005](https://www.sparkfun.com/products/15005) - SparkFun GPS-RTK Board - NEO-M8P-2 (Qwiic)
|
||||
* [GPS-15210](https://www.sparkfun.com/products/15210) - SparkFun GPS Breakout - Chip Antenna, SAM-M8Q (Qwiic)
|
||||
* [GPS-15193](https://www.sparkfun.com/products/15193) - SparkFun GPS Breakout - Chip Antenna, ZOE-M8Q (Qwiic)
|
||||
* [GPS-17285](https://www.sparkfun.com/products/17285) - SparkFun GPS Breakout - NEO-M9N, SMA (Qwiic)
|
||||
* [GPS-15733](https://www.sparkfun.com/products/15733) - SparkFun GPS Breakout - NEO-M9N, Chip Antenna (Qwiic)
|
||||
* [GPS-15712](https://www.sparkfun.com/products/15712) - SparkFun GPS Breakout - NEO-M9N, U.FL (Qwiic)
|
||||
* [GPS-16329](https://www.sparkfun.com/products/16329) - SparkFun GPS Dead Reckoning Breakout - NEO-M8U (Qwiic)
|
||||
* [SPX-14980](https://www.sparkfun.com/products/14980) - SparkX GPS-RTK Black
|
||||
* [SPX-15106](https://www.sparkfun.com/products/15106) - SparkX SAM-M8Q
|
||||
|
||||
## License Information
|
||||
|
||||
This product is _**open source**_!
|
||||
|
||||
Various bits of the code have different licenses applied. Anything SparkFun wrote is beerware; if you see me (or any other SparkFun employee) at the local, and you've found our code helpful, please buy us a round!
|
||||
|
||||
Please use, reuse, and modify these files as you see fit. Please maintain attribution to SparkFun Electronics and release anything derivative under the same license.
|
||||
|
||||
Distributed as-is; no warranty is given.
|
||||
|
||||
- Your friends at SparkFun.
|
||||
132
libraries/SparkFun_u-blox_GNSS_Arduino_Library/Theory.md
Normal file
132
libraries/SparkFun_u-blox_GNSS_Arduino_Library/Theory.md
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
## How I<sup>2</sup>C (aka DDC) communication works with a u-blox module
|
||||
|
||||
When the user calls one of the methods the library will poll the u-blox module for new data.
|
||||
|
||||
* Wait for a minimum of 25 ms between polls (configured dynamically when update rate is set)
|
||||
* Write 0xFD to module
|
||||
* Read two bytes (0xFD and 0xFE) for bytes available
|
||||
* Otherwise, read number of bytes and process into NMEA, UBX, or RTCM frame.
|
||||
* If checksum is valid, flag frame as complete.
|
||||
|
||||
This library was originally written to use the I<sup>2</sup>C interface but Serial has been implemented as well.
|
||||
|
||||
## How data is processed by this library
|
||||
|
||||
In Version 1 of this library, we tried to minimize memory usage by being very careful about how much RAM we allocated to UBX packet storage and processing. We used only three buffers or containers to store the incoming data: **packetBuf** (packetBuffer); **packetCfg** (packetConfiguration); and **packetAck** (packetAcknowledge). Incoming packets were stored in **packetBuf** initially and then diverted into **packetAck** or **packetCfg** as necessary. Once data was received and validated, it would be copied out of **packetCfg** and into 'global' variables with names like ```gpsSecond``` or ```latitude```. We also introduced the concept of _Polling vs. Auto-Reporting_ where messages like PVT (Position, Velocity, Time) could be generated and parsed "automatically". This meant that functions like ```getLatitude``` could be non-blocking, returning the most recent data and requesting fresh data when necessary. But it also meant that _polled_ messages could be _overwritten_ (in **packetCfg**) by any _auto-reported_ messages. The library dealt with this successfully, but it was a headache.
|
||||
|
||||
Version 1 had two main drawbacks. As time went on:
|
||||
- the RAM use increased as we had to add new 'global' storage for each new data type
|
||||
- the number of messages which needed "auto" processing through **packetCfg** became complex, requiring significant code changes each time a new "auto" message was added. (We started with NAV-PVT. Then came NAV-HPPOSLLH and NAV-DOP. Things got complicated when HNR-ATT, HNR-INS and HNR-PVT were added to the mix.)
|
||||
|
||||
Version 2 of the library does things differently. Whilst of course trying to keep the library backward-compatible as much as possible, we have taken a fresh approach:
|
||||
- We have added **packetAuto** which is used to temporarily buffer expected auto-reported messages and prevents data from being overwritten in **packetCfg**.
|
||||
- The payload for **packetAuto** is allocated dynamically in RAM and deleted after use.
|
||||
- If insufficient RAM is available, the code falls back to using **packetCfg** to buffer the data instead.
|
||||
- The library no longer uses 'global' (permanently-allocated) storage for the GNSS data. Instead:
|
||||
- Each message type has a **typedef struct** defined which matches the format of the UBX message. (_typedef structs_ are just definitions, they don't occupy memory.) You can find the definitions in [_**u-blox_structs.h**_](./src/u-blox_structs.h).
|
||||
- The struct allows each data field (latitude, longitude, etc.) to be read simply and easily using dot notation. Flags etc. are supported by bit definitions in the struct. The field names are as defined in the u-blox interface description.
|
||||
- Storage for that message is only _allocated_ in RAM if/when required. The allocation is done using _new_ via a pointer to the struct.
|
||||
- _Any_ message can be "auto" if required, but can be polled too.
|
||||
- An optional _callback_ can be associated with the arrival of each message type. A simple scheduler ```checkCallbacks``` triggers the callbacks once I<sup>2</sup>C/Serial data reception is complete.
|
||||
- This means that your code no longer needs to wait for the arrival of a message, you are able to request (e.g.) PVT or HNR data and your callback is called once the data arrives.
|
||||
- The callbacks are not re-entrant.
|
||||
- The callback receives a _copy_ of the data, so data reception and processing can continue while the callback is executing. Data integrity is preserved. You can call ```checkUblox()``` from inside a callback if needed.
|
||||
- Incoming data can be copied to a separate buffer to allow automatic writing to a file on SD card, which will be useful for (e.g.) RAWX logging.
|
||||
- Data is stored in a RingBuffer, the size of which can be set by calling ```setFileBufferSize``` _before_ ```.begin```.
|
||||
- The default buffer size is zero - to save memory.
|
||||
- To simplify SD card writing, data can be copied from the RingBuffer to a user-defined linear buffer first using ```extractFileBufferData```.
|
||||
- Data reception and processing can continue during the SD write.
|
||||
- User-defined code does the actual writing of data from the linear buffer to the SD card. The u-blox GNSS library itself does not perform the writing and so is not tied to any particular SD library.
|
||||
- The logged files can be played back and analyzed with (e.g.) u-center or RTKLIB.
|
||||
|
||||
In terms of RAM, you may find that your total RAM use is lower using v2 compared to v1, but it does of course depend on how many message types are being processed. The downside to this is that it is difficult to know in advance how much RAM is required, since it is only allocated if/when required. If the processor runs out of RAM (i.e. the _new_ fails) then a debug error message is generated.
|
||||
|
||||
## "Auto" messages
|
||||
|
||||
In v2.0, the full list of messages which can be processed and logged automatically is:
|
||||
- UBX-NAV-POSECEF (0x01 0x01): Position solution in ECEF
|
||||
- UBX-NAV-STATUS (0x01 0x03): Receiver navigation status
|
||||
- UBX-NAV-DOP (0x01 0x04): Dilution of precision
|
||||
- UBX-NAV-ATT (0x01 0x05): Attitude solution (**only with ADR or UDR products**)
|
||||
- UBX-NAV-PVT (0x01 0x07): Navigation position velocity time solution
|
||||
- UBX-NAV-ODO (0x01 0x09): Odometer solution
|
||||
- UBX-NAV-VELECEF (0x01 0x11): Velocity solution in ECEF
|
||||
- UBX-NAV-VELNED (0x01 0x12): Velocity solution in NED frame
|
||||
- UBX-NAV-HPPOSECEF (0x01 0x13): High precision position solution in ECEF
|
||||
- UBX-NAV-HPPOSLLH (0x01 0x14): High precision geodetic position solution
|
||||
- UBX-NAV-PVAT (0x01 0x17): Navigation position velocity attitude time solution (**only with ADR or UDR products**)
|
||||
- UBX-NAV-TIMEUTC (0x01 0x21): UTC time solution
|
||||
- UBX-NAV-CLOCK (0x01 0x22): Clock solution
|
||||
- UBX-NAV-SAT (0x01 0x35): Satellite information
|
||||
- UBX-NAV-SVIN (0x01 0x3B): Survey-in data (**only with High Precision GNSS products**)
|
||||
- UBX-NAV-RELPOSNED (0x01 0x3C): Relative positioning information in NED frame (**only with High Precision GNSS products**)
|
||||
- UBX-NAV-AOPSTATUS (0x01 0x60): AssistNow Autonomous status
|
||||
- UBX-NAV-EOE (0x01 0x61): End of epoch
|
||||
- UBX-RXM-SFRBX (0x02 0x13): Broadcast navigation data subframe
|
||||
- UBX-RXM-RAWX (0x02 0x15): Multi-GNSS raw measurement data (**only with ADR or High Precision GNSS or Time Sync products**)
|
||||
- UBX-TIM-TM2 (0x0D 0x03): Time mark data
|
||||
- UBX-ESF-ALG (0x10 0x14): IMU alignment information (**only with ADR or UDR products**)
|
||||
- UBX-ESF-INS (0x10 0x15): Vehicle dynamics information (**only with ADR or UDR products**)
|
||||
- UBX-ESF-MEAS (0x10 0x02): External sensor fusion measurements (**only with ADR or UDR products**)
|
||||
- UBX-ESF-RAW (0x10 0x03): Raw sensor measurements (**only with ADR or UDR products**)
|
||||
- UBX-ESF-STATUS (0x10 0x10): External sensor fusion status (**only with ADR or UDR products**)
|
||||
- UBX-HNR-PVT (0x28 0x00): High rate output of PVT solution (**only with ADR or UDR products**)
|
||||
- UBX-HNR-ATT (0x28 0x01): Attitude solution (**only with ADR or UDR products**)
|
||||
- UBX-HNR-INS (0x28 0x02): Vehicle dynamics information (**only with ADR or UDR products**)
|
||||
|
||||
Please see [Adding_New_Messages](./Adding_New_Messages.md) for details on how to add "auto" support for new messages.
|
||||
|
||||
Notes:
|
||||
- UBX-NAV-POSLLH is not supported as UBX-NAV-PVT contains the same information
|
||||
|
||||
## Migrating your code to v2.0
|
||||
|
||||
Migrating to v2.0 is easy. There are two small changes all users will need to make:
|
||||
|
||||
* The name of the library class has changed from ```SFE_UBLOX_GPS``` to ```SFE_UBLOX_GNSS``` to reflect that the library supports all of the Global Navigation Satellite Systems:
|
||||
* As a minimum, you need to change: ```SFE_UBLOX_GPS myGPS;```
|
||||
* to: ```SFE_UBLOX_GNSS myGPS;```
|
||||
* But we would encourage you to use ```SFE_UBLOX_GNSS myGNSS;```. You will see that all of the library examples now use ```myGNSS``` instead of ```myGPS```.
|
||||
* The name of the library header and C++ files have changed too:
|
||||
* Change: ```#include <SparkFun_Ublox_Arduino_Library.h>```
|
||||
* to: ```#include <SparkFun_u-blox_GNSS_Arduino_Library.h>```
|
||||
|
||||
The biggest change in v2.0 is that data is now stored in a _struct_ which matches the u-blox interface description for that message. For example:
|
||||
- In v1, the NAV PVT (Position Velocity Time) latitude and longitude were stored in 'global' _int32_t_ variables called ```latitude``` and ```longitude```
|
||||
- In v2.0, the data is now stored in <strong>UBX_NAV_PVT_t *packetUBXNAVPVT</strong>
|
||||
- ```myGPS.latitude``` becomes ```myGNSS.packetUBXNAVPVT->data.lat```
|
||||
- ```myGPS.longitude``` becomes ```myGNSS.packetUBXNAVPVT->data.lon```
|
||||
- The helper functions ```myGNSS.getLatitude()``` and ```myGNSS.getLongitude()``` are still available and work in the same way.
|
||||
- In v1, the ESF Sensor Fusion data for the Dead Reckoning modules was stored in 'global' variables ```imuMeas```, ```ubloxSen``` and ```vehAtt```
|
||||
- In v2.0, the data is now stored in:
|
||||
- <strong>UBX_ESF_ALG_t *packetUBXESFALG</strong> contains the IMU alignment information (roll, pitch and yaw)
|
||||
- <strong>UBX_ESF_INS_t *packetUBXESFINS</strong> contains the vehicle dynamics information (acceleration and angular rate)
|
||||
- <strong>UBX_ESF_MEAS_t *packetUBXESFMEAS</strong> contains the sensor fusion measurements
|
||||
- <strong>UBX_ESF_RAW_t *packetUBXESFRAW</strong> contains the raw sensor measurements
|
||||
- <strong>UBX_ESF_STATUS_t *packetUBXESFSTATUS</strong> contains the sensor fusion status
|
||||
- e.g. ```myGPS.imuMeas.fusionMode``` becomes ```myGNSS.packetUBXESFSTATUS->data.fusionMode```
|
||||
- The helper functions ```getSensorFusionMeasurement```, ```getRawSensorMeasurement``` and ```getSensorFusionStatus``` can be used to extract the sensor data for an individual sensor
|
||||
- "auto" data can be marked as stale by calling (e.g.) ```myGNSS.flushESFALG()```
|
||||
- Please see the [**Dead_Reckoning/Example4_vehicleDynamics**](./examples/Dead_Reckoning/Example4_vehicleDynamics/Example4_vehicleDynamics.ino) example for more details
|
||||
- In v1, the HNR (High Navigation Rate) data for the Dead Reckoning modules was stored in 'global' variables ```hnrAtt```, ```hnrVehDyn``` and ```hnrPVT```
|
||||
- In v2.0, e.g.:
|
||||
- ```myGPS.hnrAtt.roll``` becomes ```myGNSS.packetUBXHNRATT->data.roll```
|
||||
- ```myGPS.hnrVehDyn.xAccel``` becomes ```myGNSS.packetUBXHNRINS->data.xAccel```
|
||||
- ```myGPS.hnrPVT.lat``` becomes ```myGNSS.packetUBXHNRPVT->data.lat```
|
||||
- "auto" data can be marked as stale by calling (e.g.) ```myGNSS.flushHNRATT()```
|
||||
- Please see the [**Dead_Reckoning/Example6_getAutoHNRData**](./examples/Dead_Reckoning/Example6_getAutoHNRData/Example6_getAutoHNRData.ino) example for more details
|
||||
|
||||
Other changes include:
|
||||
- In v1, NAV_RELPOSNED relPosN, relPosE and relPosD were returned as (float)m. In v2.0 they are returned via <strong>packetUBXNAVRELPOSNED->data.relPosN</strong> (etc.) as (int32_t)cm.
|
||||
- New helper functions (```getRelPosN```, ```getRelPosE``` and ```getRelPosD```) provide backward-compatibility
|
||||
- Please see the [**ZED-F9P/Example5_RelativePositioningInformation**](./examples/ZED-F9P/Example5_RelativePositioningInformation/Example5_RelativePositioningInformation.ino) example for more details
|
||||
- In v1, NAV_RELPOSNED accN, accE and accD were returned as (float)m. In v2.0 they are returned via <strong>packetUBXNAVRELPOSNED->data.accN</strong> (etc.) as (uint32_t)mm*0.1.
|
||||
- New helper functions (```getRelPosAccN```, ```getRelPosAccE``` and ```getRelPosAccD```) provide backward-compatibility
|
||||
- Please see the [**ZED-F9P/Example5_RelativePositioningInformation**](./examples/ZED-F9P/Example5_RelativePositioningInformation/Example5_RelativePositioningInformation.ino) example for more details
|
||||
- getSurveyStatus now returns data via <strong>UBX_NAV_SVIN_t *packetUBXNAVSVIN</strong>
|
||||
- ```myGPS.svin.active``` becomes ```myGNSS.packetUBXNAVSVIN->data.active```
|
||||
- ```myGPS.svin.valid``` becomes ```myGNSS.packetUBXNAVSVIN->data.valid```
|
||||
- ```myGPS.svin.observationTime``` becomes ```myGNSS.packetUBXNAVSVIN->data.dur``` and is now uint32_t (not uint16_t)
|
||||
- ```myGPS.svin.MeanAccuracy``` becomes ```myGNSS.packetUBXNAVSVIN->data.meanAcc``` and is now uint32_t * 0.1mm (not float * m)
|
||||
- New helper functions (```getSurveyInActive```, ```getSurveyInValid```, ```getSurveyInObservationTime``` and ```getSurveyInMeanAccuracy```) provide backward-compatibility
|
||||
- Please see the [**ZED-F9P/Example3_StartRTCMBase**](./examples/ZED-F9P/Example3_StartRTCMBase/Example3_StartRTCMBase.ino) example for more details
|
||||
|
|
@ -0,0 +1,464 @@
|
|||
# Checks the integrity of u-blox binary files
|
||||
|
||||
# Written by: Paul Clark
|
||||
# Last update: October 17th 2021
|
||||
|
||||
# Reads a UBX file and checks the integrity of both UBX and NMEA data
|
||||
# Will rewind and re-sync if an error is found
|
||||
# Will create a repaired file if desired
|
||||
|
||||
# SparkFun code, firmware, and software is released under the MIT License (http://opensource.org/licenses/MIT)
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2020 SparkFun Electronics
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add byte to checksums sum1 and sum2
|
||||
def csum(byte, sum1, sum2):
|
||||
sum1 = sum1 + byte
|
||||
sum2 = sum2 + sum1
|
||||
sum1 = sum1 & 0xFF
|
||||
sum2 = sum2 & 0xFF
|
||||
return sum1,sum2
|
||||
|
||||
print('UBX Integrity Checker')
|
||||
print()
|
||||
|
||||
filename = ''
|
||||
|
||||
if filename == '':
|
||||
# Check if the bin filename was passed in argv
|
||||
if len(sys.argv) > 1: filename = sys.argv[1]
|
||||
|
||||
# Find first .ubx file in the current directory
|
||||
firstfile = ''
|
||||
for root, dirs, files in os.walk("."):
|
||||
if len(files) > 0:
|
||||
if root == ".": # Comment this line to check sub-directories too
|
||||
for afile in files:
|
||||
if afile[-4:] == '.ubx':
|
||||
if firstfile == '': firstfile = os.path.join(root, afile)
|
||||
|
||||
# Ask user for .bin filename offering firstfile as the default
|
||||
if filename == '': filename = input('Enter the UBX filename (default: ' + firstfile + '): ') # Get the filename
|
||||
if filename == '': filename = firstfile
|
||||
|
||||
# Ask user if the data contains NMEA messages
|
||||
response = input('Could this file contain any NMEA messages? (Y/n): ') # Get the response
|
||||
if (response == '') or (response == 'Y') or (response == 'y'):
|
||||
containsNMEA = True
|
||||
else:
|
||||
containsNMEA = False
|
||||
|
||||
# Ask user if the file should be repaired
|
||||
response = input('Do you want to repair the file? (y/N): ') # Get the response
|
||||
if (response == '') or (response == 'N') or (response == 'n'):
|
||||
repairFile = False
|
||||
else:
|
||||
repairFile = True
|
||||
if (filename[-4] == '.'):
|
||||
repairFilename = filename[:-4] + '.repair' + filename[-4:]
|
||||
else:
|
||||
repairFilename = filename + '.repair'
|
||||
|
||||
print()
|
||||
print('Processing',filename)
|
||||
print()
|
||||
filesize = os.path.getsize(filename) # Record the file size
|
||||
|
||||
# Try to open file for reading
|
||||
try:
|
||||
fi = open(filename,"rb")
|
||||
except:
|
||||
raise Exception('Invalid file!')
|
||||
|
||||
# Try to open repair file for writing
|
||||
if (repairFile):
|
||||
try:
|
||||
fo = open(repairFilename,"wb")
|
||||
except:
|
||||
raise Exception('Could not open repair file!')
|
||||
|
||||
processed = -1 # The number of bytes processed
|
||||
messages = {} # The collected message types
|
||||
keepGoing = True
|
||||
|
||||
# Sync 'state machine'
|
||||
looking_for_B5_dollar = 0 # Looking for either a UBX 0xB5 or an NMEA '$'
|
||||
looking_for_62 = 1 # Looking for a UBX 0x62 header byte
|
||||
looking_for_class = 2 # Looking for UBX class byte
|
||||
looking_for_ID = 3 # Looking for UBX ID byte
|
||||
looking_for_length_LSB = 4 # Looking for UBX length bytes
|
||||
looking_for_length_MSB = 5
|
||||
processing_payload = 6 # Processing the payload. Keep going until length bytes have been processed
|
||||
looking_for_checksum_A = 7 # Looking for UBX checksum bytes
|
||||
looking_for_checksum_B = 8
|
||||
sync_lost = 9 # Go into this state if sync is lost (bad checksum etc.)
|
||||
looking_for_asterix = 10 # Looking for NMEA '*'
|
||||
looking_for_csum1 = 11 # Looking for NMEA checksum bytes
|
||||
looking_for_csum2 = 12
|
||||
looking_for_term1 = 13 # Looking for NMEA terminating bytes (CR and LF)
|
||||
looking_for_term2 = 14
|
||||
|
||||
ubx_nmea_state = sync_lost # Initialize the state machine
|
||||
|
||||
# Storage for UBX messages
|
||||
ubx_length = 0
|
||||
ubx_class = 0
|
||||
ubx_ID = 0
|
||||
ubx_checksum_A = 0
|
||||
ubx_checksum_B = 0
|
||||
ubx_expected_checksum_A = 0
|
||||
ubx_expected_checksum_B = 0
|
||||
longest_UBX = 0 # The length of the longest UBX message
|
||||
longest_UBX_candidate = 0 # Candidate for the length of the longest valid UBX message
|
||||
|
||||
# Storage for NMEA messages
|
||||
nmea_length = 0
|
||||
nmea_char_1 = 0 # e.g. G
|
||||
nmea_char_2 = 0 # e.g. P
|
||||
nmea_char_3 = 0 # e.g. G
|
||||
nmea_char_4 = 0 # e.g. G
|
||||
nmea_char_5 = 0 # e.g. A
|
||||
nmea_csum = 0
|
||||
nmea_csum1 = 0
|
||||
nmea_csum2 = 0
|
||||
nmea_expected_csum1 = 0
|
||||
nmea_expected_csum2 = 0
|
||||
longest_NMEA = 0 # The length of the longest valid NMEA message
|
||||
|
||||
max_nmea_len = 128 # Maximum length for an NMEA message: use this to detect if we have lost sync while receiving an NMEA message
|
||||
sync_lost_at = -1 # Record where we lost sync
|
||||
rewind_to = -1 # Keep a note of where we should rewind to if sync is lost
|
||||
rewind_attempts = 0 # Keep a note of how many rewinds have been attempted
|
||||
max_rewinds = 100 # Abort after this many rewinds
|
||||
rewind_in_progress = False # Flag to indicate if a rewind is in progress
|
||||
resyncs = 0 # Record the number of successful resyncs
|
||||
resync_in_progress = False # Flag to indicate if a resync is in progress
|
||||
message_start_byte = 0 # Record where the latest message started (for resync reporting)
|
||||
|
||||
rewind_repair_file_to = 0 # Keep a note of where to rewind the repair file to if sync is lost
|
||||
repaired_file_bytes = 0 # Keep a note of how many bytes have been written to the repair file
|
||||
|
||||
try:
|
||||
while keepGoing:
|
||||
|
||||
# Read one byte from the file
|
||||
fileBytes = fi.read(1)
|
||||
if (len(fileBytes) == 0):
|
||||
print('ERROR: Read zero bytes. End of file?! Or zero file size?!')
|
||||
raise Exception('End of file?! Or zero file size?!')
|
||||
c = fileBytes[0]
|
||||
|
||||
processed = processed + 1 # Keep a record of how many bytes have been read and processed
|
||||
|
||||
# Write the byte to the repair file if desired
|
||||
if (repairFile):
|
||||
fo.write(fileBytes)
|
||||
repaired_file_bytes = repaired_file_bytes + 1
|
||||
|
||||
# Process data bytes according to ubx_nmea_state
|
||||
# For UBX messages:
|
||||
# Sync Char 1: 0xB5
|
||||
# Sync Char 2: 0x62
|
||||
# Class byte
|
||||
# ID byte
|
||||
# Length: two bytes, little endian
|
||||
# Payload: length bytes
|
||||
# Checksum: two bytes
|
||||
# For NMEA messages:
|
||||
# Starts with a '$'
|
||||
# The next five characters indicate the message type (stored in nmea_char_1 to nmea_char_5)
|
||||
# Message fields are comma-separated
|
||||
# Followed by an '*'
|
||||
# Then a two character checksum (the logical exclusive-OR of all characters between the $ and the * as ASCII hex)
|
||||
# Ends with CR LF
|
||||
# Only allow a new file to be opened when a complete packet has been processed and ubx_nmea_state has returned to "looking_for_B5_dollar"
|
||||
# Or when a data error is detected (sync_lost)
|
||||
|
||||
# RXM_RAWX is class 0x02 ID 0x15
|
||||
# RXM_SFRBF is class 0x02 ID 0x13
|
||||
# TIM_TM2 is class 0x0d ID 0x03
|
||||
# NAV_POSLLH is class 0x01 ID 0x02
|
||||
# NAV_PVT is class 0x01 ID 0x07
|
||||
# NAV-STATUS is class 0x01 ID 0x03
|
||||
|
||||
if (ubx_nmea_state == looking_for_B5_dollar) or (ubx_nmea_state == sync_lost):
|
||||
if (c == 0xB5): # Have we found Sync Char 1 (0xB5) if we were expecting one?
|
||||
if (ubx_nmea_state == sync_lost):
|
||||
print("UBX Sync Char 1 (0xB5) found at byte "+str(processed)+". Checking for Sync Char 2")
|
||||
ubx_nmea_state = looking_for_62 # Now look for Sync Char 2 (0x62)
|
||||
message_start_byte = processed # Record the message start byte for resync reporting
|
||||
elif (c == 0x24) and (containsNMEA == True): # Have we found an NMEA '$' if we were expecting one?
|
||||
if (ubx_nmea_state == sync_lost):
|
||||
print("NMEA $ found at byte "+str(processed)+". Attempting to process the message")
|
||||
ubx_nmea_state = looking_for_asterix # Now keep going until we receive an asterix
|
||||
nmea_length = 0 # Reset nmea_length then use it to check for excessive message length
|
||||
nmea_csum = 0 # Reset the nmea_csum. Update it as each character arrives
|
||||
nmea_char_1 = 0x30 # Reset the first five NMEA chars to something invalid
|
||||
nmea_char_2 = 0x30
|
||||
nmea_char_3 = 0x30
|
||||
nmea_char_4 = 0x30
|
||||
nmea_char_5 = 0x30
|
||||
message_start_byte = processed # Record the message start byte for resync reporting
|
||||
else:
|
||||
#print("Was expecting Sync Char 0xB5 or an NMEA $ but did not receive one!")
|
||||
if (c == 0x24):
|
||||
print("Warning: * found at byte "+str(processed)+"! Are you sure this file does not contain NMEA messages?")
|
||||
sync_lost_at = processed
|
||||
ubx_nmea_state = sync_lost
|
||||
elif (ubx_nmea_state == looking_for_62):
|
||||
if (c == 0x62): # Have we found Sync Char 2 (0x62) when we were expecting one?
|
||||
ubx_expected_checksum_A = 0 # Reset the expected checksum
|
||||
ubx_expected_checksum_B = 0
|
||||
ubx_nmea_state = looking_for_class # Now look for Class byte
|
||||
else:
|
||||
print("Panic!! Was expecting Sync Char 2 (0x62) but did not receive one!")
|
||||
print("Sync lost at byte "+str(processed)+". Attemting to re-sync")
|
||||
sync_lost_at = processed
|
||||
resync_in_progress = True
|
||||
ubx_nmea_state = sync_lost
|
||||
elif (ubx_nmea_state == looking_for_class):
|
||||
ubx_class = c
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + c # Update the expected checksum
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
ubx_nmea_state = looking_for_ID # Now look for ID byte
|
||||
elif (ubx_nmea_state == looking_for_ID):
|
||||
ubx_ID = c
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + c # Update the expected checksum
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
message_type = '0x%02X 0x%02X'%(ubx_class,ubx_ID) # Record the message type
|
||||
ubx_nmea_state = looking_for_length_LSB # Now look for length LSB
|
||||
elif (ubx_nmea_state == looking_for_length_LSB):
|
||||
ubx_length = c # Store the length LSB
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + c # Update the expected checksum
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
ubx_nmea_state = looking_for_length_MSB # Now look for length MSB
|
||||
elif (ubx_nmea_state == looking_for_length_MSB):
|
||||
ubx_length = ubx_length + (c * 256) # Add the length MSB
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + c # Update the expected checksum
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
longest_UBX_candidate = ubx_length + 8 # Update the longest UBX message length candidate. Include the header, class, ID, length and checksum bytes
|
||||
rewind_to = processed # If we lose sync due to dropped bytes then rewind to here
|
||||
ubx_nmea_state = processing_payload # Now look for payload bytes (length: ubx_length)
|
||||
elif (ubx_nmea_state == processing_payload):
|
||||
ubx_length = ubx_length - 1 # Decrement length by one
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + c # Update the expected checksum
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
if (ubx_length == 0):
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A & 0xff # Limit checksums to 8-bits
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B & 0xff
|
||||
ubx_nmea_state = looking_for_checksum_A # If we have received length payload bytes, look for checksum bytes
|
||||
elif (ubx_nmea_state == looking_for_checksum_A):
|
||||
ubx_checksum_A = c
|
||||
ubx_nmea_state = looking_for_checksum_B
|
||||
elif (ubx_nmea_state == looking_for_checksum_B):
|
||||
ubx_checksum_B = c
|
||||
ubx_nmea_state = looking_for_B5_dollar # All bytes received so go back to looking for a new Sync Char 1 unless there is a checksum error
|
||||
if ((ubx_expected_checksum_A != ubx_checksum_A) or (ubx_expected_checksum_B != ubx_checksum_B)):
|
||||
print("Panic!! UBX checksum error!")
|
||||
print("Sync lost at byte "+str(processed)+". Attemting to re-sync.")
|
||||
sync_lost_at = processed
|
||||
resync_in_progress = True
|
||||
ubx_nmea_state = sync_lost
|
||||
else:
|
||||
# Valid UBX message was received. Check if we have seen this message type before
|
||||
if message_type in messages:
|
||||
messages[message_type] += 1 # if we have, increment its count
|
||||
else:
|
||||
messages[message_type] = 1 # if we have not, set its count to 1
|
||||
if (longest_UBX_candidate > longest_UBX): # Update the longest UBX message length
|
||||
longest_UBX = longest_UBX_candidate
|
||||
rewind_in_progress = False # Clear rewind_in_progress
|
||||
rewind_to = -1
|
||||
if (resync_in_progress == True): # Check if we are resyncing
|
||||
resync_in_progress = False # Clear the flag now that a valid message has been received
|
||||
resyncs += 1 # Increment the number of successful resyncs
|
||||
print("Sync successfully re-established at byte "+str(processed)+". The UBX message started at byte "+str(message_start_byte))
|
||||
print()
|
||||
if (repairFile):
|
||||
fo.seek(rewind_repair_file_to) # Rewind the repaired file
|
||||
repaired_file_bytes = rewind_repair_file_to
|
||||
fi.seek(message_start_byte) # Copy the valid message into the repair file
|
||||
repaired_bytes_to_write = processed - message_start_byte
|
||||
fileBytes = fi.read(repaired_bytes_to_write)
|
||||
fo.write(fileBytes)
|
||||
repaired_file_bytes = repaired_file_bytes + repaired_bytes_to_write
|
||||
else:
|
||||
if (repairFile):
|
||||
rewind_repair_file_to = repaired_file_bytes # Rewind repair file to here if sync is lost
|
||||
|
||||
# NMEA messages
|
||||
elif (ubx_nmea_state == looking_for_asterix):
|
||||
nmea_length = nmea_length + 1 # Increase the message length count
|
||||
if (nmea_length > max_nmea_len): # If the length is greater than max_nmea_len, something bad must have happened (sync_lost)
|
||||
print("Panic!! Excessive NMEA message length!")
|
||||
print("Sync lost at byte "+str(processed)+". Attemting to re-sync")
|
||||
sync_lost_at = processed
|
||||
resync_in_progress = True
|
||||
ubx_nmea_state = sync_lost
|
||||
continue
|
||||
# If this is one of the first five characters, store it
|
||||
if (nmea_length <= 5):
|
||||
if (nmea_length == 1):
|
||||
nmea_char_1 = c
|
||||
rewind_to = processed # If we lose sync due to dropped bytes then rewind to here
|
||||
elif (nmea_length == 2):
|
||||
nmea_char_2 = c
|
||||
elif (nmea_length == 3):
|
||||
nmea_char_3 = c
|
||||
elif (nmea_length == 4):
|
||||
nmea_char_4 = c
|
||||
else: # ubx_length == 5
|
||||
nmea_char_5 = c
|
||||
message_type = chr(nmea_char_1) + chr(nmea_char_2) + chr(nmea_char_3) + chr(nmea_char_4) + chr(nmea_char_5) # Record the message type
|
||||
if (message_type == "PUBX,"): # Remove the comma from PUBX
|
||||
message_type = "PUBX"
|
||||
# Now check if this is an '*'
|
||||
if (c == 0x2A):
|
||||
# Asterix received
|
||||
# Don't exOR it into the checksum
|
||||
# Instead calculate what the expected checksum should be (nmea_csum in ASCII hex)
|
||||
nmea_expected_csum1 = ((nmea_csum & 0xf0) >> 4) + 0x30 # Convert MS nibble to ASCII hex
|
||||
if (nmea_expected_csum1 >= 0x3A): # : follows 9 so add 7 to convert to A-F
|
||||
nmea_expected_csum1 += 7
|
||||
nmea_expected_csum2 = (nmea_csum & 0x0f) + 0x30 # Convert LS nibble to ASCII hex
|
||||
if (nmea_expected_csum2 >= 0x3A): # : follows 9 so add 7 to convert to A-F
|
||||
nmea_expected_csum2 += 7
|
||||
# Next, look for the first csum character
|
||||
ubx_nmea_state = looking_for_csum1
|
||||
continue # Don't include the * in the checksum
|
||||
# Now update the checksum
|
||||
# The checksum is the exclusive-OR of all characters between the $ and the *
|
||||
nmea_csum = nmea_csum ^ c
|
||||
elif (ubx_nmea_state == looking_for_csum1):
|
||||
# Store the first NMEA checksum character
|
||||
nmea_csum1 = c
|
||||
ubx_nmea_state = looking_for_csum2
|
||||
elif (ubx_nmea_state == looking_for_csum2):
|
||||
# Store the second NMEA checksum character
|
||||
nmea_csum2 = c
|
||||
# Now check if the checksum is correct
|
||||
if ((nmea_csum1 != nmea_expected_csum1) or (nmea_csum2 != nmea_expected_csum2)):
|
||||
# The checksum does not match so sync_lost
|
||||
print("Panic!! NMEA checksum error!")
|
||||
print("Sync lost at byte "+str(processed)+". Attemting to re-sync")
|
||||
sync_lost_at = processed
|
||||
resync_in_progress = True
|
||||
ubx_nmea_state = sync_lost
|
||||
else:
|
||||
# Checksum was valid so wait for the terminators
|
||||
ubx_nmea_state = looking_for_term1
|
||||
elif (ubx_nmea_state == looking_for_term1):
|
||||
# Check if this is CR
|
||||
if (c != 0x0D):
|
||||
print("Panic!! NMEA CR not found!")
|
||||
print("Sync lost at byte "+str(processed)+". Attemting to re-sync")
|
||||
sync_lost_at = processed
|
||||
resync_in_progress = True
|
||||
ubx_nmea_state = sync_lost
|
||||
else:
|
||||
ubx_nmea_state = looking_for_term2
|
||||
elif (ubx_nmea_state == looking_for_term2):
|
||||
# Check if this is LF
|
||||
if (c != 0x0A):
|
||||
print("Panic!! NMEA LF not found!")
|
||||
print("Sync lost at byte "+str(processed)+". Attemting to re-sync")
|
||||
sync_lost_at = processed
|
||||
resync_in_progress = True
|
||||
ubx_nmea_state = sync_lost
|
||||
else:
|
||||
# Valid NMEA message was received. Check if we have seen this message type before
|
||||
if message_type in messages:
|
||||
messages[message_type] += 1 # if we have, increment its count
|
||||
else:
|
||||
messages[message_type] = 1 # if we have not, set its count to 1
|
||||
if (nmea_length > longest_NMEA): # Update the longest NMEA message length
|
||||
longest_NMEA = nmea_length
|
||||
# LF was received so go back to looking for B5 or a $
|
||||
ubx_nmea_state = looking_for_B5_dollar
|
||||
rewind_in_progress = False # Clear rewind_in_progress
|
||||
rewind_to = -1
|
||||
if (resync_in_progress == True): # Check if we are resyncing
|
||||
resync_in_progress = False # Clear the flag now that a valid message has been received
|
||||
resyncs += 1 # Increment the number of successful resyncs
|
||||
print("Sync successfully re-established at byte "+str(processed)+". The NMEA message started at byte "+str(message_start_byte))
|
||||
print()
|
||||
if (repairFile):
|
||||
fo.seek(rewind_repair_file_to) # Rewind the repaired file
|
||||
repaired_file_bytes = rewind_repair_file_to
|
||||
fi.seek(message_start_byte) # Copy the valid message into the repair file
|
||||
repaired_bytes_to_write = processed - message_start_byte
|
||||
fileBytes = fi.read(repaired_bytes_to_write)
|
||||
fo.write(fileBytes)
|
||||
repaired_file_bytes = repaired_file_bytes + repaired_bytes_to_write
|
||||
else:
|
||||
if (repairFile):
|
||||
rewind_repair_file_to = repaired_file_bytes # Rewind repair file to here if sync is lost
|
||||
|
||||
# Check if the end of the file has been reached
|
||||
if (processed >= filesize - 1): keepGoing = False
|
||||
|
||||
# Check if we should attempt to rewind
|
||||
# Don't rewind if we have not yet seen a valid message
|
||||
# Don't rewind if a rewind is already in progress
|
||||
if (ubx_nmea_state == sync_lost) and (len(messages) > 0) and (rewind_in_progress == False) and (rewind_to >= 0):
|
||||
rewind_attempts += 1 # Increment the number of rewind attempts
|
||||
if (rewind_attempts > max_rewinds): # Only rewind up to max_rewind times
|
||||
print("Panic! Maximum rewind attempts reached! Aborting...")
|
||||
keepGoing = False
|
||||
else:
|
||||
print("Sync has been lost. Currently processing byte "+str(processed)+". Rewinding to byte "+str(rewind_to))
|
||||
fi.seek(rewind_to) # Rewind the file
|
||||
processed = rewind_to - 1 # Rewind processed too! (-1 is needed as processed is incremented at the start of the loop)
|
||||
rewind_in_progress = True # Flag that a rewind is in progress
|
||||
|
||||
|
||||
finally:
|
||||
fi.close() # Close the file
|
||||
|
||||
if (repairFile):
|
||||
fo.close()
|
||||
|
||||
# Print the file statistics
|
||||
print()
|
||||
processed += 1
|
||||
print('Processed',processed,'bytes')
|
||||
print('File size was',filesize)
|
||||
if (processed != filesize):
|
||||
print('FILE SIZE MISMATCH!!')
|
||||
print('Longest valid UBX message was %i bytes'%longest_UBX)
|
||||
if (containsNMEA == True):
|
||||
print('Longest valid NMEA message was %i characters'%longest_NMEA)
|
||||
if len(messages) > 0:
|
||||
print('Message types and totals were:')
|
||||
for key in messages.keys():
|
||||
print('Message type:',key,' Total:',messages[key])
|
||||
if (resyncs > 0):
|
||||
print('Number of successful resyncs:',resyncs)
|
||||
print()
|
||||
if (repairFile):
|
||||
print('Repaired data written to:', repairFilename)
|
||||
print()
|
||||
print('Bye!')
|
||||
|
|
@ -0,0 +1,515 @@
|
|||
# Aligns the rcvTow in RAWX messages in u-blox UBX binary files to the nearest decimalPlaces seconds
|
||||
|
||||
# Written by: Paul Clark
|
||||
# Last update: August 17th 2022
|
||||
|
||||
# SparkFun code, firmware, and software is released under the MIT License (http://opensource.org/licenses/MIT)
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2022 SparkFun Electronics
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import struct
|
||||
|
||||
# Add byte to checksums sum1 and sum2
|
||||
def csum(byte, sum1, sum2):
|
||||
sum1 = sum1 + byte
|
||||
sum2 = sum2 + sum1
|
||||
sum1 = sum1 & 0xFF
|
||||
sum2 = sum2 & 0xFF
|
||||
return sum1,sum2
|
||||
|
||||
print('UBX RAWX Aligner')
|
||||
print()
|
||||
|
||||
filename = ''
|
||||
|
||||
if filename == '':
|
||||
# Check if the bin filename was passed in argv
|
||||
if len(sys.argv) > 1: filename = sys.argv[1]
|
||||
|
||||
# Find first .ubx file in the current directory
|
||||
firstfile = ''
|
||||
for root, dirs, files in os.walk("."):
|
||||
if len(files) > 0:
|
||||
if root == ".": # Comment this line to check sub-directories too
|
||||
for afile in files:
|
||||
if afile[-4:] == '.ubx':
|
||||
if firstfile == '': firstfile = os.path.join(root, afile)
|
||||
|
||||
# Ask user for .bin filename offering firstfile as the default
|
||||
if filename == '': filename = input('Enter the UBX filename (default: ' + firstfile + '): ') # Get the filename
|
||||
if filename == '': filename = firstfile
|
||||
|
||||
# Ask user if the data contains NMEA messages
|
||||
response = input('Could this file contain any NMEA messages? (Y/n): ') # Get the response
|
||||
if (response == '') or (response == 'Y') or (response == 'y'):
|
||||
containsNMEA = True
|
||||
else:
|
||||
containsNMEA = False
|
||||
|
||||
repairFile = True
|
||||
if (filename[-4] == '.'):
|
||||
repairFilename = filename[:-4] + '.aligned' + filename[-4:]
|
||||
else:
|
||||
repairFilename = filename + '.aligned'
|
||||
|
||||
decimalPlaces = 0 # Default to whole seconds
|
||||
if len(sys.argv) > 2: decimalPlaces = sys.argv[2]
|
||||
|
||||
print()
|
||||
print('Processing',filename)
|
||||
print()
|
||||
filesize = os.path.getsize(filename) # Record the file size
|
||||
|
||||
# Try to open file for reading
|
||||
try:
|
||||
fi = open(filename,"rb")
|
||||
except:
|
||||
raise Exception('Invalid file!')
|
||||
|
||||
# Try to open repair file for write and read
|
||||
if (repairFile):
|
||||
try:
|
||||
fo = open(repairFilename,"w+b")
|
||||
except:
|
||||
raise Exception('Could not open aligned file!')
|
||||
|
||||
processed = -1 # The number of bytes processed
|
||||
messages = {} # The collected message types
|
||||
keepGoing = True
|
||||
|
||||
# Sync 'state machine'
|
||||
looking_for_B5_dollar = 0 # Looking for either a UBX 0xB5 or an NMEA '$'
|
||||
looking_for_62 = 1 # Looking for a UBX 0x62 header byte
|
||||
looking_for_class = 2 # Looking for UBX class byte
|
||||
looking_for_ID = 3 # Looking for UBX ID byte
|
||||
looking_for_length_LSB = 4 # Looking for UBX length bytes
|
||||
looking_for_length_MSB = 5
|
||||
processing_payload = 6 # Processing the payload. Keep going until length bytes have been processed
|
||||
looking_for_checksum_A = 7 # Looking for UBX checksum bytes
|
||||
looking_for_checksum_B = 8
|
||||
sync_lost = 9 # Go into this state if sync is lost (bad checksum etc.)
|
||||
looking_for_asterix = 10 # Looking for NMEA '*'
|
||||
looking_for_csum1 = 11 # Looking for NMEA checksum bytes
|
||||
looking_for_csum2 = 12
|
||||
looking_for_term1 = 13 # Looking for NMEA terminating bytes (CR and LF)
|
||||
looking_for_term2 = 14
|
||||
|
||||
ubx_nmea_state = sync_lost # Initialize the state machine
|
||||
|
||||
# Storage for UBX messages
|
||||
ubx_length = 0
|
||||
ubx_length_LSB = 0
|
||||
ubx_length_MSB = 0
|
||||
ubx_class = 0
|
||||
ubx_ID = 0
|
||||
ubx_checksum_A = 0
|
||||
ubx_checksum_B = 0
|
||||
ubx_expected_checksum_A = 0
|
||||
ubx_expected_checksum_B = 0
|
||||
longest_UBX = 0 # The length of the longest UBX message
|
||||
longest_UBX_candidate = 0 # Candidate for the length of the longest valid UBX message
|
||||
|
||||
# Storage for NMEA messages
|
||||
nmea_length = 0
|
||||
nmea_char_1 = 0 # e.g. G
|
||||
nmea_char_2 = 0 # e.g. P
|
||||
nmea_char_3 = 0 # e.g. G
|
||||
nmea_char_4 = 0 # e.g. G
|
||||
nmea_char_5 = 0 # e.g. A
|
||||
nmea_csum = 0
|
||||
nmea_csum1 = 0
|
||||
nmea_csum2 = 0
|
||||
nmea_expected_csum1 = 0
|
||||
nmea_expected_csum2 = 0
|
||||
longest_NMEA = 0 # The length of the longest valid NMEA message
|
||||
|
||||
max_nmea_len = 128 # Maximum length for an NMEA message: use this to detect if we have lost sync while receiving an NMEA message
|
||||
sync_lost_at = -1 # Record where we lost sync
|
||||
rewind_to = -1 # Keep a note of where we should rewind to if sync is lost
|
||||
rewind_attempts = 0 # Keep a note of how many rewinds have been attempted
|
||||
max_rewinds = 100 # Abort after this many rewinds
|
||||
rewind_in_progress = False # Flag to indicate if a rewind is in progress
|
||||
resyncs = 0 # Record the number of successful resyncs
|
||||
resync_in_progress = False # Flag to indicate if a resync is in progress
|
||||
message_start_byte = 0 # Record where the latest message started (for resync reporting)
|
||||
|
||||
rewind_repair_file_to = 0 # Keep a note of where to rewind the repair file to if sync is lost
|
||||
repaired_file_bytes = 0 # Keep a note of how many bytes have been written to the repair file
|
||||
|
||||
repair_file_rawx_payload_start = 0 # Keep a note of where the RAWX payload starts (i.e. where the rcvTow R8 starts)
|
||||
largest_rawx_alignment = 0.0 # Keep note of the largest alignment change
|
||||
|
||||
try:
|
||||
while keepGoing:
|
||||
|
||||
# Read one byte from the file
|
||||
fileBytes = fi.read(1)
|
||||
if (len(fileBytes) == 0):
|
||||
print('ERROR: Read zero bytes. End of file?! Or zero file size?!')
|
||||
raise Exception('End of file?! Or zero file size?!')
|
||||
c = fileBytes[0]
|
||||
|
||||
processed = processed + 1 # Keep a record of how many bytes have been read and processed
|
||||
|
||||
# Write the byte to the repair file if desired
|
||||
if (repairFile):
|
||||
fo.write(fileBytes)
|
||||
repaired_file_bytes = repaired_file_bytes + 1
|
||||
|
||||
# Process data bytes according to ubx_nmea_state
|
||||
# For UBX messages:
|
||||
# Sync Char 1: 0xB5
|
||||
# Sync Char 2: 0x62
|
||||
# Class byte
|
||||
# ID byte
|
||||
# Length: two bytes, little endian
|
||||
# Payload: length bytes
|
||||
# Checksum: two bytes
|
||||
# For NMEA messages:
|
||||
# Starts with a '$'
|
||||
# The next five characters indicate the message type (stored in nmea_char_1 to nmea_char_5)
|
||||
# Message fields are comma-separated
|
||||
# Followed by an '*'
|
||||
# Then a two character checksum (the logical exclusive-OR of all characters between the $ and the * as ASCII hex)
|
||||
# Ends with CR LF
|
||||
# Only allow a new file to be opened when a complete packet has been processed and ubx_nmea_state has returned to "looking_for_B5_dollar"
|
||||
# Or when a data error is detected (sync_lost)
|
||||
|
||||
# RXM_RAWX is class 0x02 ID 0x15
|
||||
# RXM_SFRBF is class 0x02 ID 0x13
|
||||
# TIM_TM2 is class 0x0d ID 0x03
|
||||
# NAV_POSLLH is class 0x01 ID 0x02
|
||||
# NAV_PVT is class 0x01 ID 0x07
|
||||
# NAV-STATUS is class 0x01 ID 0x03
|
||||
|
||||
if (ubx_nmea_state == looking_for_B5_dollar) or (ubx_nmea_state == sync_lost):
|
||||
if (c == 0xB5): # Have we found Sync Char 1 (0xB5) if we were expecting one?
|
||||
if (ubx_nmea_state == sync_lost):
|
||||
print("UBX Sync Char 1 (0xB5) found at byte "+str(processed)+". Checking for Sync Char 2")
|
||||
ubx_nmea_state = looking_for_62 # Now look for Sync Char 2 (0x62)
|
||||
message_start_byte = processed # Record the message start byte for resync reporting
|
||||
elif (c == 0x24) and (containsNMEA == True): # Have we found an NMEA '$' if we were expecting one?
|
||||
if (ubx_nmea_state == sync_lost):
|
||||
print("NMEA $ found at byte "+str(processed)+". Attempting to process the message")
|
||||
ubx_nmea_state = looking_for_asterix # Now keep going until we receive an asterix
|
||||
nmea_length = 0 # Reset nmea_length then use it to check for excessive message length
|
||||
nmea_csum = 0 # Reset the nmea_csum. Update it as each character arrives
|
||||
nmea_char_1 = 0x30 # Reset the first five NMEA chars to something invalid
|
||||
nmea_char_2 = 0x30
|
||||
nmea_char_3 = 0x30
|
||||
nmea_char_4 = 0x30
|
||||
nmea_char_5 = 0x30
|
||||
message_start_byte = processed # Record the message start byte for resync reporting
|
||||
else:
|
||||
#print("Was expecting Sync Char 0xB5 or an NMEA $ but did not receive one!")
|
||||
if (c == 0x24):
|
||||
print("Warning: * found at byte "+str(processed)+"! Are you sure this file does not contain NMEA messages?")
|
||||
sync_lost_at = processed
|
||||
ubx_nmea_state = sync_lost
|
||||
elif (ubx_nmea_state == looking_for_62):
|
||||
if (c == 0x62): # Have we found Sync Char 2 (0x62) when we were expecting one?
|
||||
ubx_expected_checksum_A = 0 # Reset the expected checksum
|
||||
ubx_expected_checksum_B = 0
|
||||
ubx_nmea_state = looking_for_class # Now look for Class byte
|
||||
else:
|
||||
print("Panic!! Was expecting Sync Char 2 (0x62) but did not receive one!")
|
||||
print("Sync lost at byte "+str(processed)+". Attemting to re-sync")
|
||||
sync_lost_at = processed
|
||||
resync_in_progress = True
|
||||
ubx_nmea_state = sync_lost
|
||||
elif (ubx_nmea_state == looking_for_class):
|
||||
ubx_class = c
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + c # Update the expected checksum
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
ubx_nmea_state = looking_for_ID # Now look for ID byte
|
||||
elif (ubx_nmea_state == looking_for_ID):
|
||||
ubx_ID = c
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + c # Update the expected checksum
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
message_type = '0x%02X 0x%02X'%(ubx_class,ubx_ID) # Record the message type
|
||||
ubx_nmea_state = looking_for_length_LSB # Now look for length LSB
|
||||
elif (ubx_nmea_state == looking_for_length_LSB):
|
||||
ubx_length = c # Store the length LSB
|
||||
ubx_length_LSB = c
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + c # Update the expected checksum
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
ubx_nmea_state = looking_for_length_MSB # Now look for length MSB
|
||||
elif (ubx_nmea_state == looking_for_length_MSB):
|
||||
ubx_length = ubx_length + (c * 256) # Add the length MSB
|
||||
ubx_length_MSB = c
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + c # Update the expected checksum
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
longest_UBX_candidate = ubx_length + 8 # Update the longest UBX message length candidate. Include the header, class, ID, length and checksum bytes
|
||||
rewind_to = processed # If we lose sync due to dropped bytes then rewind to here
|
||||
ubx_nmea_state = processing_payload # Now look for payload bytes (length: ubx_length)
|
||||
|
||||
if (message_type == '0x02 0x15'): # Is this RAWX? If so, record the start of the payload
|
||||
repair_file_rawx_payload_start = repaired_file_bytes
|
||||
|
||||
elif (ubx_nmea_state == processing_payload):
|
||||
ubx_length = ubx_length - 1 # Decrement length by one
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + c # Update the expected checksum
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
if (ubx_length == 0):
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A & 0xff # Limit checksums to 8-bits
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B & 0xff
|
||||
ubx_nmea_state = looking_for_checksum_A # If we have received length payload bytes, look for checksum bytes
|
||||
elif (ubx_nmea_state == looking_for_checksum_A):
|
||||
ubx_checksum_A = c
|
||||
ubx_nmea_state = looking_for_checksum_B
|
||||
elif (ubx_nmea_state == looking_for_checksum_B):
|
||||
ubx_checksum_B = c
|
||||
ubx_nmea_state = looking_for_B5_dollar # All bytes received so go back to looking for a new Sync Char 1 unless there is a checksum error
|
||||
if ((ubx_expected_checksum_A != ubx_checksum_A) or (ubx_expected_checksum_B != ubx_checksum_B)):
|
||||
print("Panic!! UBX checksum error!")
|
||||
print("Sync lost at byte "+str(processed)+". Attemting to re-sync.")
|
||||
sync_lost_at = processed
|
||||
resync_in_progress = True
|
||||
ubx_nmea_state = sync_lost
|
||||
else:
|
||||
# Valid UBX message was received. Check if we have seen this message type before
|
||||
if message_type in messages:
|
||||
messages[message_type] += 1 # if we have, increment its count
|
||||
else:
|
||||
messages[message_type] = 1 # if we have not, set its count to 1
|
||||
if (longest_UBX_candidate > longest_UBX): # Update the longest UBX message length
|
||||
longest_UBX = longest_UBX_candidate
|
||||
rewind_in_progress = False # Clear rewind_in_progress
|
||||
rewind_to = -1
|
||||
if (resync_in_progress == True): # Check if we are resyncing
|
||||
resync_in_progress = False # Clear the flag now that a valid message has been received
|
||||
resyncs += 1 # Increment the number of successful resyncs
|
||||
print("Sync successfully re-established at byte "+str(processed)+". The UBX message started at byte "+str(message_start_byte))
|
||||
print()
|
||||
if (repairFile):
|
||||
fo.seek(rewind_repair_file_to) # Rewind the repaired file
|
||||
repaired_file_bytes = rewind_repair_file_to
|
||||
fi.seek(message_start_byte) # Copy the valid message into the repair file
|
||||
repaired_bytes_to_write = processed - message_start_byte
|
||||
fileBytes = fi.read(repaired_bytes_to_write)
|
||||
fo.write(fileBytes)
|
||||
repaired_file_bytes = repaired_file_bytes + repaired_bytes_to_write
|
||||
|
||||
# Note: alignment is skipped if resyncing is in progress
|
||||
# You may need to run the code twice to align any skipped alignments
|
||||
|
||||
else:
|
||||
if (repairFile):
|
||||
rewind_repair_file_to = repaired_file_bytes # Rewind repair file to here if sync is lost
|
||||
|
||||
if (message_type == '0x02 0x15'): # Is this RAWX? If so, do the alignment
|
||||
|
||||
ubx_expected_checksum_A = 0 # Reuse the expected checksum
|
||||
ubx_expected_checksum_B = 0
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + ubx_class
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + ubx_ID
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + ubx_length_LSB
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + ubx_length_MSB
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
|
||||
fo.seek(repair_file_rawx_payload_start) # Rewind the repair file
|
||||
|
||||
fileBytes = fo.read(8) # Read the rcvTow R8
|
||||
rcvTow = struct.unpack('<d', fileBytes)[0] # Unpack the R8 (Little-endian)
|
||||
rcvTowRounded = round(rcvTow, decimalPlaces) # Round to decimalPlaces
|
||||
if (abs(rcvTow - rcvTowRounded) > largest_rawx_alignment):
|
||||
largest_rawx_alignment = abs(rcvTow - rcvTowRounded) # Record the largest alignment change
|
||||
fileBytes = struct.pack('<d', rcvTowRounded)
|
||||
fo.seek(repair_file_rawx_payload_start) # Rewind the repair file
|
||||
fo.write(fileBytes) # Write the rounded TOW to the repair file
|
||||
for i in range(8): # Update the checksum
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + fileBytes[i]
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
|
||||
bytesToRead = (ubx_length_MSB * 256) + ubx_length_LSB - 8
|
||||
fileBytes = fo.read(bytesToRead)
|
||||
for i in range(bytesToRead): # Update the checksum
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A + fileBytes[i]
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
|
||||
ubx_expected_checksum_A = ubx_expected_checksum_A & 0xff # Limit checksums to 8-bits
|
||||
ubx_expected_checksum_B = ubx_expected_checksum_B & 0xff
|
||||
fileBytes = struct.pack('BB', ubx_expected_checksum_A, ubx_expected_checksum_B)
|
||||
fo.write(fileBytes) # Write the updated checksum
|
||||
|
||||
# NMEA messages
|
||||
elif (ubx_nmea_state == looking_for_asterix):
|
||||
nmea_length = nmea_length + 1 # Increase the message length count
|
||||
if (nmea_length > max_nmea_len): # If the length is greater than max_nmea_len, something bad must have happened (sync_lost)
|
||||
print("Panic!! Excessive NMEA message length!")
|
||||
print("Sync lost at byte "+str(processed)+". Attemting to re-sync")
|
||||
sync_lost_at = processed
|
||||
resync_in_progress = True
|
||||
ubx_nmea_state = sync_lost
|
||||
continue
|
||||
# If this is one of the first five characters, store it
|
||||
if (nmea_length <= 5):
|
||||
if (nmea_length == 1):
|
||||
nmea_char_1 = c
|
||||
rewind_to = processed # If we lose sync due to dropped bytes then rewind to here
|
||||
elif (nmea_length == 2):
|
||||
nmea_char_2 = c
|
||||
elif (nmea_length == 3):
|
||||
nmea_char_3 = c
|
||||
elif (nmea_length == 4):
|
||||
nmea_char_4 = c
|
||||
else: # ubx_length == 5
|
||||
nmea_char_5 = c
|
||||
message_type = chr(nmea_char_1) + chr(nmea_char_2) + chr(nmea_char_3) + chr(nmea_char_4) + chr(nmea_char_5) # Record the message type
|
||||
if (message_type == "PUBX,"): # Remove the comma from PUBX
|
||||
message_type = "PUBX"
|
||||
# Now check if this is an '*'
|
||||
if (c == 0x2A):
|
||||
# Asterix received
|
||||
# Don't exOR it into the checksum
|
||||
# Instead calculate what the expected checksum should be (nmea_csum in ASCII hex)
|
||||
nmea_expected_csum1 = ((nmea_csum & 0xf0) >> 4) + 0x30 # Convert MS nibble to ASCII hex
|
||||
if (nmea_expected_csum1 >= 0x3A): # : follows 9 so add 7 to convert to A-F
|
||||
nmea_expected_csum1 += 7
|
||||
nmea_expected_csum2 = (nmea_csum & 0x0f) + 0x30 # Convert LS nibble to ASCII hex
|
||||
if (nmea_expected_csum2 >= 0x3A): # : follows 9 so add 7 to convert to A-F
|
||||
nmea_expected_csum2 += 7
|
||||
# Next, look for the first csum character
|
||||
ubx_nmea_state = looking_for_csum1
|
||||
continue # Don't include the * in the checksum
|
||||
# Now update the checksum
|
||||
# The checksum is the exclusive-OR of all characters between the $ and the *
|
||||
nmea_csum = nmea_csum ^ c
|
||||
elif (ubx_nmea_state == looking_for_csum1):
|
||||
# Store the first NMEA checksum character
|
||||
nmea_csum1 = c
|
||||
ubx_nmea_state = looking_for_csum2
|
||||
elif (ubx_nmea_state == looking_for_csum2):
|
||||
# Store the second NMEA checksum character
|
||||
nmea_csum2 = c
|
||||
# Now check if the checksum is correct
|
||||
if ((nmea_csum1 != nmea_expected_csum1) or (nmea_csum2 != nmea_expected_csum2)):
|
||||
# The checksum does not match so sync_lost
|
||||
print("Panic!! NMEA checksum error!")
|
||||
print("Sync lost at byte "+str(processed)+". Attemting to re-sync")
|
||||
sync_lost_at = processed
|
||||
resync_in_progress = True
|
||||
ubx_nmea_state = sync_lost
|
||||
else:
|
||||
# Checksum was valid so wait for the terminators
|
||||
ubx_nmea_state = looking_for_term1
|
||||
elif (ubx_nmea_state == looking_for_term1):
|
||||
# Check if this is CR
|
||||
if (c != 0x0D):
|
||||
print("Panic!! NMEA CR not found!")
|
||||
print("Sync lost at byte "+str(processed)+". Attemting to re-sync")
|
||||
sync_lost_at = processed
|
||||
resync_in_progress = True
|
||||
ubx_nmea_state = sync_lost
|
||||
else:
|
||||
ubx_nmea_state = looking_for_term2
|
||||
elif (ubx_nmea_state == looking_for_term2):
|
||||
# Check if this is LF
|
||||
if (c != 0x0A):
|
||||
print("Panic!! NMEA LF not found!")
|
||||
print("Sync lost at byte "+str(processed)+". Attemting to re-sync")
|
||||
sync_lost_at = processed
|
||||
resync_in_progress = True
|
||||
ubx_nmea_state = sync_lost
|
||||
else:
|
||||
# Valid NMEA message was received. Check if we have seen this message type before
|
||||
if message_type in messages:
|
||||
messages[message_type] += 1 # if we have, increment its count
|
||||
else:
|
||||
messages[message_type] = 1 # if we have not, set its count to 1
|
||||
if (nmea_length > longest_NMEA): # Update the longest NMEA message length
|
||||
longest_NMEA = nmea_length
|
||||
# LF was received so go back to looking for B5 or a $
|
||||
ubx_nmea_state = looking_for_B5_dollar
|
||||
rewind_in_progress = False # Clear rewind_in_progress
|
||||
rewind_to = -1
|
||||
if (resync_in_progress == True): # Check if we are resyncing
|
||||
resync_in_progress = False # Clear the flag now that a valid message has been received
|
||||
resyncs += 1 # Increment the number of successful resyncs
|
||||
print("Sync successfully re-established at byte "+str(processed)+". The NMEA message started at byte "+str(message_start_byte))
|
||||
print()
|
||||
if (repairFile):
|
||||
fo.seek(rewind_repair_file_to) # Rewind the repaired file
|
||||
repaired_file_bytes = rewind_repair_file_to
|
||||
fi.seek(message_start_byte) # Copy the valid message into the repair file
|
||||
repaired_bytes_to_write = processed - message_start_byte
|
||||
fileBytes = fi.read(repaired_bytes_to_write)
|
||||
fo.write(fileBytes)
|
||||
repaired_file_bytes = repaired_file_bytes + repaired_bytes_to_write
|
||||
else:
|
||||
if (repairFile):
|
||||
rewind_repair_file_to = repaired_file_bytes # Rewind repair file to here if sync is lost
|
||||
|
||||
# Check if the end of the file has been reached
|
||||
if (processed >= filesize - 1): keepGoing = False
|
||||
|
||||
# Check if we should attempt to rewind
|
||||
# Don't rewind if we have not yet seen a valid message
|
||||
# Don't rewind if a rewind is already in progress
|
||||
if (ubx_nmea_state == sync_lost) and (len(messages) > 0) and (rewind_in_progress == False) and (rewind_to >= 0):
|
||||
rewind_attempts += 1 # Increment the number of rewind attempts
|
||||
if (rewind_attempts > max_rewinds): # Only rewind up to max_rewind times
|
||||
print("Panic! Maximum rewind attempts reached! Aborting...")
|
||||
keepGoing = False
|
||||
else:
|
||||
print("Sync has been lost. Currently processing byte "+str(processed)+". Rewinding to byte "+str(rewind_to))
|
||||
fi.seek(rewind_to) # Rewind the file
|
||||
processed = rewind_to - 1 # Rewind processed too! (-1 is needed as processed is incremented at the start of the loop)
|
||||
rewind_in_progress = True # Flag that a rewind is in progress
|
||||
|
||||
|
||||
finally:
|
||||
fi.close() # Close the file
|
||||
|
||||
if (repairFile):
|
||||
fo.close()
|
||||
|
||||
# Print the file statistics
|
||||
print()
|
||||
processed += 1
|
||||
print('Processed',processed,'bytes')
|
||||
print('File size was',filesize)
|
||||
if (processed != filesize):
|
||||
print('FILE SIZE MISMATCH!!')
|
||||
print('Longest valid UBX message was %i bytes'%longest_UBX)
|
||||
if (containsNMEA == True):
|
||||
print('Longest valid NMEA message was %i characters'%longest_NMEA)
|
||||
if len(messages) > 0:
|
||||
print('Message types and totals were:')
|
||||
for key in messages.keys():
|
||||
print('Message type:',key,' Total:',messages[key])
|
||||
if (resyncs > 0):
|
||||
print('Number of successful resyncs:',resyncs)
|
||||
print()
|
||||
if (repairFile):
|
||||
print('Aligned data written to:', repairFilename)
|
||||
print('Largest alignment change:', largest_rawx_alignment)
|
||||
if (resyncs > 0):
|
||||
print('Note: alignment is skipped during resyncing')
|
||||
print('You may need to run the code twice to align any skipped alignments')
|
||||
print()
|
||||
print('Bye!')
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
Monitor AssistNow Autonomous data collection
|
||||
By: SparkFun Electronics / Paul Clark
|
||||
Date: November 29th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to enable and monitor AssistNow Autonomous data collection by the module.
|
||||
A callback is used to monitor AssistNow Autonomous data availability for each satellite.
|
||||
A second callback is used to print the AOPSTATUS status.
|
||||
|
||||
If your GNSS board has battery-backup for the RAM - and all SparkFun boards do! - then you can:
|
||||
wait until the module has AssistNow Autonomous data for a few satellites;
|
||||
power-cycle the board;
|
||||
watch how fast it gets its first fix!
|
||||
|
||||
Note: this example will only work on boards which have plenty of RAM available.
|
||||
The UBX-NAV-SAT information occupies several kBytes.
|
||||
|
||||
Note: this example will not work on the ZED-F9P. "The ZED-F9P supports AssistNow Online only."
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
|
||||
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
// Callback: printSATdata will be called when new NAV SAT data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_NAV_SAT_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVSATcallback
|
||||
// / _____ This _must_ be UBX_NAV_SAT_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printSATdata(UBX_NAV_SAT_data_t *ubxDataStruct)
|
||||
{
|
||||
//Serial.println();
|
||||
|
||||
Serial.print(F("UBX-NAV-SAT contains data for "));
|
||||
Serial.print(ubxDataStruct->header.numSvs);
|
||||
if (ubxDataStruct->header.numSvs == 1)
|
||||
Serial.println(F(" SV"));
|
||||
else
|
||||
Serial.println(F(" SVs"));
|
||||
|
||||
uint16_t numAopAvail = 0; // Count how many SVs have AssistNow Autonomous data available
|
||||
|
||||
for (uint16_t block = 0; block < ubxDataStruct->header.numSvs; block++) // For each SV
|
||||
{
|
||||
if (ubxDataStruct->blocks[block].flags.bits.aopAvail == 1) // If the aopAvail bit is set
|
||||
numAopAvail++; // Increment the number of SVs
|
||||
}
|
||||
|
||||
Serial.print(F("AssistNow Autonomous data is available for "));
|
||||
Serial.print(numAopAvail);
|
||||
if (numAopAvail == 1)
|
||||
Serial.println(F(" SV"));
|
||||
else
|
||||
Serial.println(F(" SVs"));
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
// Callback: printAOPstatus will be called when new NAV AOPSTATUS data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_NAV_AOPSTATUS_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVAOPSTATUScallback
|
||||
// / _____ This _must_ be UBX_NAV_AOPSTATUS_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printAOPstatus(UBX_NAV_AOPSTATUS_data_t *ubxDataStruct)
|
||||
{
|
||||
//Serial.println();
|
||||
|
||||
Serial.print(F("AOPSTATUS status is "));
|
||||
Serial.println(ubxDataStruct->status);
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
// Callback: printPVTdata will be called when new NAV PVT data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoPVTcallback
|
||||
// / _____ This _must_ be UBX_NAV_PVT_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct)
|
||||
{
|
||||
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
|
||||
|
||||
Serial.println();
|
||||
|
||||
long latitude = ubxDataStruct->lat; // Print the latitude
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = ubxDataStruct->lon; // Print the longitude
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = ubxDataStruct->hMSL; // Print the height above mean sea level
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte fixType = ubxDataStruct->fixType; // Print the fix type
|
||||
Serial.print(F(" Fix: "));
|
||||
if(fixType == 0) Serial.print(F("No fix"));
|
||||
else if(fixType == 1) Serial.print(F("Dead reckoning"));
|
||||
else if(fixType == 2) Serial.print(F("2D"));
|
||||
else if(fixType == 3) Serial.print(F("3D"));
|
||||
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
|
||||
else if(fixType == 5) Serial.print(F("Time only"));
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void setup()
|
||||
{
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("AssistNow Example"));
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Start I2C. Connect to the GNSS.
|
||||
|
||||
Wire.begin(); //Start I2C
|
||||
|
||||
//myGNSS.enableDebugging(Serial, true); // Uncomment this line to see the 'major' debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
Serial.println(F("u-blox module connected"));
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Enable AssistNow Autonomous data collection.
|
||||
|
||||
if (myGNSS.setAopCfg(1) == true)
|
||||
{
|
||||
Serial.println(F("aopCfg enabled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Could not enable aopCfg. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Enable automatic UBX-NAV-SAT and UBX-NAV-AOPSTATUS messages and set up the callbacks
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one solution per second
|
||||
|
||||
myGNSS.setAutoNAVSATcallbackPtr(&printSATdata); // Enable automatic NAV SAT messages with callback to printSATdata
|
||||
myGNSS.setAutoAOPSTATUScallbackPtr(&printAOPstatus); // Enable automatic NAV AOPSTATUS messages with callback to printAOPstatus
|
||||
myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
Serial.print(".");
|
||||
delay(50);
|
||||
}
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
Read the AssistNow Autonomous database from the module
|
||||
By: SparkFun Electronics / Paul Clark
|
||||
Date: November 29th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to enable, check the status of, and read the AssistNow Autonomous data from the module.
|
||||
|
||||
Note: this example will only work on boards which have plenty of RAM available.
|
||||
The database can be several kBytes in length.
|
||||
|
||||
Note: this example will not work on the ZED-F9P. "The ZED-F9P supports AssistNow Online only."
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
|
||||
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
// Callback: printSATdata will be called when new NAV SAT data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_NAV_SAT_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVSATcallback
|
||||
// / _____ This _must_ be UBX_NAV_SAT_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printSATdata(UBX_NAV_SAT_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("UBX-NAV-SAT contains data for "));
|
||||
Serial.print(ubxDataStruct->header.numSvs);
|
||||
if (ubxDataStruct->header.numSvs == 1)
|
||||
Serial.println(F(" SV"));
|
||||
else
|
||||
Serial.println(F(" SVs"));
|
||||
|
||||
uint16_t numAopAvail = 0; // Count how many SVs have AssistNow Autonomous data available
|
||||
|
||||
for (uint16_t block = 0; block < ubxDataStruct->header.numSvs; block++) // For each SV
|
||||
{
|
||||
if (ubxDataStruct->blocks[block].flags.bits.aopAvail == 1) // If the aopAvail bit is set
|
||||
numAopAvail++; // Increment the number of SVs
|
||||
}
|
||||
|
||||
Serial.print(F("AssistNow Autonomous data is available for "));
|
||||
Serial.print(numAopAvail);
|
||||
if (numAopAvail == 1)
|
||||
Serial.println(F(" SV"));
|
||||
else
|
||||
Serial.println(F(" SVs"));
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
// Callback: printAOPstatus will be called when new NAV AOPSTATUS data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_NAV_AOPSTATUS_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVAOPSTATUScallback
|
||||
// / _____ This _must_ be UBX_NAV_AOPSTATUS_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printAOPstatus(UBX_NAV_AOPSTATUS_data_t *ubxDataStruct)
|
||||
{
|
||||
//Serial.println();
|
||||
|
||||
Serial.print(F("AOPSTATUS status is "));
|
||||
Serial.println(ubxDataStruct->status);
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void setup()
|
||||
{
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("AssistNow Example"));
|
||||
|
||||
while (Serial.available()) Serial.read(); // Empty the serial buffer
|
||||
Serial.println(F("Press any key to begin..."));
|
||||
while (!Serial.available()); // Wait for a keypress
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Start I2C. Connect to the GNSS.
|
||||
|
||||
Wire.begin(); //Start I2C
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
Serial.println(F("u-blox module connected"));
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
|
||||
|
||||
//myGNSS.enableDebugging(Serial, true); // Uncomment this line to see helpful debug messages on Serial
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Enable AssistNow Autonomous data collection.
|
||||
|
||||
if (myGNSS.setAopCfg(1) == true)
|
||||
{
|
||||
Serial.println(F("aopCfg enabled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Could not enable aopCfg. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Enable automatic UBX-NAV-SAT and UBX-NAV-AOPSTATUS messages and set up the callbacks
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one solution per second
|
||||
|
||||
myGNSS.setAutoNAVSATcallbackPtr(&printSATdata); // Enable automatic NAV SAT messages with callback to printSATdata
|
||||
myGNSS.setAutoAOPSTATUScallbackPtr(&printAOPstatus); // Enable automatic NAV AOPSTATUS messages with callback to printAOPstatus
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Keep displaying NAV SAT and AOPSTATUS until the user presses a key
|
||||
|
||||
Serial.println(F("AssistNow Autonomous data collection is in progress. Press any key to quit and read the database."));
|
||||
|
||||
while (Serial.available()) Serial.read(); // Empty the serial buffer
|
||||
|
||||
while (!Serial.available()) // Wait for the arrival of a keypress
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
Serial.print(".");
|
||||
delay(50);
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Disable the automatic UBX-NAV-SAT and UBX-NAV-AOPSTATUS messages
|
||||
|
||||
myGNSS.setAutoNAVSAT(false);
|
||||
myGNSS.setAutoAOPSTATUS(false);
|
||||
delay(1100);
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Read the AssistNow Autonomous database from the module and pretty-print it (so it can be copied and pasted into the next example)
|
||||
|
||||
#define MAX_DATABASE_LENGTH 32768 // Allocate 32kBytes to store the navigation database
|
||||
size_t maxDatabaseLen = MAX_DATABASE_LENGTH;
|
||||
uint8_t *database = new uint8_t[MAX_DATABASE_LENGTH]; // The database will be stored here
|
||||
|
||||
Serial.println(F("Storage has been allocated for the database.")); Serial.flush();
|
||||
|
||||
size_t actualDatabaseLen = myGNSS.readNavigationDatabase(database, maxDatabaseLen); // Read the database
|
||||
|
||||
Serial.print(F("The Navigation Database length was "));
|
||||
Serial.println(actualDatabaseLen);
|
||||
|
||||
if (actualDatabaseLen == maxDatabaseLen)
|
||||
Serial.println(F("There was not enough memory to store the entire database. Some data will have been lost!"));
|
||||
|
||||
// Pretty-print the database so it can be copied into the next example
|
||||
Serial.println(F("Copy and paste the following into the next example, so you can write it back to the module:"));
|
||||
Serial.println();
|
||||
Serial.print(F("size_t databaseLen = "));
|
||||
Serial.print(actualDatabaseLen);
|
||||
Serial.println(F(";"));
|
||||
Serial.print(F("const uint8_t database["));
|
||||
Serial.print(actualDatabaseLen);
|
||||
Serial.println(F("] = {"));
|
||||
size_t i;
|
||||
for(i = 0; i < actualDatabaseLen; i++)
|
||||
{
|
||||
if ((i % 32) == 0)
|
||||
Serial.print(F(" 0x"));
|
||||
if (*(database + i) < 0x10) // Print leading zero
|
||||
Serial.print(F("0"));
|
||||
Serial.print(*(database + i), HEX);
|
||||
if (i == (actualDatabaseLen - 1))
|
||||
Serial.println();
|
||||
else if ((i % 32) == 31)
|
||||
Serial.println(F(","));
|
||||
else
|
||||
Serial.print(F(", 0x"));
|
||||
}
|
||||
Serial.println(F("};"));
|
||||
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Nothing to do here
|
||||
}
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
Write the AssistNow Autonomous database data to the module
|
||||
By: SparkFun Electronics / Paul Clark
|
||||
Date: December 1st, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to write the AssistNow Autonomous database date back to the module.
|
||||
|
||||
This example is written for the ESP32. A WiFi connection is used to get network time to pass to the module.
|
||||
(You could use an RTC instead.)
|
||||
|
||||
Copy and paste the database data from the previous example into database.h.
|
||||
|
||||
Update secrets.h with your:
|
||||
- WiFi credentials
|
||||
|
||||
Note: this example will not work on the ZED-F9P. "The ZED-F9P supports AssistNow Online only."
|
||||
|
||||
Note: this example works best if you have the GNSS RAM battery-backup disabled.
|
||||
All SparkFun boards have battery-backup for the RAM which will means the database is retained if you disconnect the power.
|
||||
The module will use the database data from the battery-backed RAM when you turn the power back on.
|
||||
You will only see the improvement in the time-to-first-fix if you disable the battery first - or you are using a non-SparkFun
|
||||
board that does not have the backup battery.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
|
||||
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include "database.h" // <- Copy and paste the database data from the previous example into database.h
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include "secrets.h"
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
#include "time.h"
|
||||
|
||||
const char* ntpServer = "pool.ntp.org"; // The Network Time Protocol Server
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void setup()
|
||||
{
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("AssistNow Example"));
|
||||
|
||||
while (Serial.available()) Serial.read(); // Empty the serial buffer
|
||||
Serial.println(F("Press any key to begin..."));
|
||||
while (!Serial.available()); // Wait for a keypress
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Start I2C. Connect to the GNSS.
|
||||
|
||||
Wire.begin(); //Start I2C
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
Serial.println(F("u-blox module connected"));
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
|
||||
|
||||
//myGNSS.enableDebugging(Serial, true); // Uncomment this line to see helpful debug messages on Serial
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Connect to WiFi.
|
||||
|
||||
Serial.print(F("Connecting to local WiFi"));
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(F("."));
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
Serial.println(F("WiFi connected!"));
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Set the RTC using network time. (Code taken from the SimpleTime example.)
|
||||
|
||||
// Request the time from the NTP server and use it to set the ESP32's RTC.
|
||||
configTime(0, 0, ntpServer); // Set the GMT and daylight offsets to zero. We need UTC, not local time.
|
||||
|
||||
struct tm timeinfo;
|
||||
if(!getLocalTime(&timeinfo))
|
||||
{
|
||||
Serial.println("Failed to obtain time");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(&timeinfo, "Time is: %A, %B %d %Y %H:%M:%S");
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Push the RTC time to the module
|
||||
|
||||
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
|
||||
//myGNSS.enableDebugging(Serial, true);
|
||||
|
||||
if(getLocalTime(&timeinfo))
|
||||
{
|
||||
// setUTCTimeAssistance uses a default time accuracy of 2 seconds which should be OK here.
|
||||
// Have a look at the library source code for more details.
|
||||
myGNSS.setUTCTimeAssistance(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
|
||||
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Push the AssistNow Autonomous data to the module
|
||||
|
||||
size_t bytesPushed = myGNSS.pushAssistNowData(database, databaseLen);
|
||||
|
||||
Serial.print(F("Pushed "));
|
||||
Serial.print(bytesPushed);
|
||||
Serial.println(F(" bytes of AssistNow Autonomous data to the module"));
|
||||
|
||||
if (bytesPushed != databaseLen)
|
||||
Serial.println(F("Warning: bytesPushed does not match databaseLen! Maybe the database contains bad data? Or there was a communication error?"));
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Disconnect the WiFi as it's no longer needed
|
||||
|
||||
WiFi.disconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
Serial.println(F("WiFi disconnected"));
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
byte fixType = myGNSS.getFixType();
|
||||
Serial.print(F(" Fix: "));
|
||||
if(fixType == 0) Serial.print(F("No fix"));
|
||||
else if(fixType == 1) Serial.print(F("Dead reckoning"));
|
||||
else if(fixType == 2) Serial.print(F("2D"));
|
||||
else if(fixType == 3) Serial.print(F("3D"));
|
||||
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
|
||||
else if(fixType == 5) Serial.print(F("Time only"));
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
// Paste the AssistNow Autonomous database data from the previous example here:
|
||||
|
||||
size_t databaseLen = 5480;
|
||||
const uint8_t database[5480] = {
|
||||
0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x02, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x01, 0x08, 0xC4, 0x04, 0x26, 0xFE, 0x02, 0x54, 0xBA, 0xA9,
|
||||
0xFF, 0xDA, 0x8C, 0x05, 0xA3, 0xC1, 0xCD, 0x85, 0x86, 0x0A, 0x14, 0x20, 0xAA, 0xE6, 0xB4, 0xD3, 0x4F, 0x27, 0x12, 0xE0, 0xE6, 0xC3, 0xE4, 0x79, 0x0E, 0xA1, 0xD3, 0x49, 0xF4, 0xFF, 0xAF, 0xF7,
|
||||
0x67, 0x2E, 0x93, 0xF9, 0x6A, 0x1B, 0x2D, 0x10, 0xD3, 0x49, 0xBD, 0xFF, 0x26, 0x01, 0x00, 0x1E, 0x81, 0x22, 0xA1, 0xE4, 0x2A, 0x00, 0x10, 0x50, 0x04, 0x00, 0xB7, 0xBF, 0xB5, 0x62, 0x13, 0x80,
|
||||
0x54, 0x00, 0x01, 0x00, 0x00, 0x05, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x04, 0x1E, 0xC4, 0x44, 0x72, 0x2F, 0x02, 0x71, 0xAD, 0xA4, 0xFF, 0xE8, 0xAE, 0xFA,
|
||||
0x42, 0x25, 0xD1, 0x0F, 0x0D, 0x03, 0xCB, 0x71, 0xCF, 0x12, 0x6F, 0x89, 0x0F, 0x27, 0xF3, 0x49, 0x7B, 0x29, 0x4B, 0xF1, 0x0C, 0xA1, 0xD4, 0x49, 0xF5, 0xFF, 0xB6, 0x03, 0x98, 0x36, 0xA0, 0x03,
|
||||
0xBB, 0x0F, 0x72, 0x1D, 0xD4, 0x49, 0xEE, 0xFF, 0x17, 0x00, 0x00, 0xC0, 0x85, 0x22, 0x2F, 0xF0, 0x3D, 0x00, 0x3C, 0x50, 0x04, 0x00, 0x1A, 0x35, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00,
|
||||
0x00, 0x07, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x06, 0x5B, 0xC4, 0x44, 0xD8, 0xEC, 0x02, 0x4E, 0x79, 0xAC, 0xFF, 0xE8, 0x8A, 0x1D, 0xBC, 0x9F, 0xE8, 0x86,
|
||||
0xD9, 0x07, 0x45, 0xD0, 0x05, 0x6A, 0x05, 0x06, 0xC3, 0x26, 0xB5, 0x7D, 0x4A, 0xA2, 0x86, 0xCA, 0x0D, 0xA1, 0xD4, 0x49, 0x2B, 0x00, 0x62, 0x07, 0x63, 0x2F, 0xF5, 0x05, 0x1E, 0x1A, 0x98, 0x10,
|
||||
0xD4, 0x49, 0x38, 0x00, 0xBA, 0xFF, 0x00, 0xCB, 0xBE, 0x22, 0xF4, 0x59, 0x09, 0x00, 0xB6, 0x50, 0x04, 0x00, 0x2E, 0x9B, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x09, 0x15, 0x0C,
|
||||
0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x08, 0x5E, 0xC4, 0x44, 0xFA, 0x7B, 0x02, 0x4E, 0x1B, 0xA5, 0xFF, 0x03, 0x6E, 0x07, 0xF5, 0x25, 0xF3, 0xB8, 0x36, 0x01, 0xDB, 0x4F,
|
||||
0x56, 0x3E, 0x8D, 0xA6, 0xD7, 0x26, 0x82, 0xFE, 0xA8, 0x4A, 0x7A, 0x44, 0x0D, 0xA1, 0xD4, 0x49, 0x05, 0x00, 0x7A, 0xFA, 0x1C, 0x37, 0xDC, 0xFA, 0x33, 0x0E, 0x7E, 0x1E, 0xD4, 0x49, 0xE5, 0xFF,
|
||||
0xFC, 0xFF, 0x00, 0xB7, 0xBA, 0x22, 0x87, 0x2A, 0x34, 0x00, 0xBC, 0x50, 0x04, 0x00, 0xDF, 0x11, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x0B, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00,
|
||||
0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0A, 0x2F, 0xC4, 0x44, 0xC7, 0x68, 0x00, 0xF6, 0x09, 0xAA, 0xFF, 0xED, 0xB8, 0x38, 0x24, 0x1C, 0xE8, 0xC5, 0x30, 0x00, 0xD0, 0x23, 0x17, 0xEC, 0xF7, 0x92,
|
||||
0x2D, 0x27, 0x7C, 0x39, 0x2C, 0x6B, 0x66, 0xF5, 0x0D, 0xA1, 0xD4, 0x49, 0xEA, 0xFF, 0x27, 0xF9, 0x09, 0x2F, 0x2B, 0xFA, 0x6A, 0x1B, 0xFB, 0x0F, 0xD4, 0x49, 0x01, 0x00, 0x0F, 0x00, 0x00, 0xC1,
|
||||
0x82, 0x22, 0x2A, 0x8A, 0x80, 0xFF, 0x5E, 0x50, 0x04, 0x00, 0x52, 0xBB, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x0D, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A,
|
||||
0x01, 0x03, 0x0C, 0x96, 0xC4, 0x44, 0x8E, 0xBD, 0x02, 0xE4, 0x39, 0xA6, 0xFF, 0xE8, 0x7E, 0xBE, 0x5F, 0xFE, 0xF3, 0xCA, 0xF0, 0x02, 0x5D, 0x9F, 0x84, 0x44, 0x3A, 0xC9, 0x6F, 0x27, 0xFD, 0x1B,
|
||||
0xDB, 0x27, 0x60, 0x63, 0x0D, 0xA1, 0xD4, 0x49, 0x32, 0x00, 0x4B, 0xFA, 0xA6, 0x33, 0x2C, 0xFB, 0x5C, 0x10, 0xB8, 0x1C, 0xD4, 0x49, 0x0E, 0x00, 0x1E, 0x00, 0x00, 0x0D, 0xB9, 0x22, 0x3A, 0x4D,
|
||||
0x07, 0x00, 0x2C, 0x51, 0x04, 0x00, 0x76, 0x2E, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x10, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0F, 0x22,
|
||||
0xC4, 0x44, 0x47, 0xD2, 0x02, 0x47, 0xEA, 0xA3, 0xFF, 0xEA, 0x53, 0xBB, 0xBD, 0x37, 0xBE, 0x0A, 0x5B, 0x06, 0x85, 0x4F, 0x13, 0x98, 0x48, 0x33, 0x95, 0x27, 0xC8, 0x3B, 0xE7, 0x1B, 0x37, 0x8F,
|
||||
0x0C, 0xA1, 0xD4, 0x49, 0xC9, 0xFF, 0x09, 0x0C, 0x98, 0x30, 0xB3, 0x0A, 0x16, 0x09, 0x14, 0x26, 0xD4, 0x49, 0xB3, 0xFF, 0x4E, 0x00, 0x00, 0xE0, 0x81, 0x22, 0x2D, 0xCD, 0x31, 0x00, 0x44, 0x50,
|
||||
0x04, 0x00, 0x39, 0x9B, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x14, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x13, 0x1B, 0xC4, 0x44, 0x6A, 0xD2,
|
||||
0x02, 0xE9, 0x7C, 0xA3, 0xFF, 0xEE, 0xD1, 0x59, 0xEE, 0xE7, 0x56, 0x56, 0xCC, 0x02, 0xE4, 0x2C, 0x39, 0x0E, 0xB6, 0x13, 0x56, 0x26, 0xDF, 0xE5, 0x41, 0x7C, 0xDA, 0x86, 0x0D, 0xA1, 0xD4, 0x49,
|
||||
0xFE, 0xFF, 0x81, 0x04, 0x73, 0x3A, 0x0F, 0x04, 0x54, 0x10, 0x59, 0x1B, 0xD4, 0x49, 0x37, 0x00, 0xDF, 0xFF, 0x00, 0x21, 0x87, 0x22, 0x0B, 0xF8, 0x10, 0x00, 0x36, 0x50, 0x04, 0x00, 0x75, 0x76,
|
||||
0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x1D, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1C, 0x31, 0xC4, 0xC4, 0x58, 0xF9, 0x02, 0xFC, 0xD0, 0xA5,
|
||||
0xFF, 0xEA, 0x04, 0x79, 0x3B, 0x17, 0xD6, 0x48, 0xEF, 0x00, 0xB9, 0x34, 0x1C, 0xC2, 0x1E, 0x93, 0x05, 0x28, 0xA0, 0x7E, 0x9D, 0x60, 0x7C, 0x63, 0x0C, 0xA1, 0xD4, 0x49, 0xD2, 0xFF, 0x51, 0xF4,
|
||||
0xD6, 0x2D, 0xD9, 0xF5, 0x45, 0x08, 0x41, 0x27, 0xD4, 0x49, 0x23, 0x00, 0xFE, 0xFF, 0x00, 0x7C, 0xBC, 0x22, 0x15, 0x51, 0x31, 0x00, 0x62, 0x50, 0x04, 0x00, 0xEC, 0xE1, 0xB5, 0x62, 0x13, 0x80,
|
||||
0x54, 0x00, 0x01, 0x00, 0x00, 0x1E, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1D, 0x22, 0xC4, 0x04, 0x53, 0x24, 0x02, 0xF4, 0x99, 0xA8, 0xFF, 0x08, 0x62, 0xE5,
|
||||
0x6F, 0x9E, 0x9C, 0x48, 0xBC, 0x02, 0xB4, 0x07, 0x9B, 0x6A, 0x21, 0x82, 0x28, 0x26, 0x78, 0x77, 0x0C, 0x90, 0x2F, 0xF9, 0x0C, 0xA1, 0xD4, 0x49, 0xE5, 0xFF, 0x34, 0x08, 0x30, 0x33, 0xC0, 0x06,
|
||||
0x34, 0x1B, 0x7C, 0x0E, 0xD4, 0x49, 0xF7, 0xFF, 0xEE, 0xFF, 0x00, 0x19, 0xBE, 0x22, 0x6F, 0xC0, 0x2F, 0x00, 0x44, 0x50, 0x04, 0x00, 0x93, 0x6D, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
|
||||
0x06, 0x07, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xA5, 0xB9, 0xC6, 0x04, 0x16, 0x44, 0x02, 0xC6, 0xE0, 0xD9, 0x21, 0x1C, 0xC0, 0xE0, 0xF8, 0xD5, 0x3D, 0x6E,
|
||||
0x01, 0x56, 0x21, 0xC1, 0x0F, 0x39, 0xF8, 0x70, 0x2D, 0x10, 0x7F, 0xFF, 0x10, 0x38, 0xEE, 0xA5, 0x80, 0x00, 0x00, 0xE8, 0x55, 0x0C, 0x1C, 0xEB, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
|
||||
0x06, 0x0F, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xAD, 0xB9, 0xC6, 0x04, 0x6F, 0x28, 0x02, 0x17, 0x5C, 0xB7, 0xE5, 0xF7, 0x80, 0x1F, 0x46, 0x2A, 0xDE, 0xBE,
|
||||
0xF0, 0x59, 0x45, 0x5C, 0xCE, 0x39, 0x75, 0x99, 0xF7, 0x10, 0x1B, 0x7B, 0xFF, 0x78, 0x18, 0x5D, 0xFE, 0x00, 0x00, 0xE8, 0x55, 0x07, 0xC8, 0x8F, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
|
||||
0x06, 0x10, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xAE, 0xB9, 0xC6, 0x84, 0x26, 0x63, 0x02, 0x0C, 0x60, 0x9D, 0xDA, 0x44, 0x5E, 0xE2, 0x3C, 0x27, 0xDD, 0xED,
|
||||
0xF5, 0x3B, 0xDE, 0xC1, 0xDE, 0x39, 0xA7, 0xDD, 0xF9, 0x20, 0x11, 0x54, 0x2A, 0x80, 0xFB, 0x6C, 0x80, 0x00, 0xFF, 0xEF, 0x55, 0x06, 0x17, 0x43, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
|
||||
0x06, 0x15, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xB3, 0xB9, 0xC6, 0x04, 0x6F, 0xC3, 0x02, 0xF0, 0xC6, 0x33, 0xC1, 0x45, 0x3F, 0x28, 0xC9, 0xBB, 0xBF, 0x1B,
|
||||
0x1B, 0xEC, 0x14, 0xF1, 0xF5, 0x39, 0x55, 0x25, 0x06, 0x30, 0x84, 0xAE, 0xC7, 0xA8, 0x89, 0x3D, 0x44, 0x00, 0xFD, 0xEF, 0x55, 0x0B, 0x89, 0xE0, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
|
||||
0x06, 0x17, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xB5, 0xB9, 0xC6, 0x04, 0x34, 0xBC, 0x02, 0xF5, 0xBE, 0x0D, 0x15, 0xEA, 0x21, 0xA3, 0xC8, 0xDB, 0x1E, 0x3A,
|
||||
0x31, 0x5A, 0x38, 0xB6, 0x20, 0x39, 0x8B, 0x4A, 0xD9, 0x30, 0xDF, 0x66, 0xF8, 0xB8, 0x9D, 0x5B, 0x00, 0x02, 0xFF, 0xEF, 0x55, 0x0A, 0x20, 0x5A, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00,
|
||||
0x00, 0x01, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x00, 0x7B, 0xB0, 0x04, 0xC5, 0xE4, 0x01, 0x73, 0x47, 0x5B, 0xAE, 0x1C, 0x18, 0x0D, 0xA1, 0x00, 0x65, 0xFD,
|
||||
0x00, 0x7B, 0x41, 0x2C, 0xEA, 0x00, 0x14, 0x16, 0x24, 0x00, 0xF1, 0x02, 0x67, 0x00, 0x06, 0xEA, 0x3F, 0x8A, 0xA4, 0x7B, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x02, 0x15, 0x0C,
|
||||
0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x01, 0x7B, 0xB0, 0x44, 0x66, 0x1F, 0x03, 0xC2, 0x82, 0xA8, 0x90, 0x0E, 0x1C, 0x0E, 0xA1, 0x00, 0x4E, 0xFD, 0x00, 0x7B, 0x4F, 0x99,
|
||||
0xE6, 0x00, 0xF3, 0xEB, 0xC3, 0x00, 0xE8, 0x8A, 0x6E, 0x00, 0x5C, 0x05, 0x00, 0x8A, 0xDF, 0xF9, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x03, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C,
|
||||
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x02, 0x7B, 0xB0, 0x04, 0x96, 0x8D, 0x01, 0xEB, 0x94, 0x1F, 0x20, 0x13, 0x6B, 0x0D, 0xA1, 0x00, 0x69, 0xFD, 0x00, 0x7B, 0xC1, 0x59, 0x14, 0x00, 0x8A, 0xAC,
|
||||
0x28, 0x00, 0xDD, 0x24, 0x37, 0x00, 0xE0, 0xEF, 0x3F, 0x8A, 0x0F, 0xED, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x04, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A,
|
||||
0x01, 0x03, 0x03, 0x7B, 0xB0, 0x44, 0x8F, 0x51, 0x01, 0xFF, 0xCA, 0x0C, 0xA8, 0x0B, 0xD6, 0x0C, 0xA1, 0x00, 0x44, 0xFD, 0x00, 0x7B, 0x3F, 0x67, 0x40, 0x00, 0x77, 0x26, 0x80, 0x00, 0x3A, 0x7C,
|
||||
0xB2, 0x00, 0x2E, 0x07, 0x00, 0x8A, 0xD8, 0xB6, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x05, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x04, 0x00,
|
||||
0xB0, 0x14, 0xB8, 0x76, 0x03, 0xEA, 0xD0, 0x30, 0x92, 0x0A, 0xF1, 0x0C, 0xA1, 0x00, 0x25, 0xFD, 0xD4, 0x49, 0x71, 0xCF, 0x12, 0x00, 0x49, 0x7B, 0x29, 0x00, 0xFA, 0x42, 0x25, 0x00, 0xBE, 0xFF,
|
||||
0x3F, 0x8A, 0xD6, 0xA9, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x06, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x05, 0x7B, 0xB0, 0x44, 0xBB, 0x76,
|
||||
0x01, 0x15, 0x1F, 0x14, 0x47, 0x1C, 0xB5, 0x0C, 0xA1, 0x00, 0x63, 0xFD, 0x00, 0x7B, 0x16, 0xD6, 0xE9, 0x00, 0xEC, 0xC2, 0xD5, 0x00, 0xAB, 0x35, 0x77, 0x00, 0x8C, 0x18, 0x80, 0x8A, 0x81, 0xB1,
|
||||
0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x07, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x06, 0x00, 0xB0, 0x14, 0x33, 0xF6, 0x03, 0x49, 0x98, 0x7D,
|
||||
0xC9, 0x05, 0xCA, 0x0D, 0xA1, 0x00, 0x63, 0xFD, 0xD4, 0x49, 0xD0, 0x05, 0x6A, 0x00, 0x7D, 0x4A, 0xA2, 0x00, 0x1D, 0xBC, 0x9F, 0x00, 0x2B, 0x09, 0x00, 0x8A, 0x4B, 0xEC, 0xB5, 0x62, 0x13, 0x80,
|
||||
0x34, 0x00, 0x02, 0x00, 0x00, 0x08, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x07, 0x7B, 0xB0, 0x04, 0x04, 0xE8, 0x01, 0xB3, 0x40, 0x38, 0xDD, 0x0E, 0x13, 0x0D,
|
||||
0xA1, 0x00, 0x22, 0xFD, 0x00, 0x7B, 0x33, 0x39, 0xBE, 0x00, 0x60, 0x6D, 0x02, 0x00, 0xAF, 0xE0, 0xC5, 0x00, 0xCF, 0x07, 0x80, 0x8A, 0x59, 0x50, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00,
|
||||
0x00, 0x09, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x08, 0x00, 0xB0, 0x14, 0x50, 0xB2, 0x03, 0x0A, 0x6B, 0x13, 0x14, 0x07, 0x44, 0x0D, 0xA1, 0x00, 0x28, 0xFD,
|
||||
0xD4, 0x49, 0x4F, 0x56, 0x3E, 0x00, 0xFE, 0xA8, 0x4A, 0x00, 0x07, 0xF5, 0x25, 0x00, 0x85, 0x06, 0x00, 0x8A, 0x09, 0xB0, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0A, 0x15, 0x0C,
|
||||
0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x09, 0x7B, 0xB0, 0x44, 0x94, 0x64, 0x01, 0x0C, 0xB3, 0x3B, 0x06, 0x13, 0x0D, 0x0D, 0xA1, 0x00, 0x6E, 0xFD, 0x00, 0x7B, 0x68, 0x3C,
|
||||
0x14, 0x00, 0x15, 0x6E, 0x97, 0x00, 0x53, 0x99, 0x16, 0x00, 0xEF, 0xF6, 0xBF, 0x8A, 0xC1, 0xA9, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0B, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C,
|
||||
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0A, 0x7B, 0xB0, 0x04, 0xF5, 0x0B, 0x01, 0xDE, 0x10, 0x03, 0x70, 0x0C, 0x97, 0x0D, 0xA1, 0xFF, 0x52, 0xFD, 0x00, 0x7B, 0x7A, 0x06, 0xEC, 0x00, 0xA3, 0x44,
|
||||
0x6B, 0x00, 0xA1, 0xEB, 0xC8, 0x00, 0x11, 0xF8, 0xBF, 0x8A, 0xB4, 0x35, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A,
|
||||
0x01, 0x03, 0x0B, 0x7B, 0xB0, 0x04, 0xFD, 0x31, 0x01, 0x09, 0xE0, 0x44, 0xFA, 0x12, 0xD4, 0x0C, 0xA1, 0x00, 0x54, 0xFD, 0x00, 0x7B, 0xBC, 0x3F, 0x97, 0x00, 0x0C, 0x17, 0x32, 0x00, 0x5D, 0xE0,
|
||||
0x30, 0x00, 0x72, 0xF7, 0xBF, 0x8A, 0x91, 0x2E, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0D, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0C, 0x00,
|
||||
0xB0, 0x14, 0x82, 0xD3, 0x03, 0x6F, 0x0C, 0x2F, 0x96, 0x10, 0x63, 0x0D, 0xA1, 0x00, 0x31, 0xFD, 0xD4, 0x49, 0x9F, 0x84, 0x44, 0x00, 0x1B, 0xDB, 0x27, 0x00, 0xBE, 0x5F, 0xFE, 0x00, 0xE9, 0x08,
|
||||
0x00, 0x8A, 0x4A, 0x74, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0E, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0D, 0x7B, 0xB0, 0x44, 0x3E, 0xB1,
|
||||
0x01, 0x66, 0xD7, 0x09, 0x30, 0x08, 0xCD, 0x0C, 0xA1, 0x00, 0x4A, 0xFD, 0x00, 0x7B, 0x72, 0x05, 0x96, 0x00, 0x85, 0x34, 0x7E, 0x00, 0xFE, 0xFB, 0x2F, 0x00, 0xCC, 0xF7, 0xBF, 0x8A, 0x3C, 0x14,
|
||||
0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0F, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0E, 0x7B, 0xB0, 0x44, 0x92, 0xB0, 0x01, 0xBF, 0xF2, 0x71,
|
||||
0x4F, 0xF7, 0x0E, 0x0D, 0xA1, 0x00, 0x26, 0xFD, 0x00, 0x7B, 0x66, 0x06, 0x3A, 0x00, 0xAE, 0x39, 0x2B, 0x00, 0xEF, 0x2D, 0x9C, 0x00, 0x95, 0x0F, 0x80, 0x8A, 0x3F, 0x35, 0xB5, 0x62, 0x13, 0x80,
|
||||
0x34, 0x00, 0x02, 0x00, 0x00, 0x10, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0F, 0x00, 0xB0, 0x14, 0x96, 0x34, 0x03, 0x8E, 0xB0, 0x65, 0xEC, 0x12, 0x8F, 0x0C,
|
||||
0xA1, 0x00, 0x1F, 0xFD, 0xD4, 0x49, 0x4F, 0x13, 0x98, 0x00, 0x3B, 0xE7, 0x1B, 0x00, 0xBB, 0xBD, 0x37, 0x00, 0x39, 0xF6, 0x3F, 0x8A, 0xF3, 0x43, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00,
|
||||
0x00, 0x11, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x10, 0x7B, 0xB0, 0x04, 0x5E, 0xE6, 0x01, 0xF3, 0xDF, 0x70, 0xA4, 0x18, 0x50, 0x0D, 0xA1, 0x00, 0x34, 0xFD,
|
||||
0x00, 0x7B, 0x86, 0x84, 0xC1, 0x00, 0x0F, 0xBA, 0xC1, 0x00, 0xF9, 0x59, 0xC2, 0x00, 0x39, 0x0A, 0x80, 0x8A, 0x83, 0x21, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x12, 0x15, 0x0C,
|
||||
0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x11, 0x7B, 0xB0, 0x04, 0x92, 0xB3, 0x01, 0xCD, 0x23, 0x11, 0x1A, 0x12, 0xC7, 0x0C, 0xA1, 0x00, 0x57, 0xFD, 0x00, 0x7B, 0x1B, 0x89,
|
||||
0xEA, 0x00, 0x3E, 0x35, 0x7D, 0x00, 0x7D, 0xB8, 0x6F, 0x00, 0x2B, 0xF1, 0xBF, 0x8A, 0x1F, 0x89, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x13, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C,
|
||||
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x12, 0x7B, 0xB0, 0x44, 0xDE, 0x29, 0x01, 0x15, 0x35, 0x49, 0xCA, 0x17, 0xF3, 0x0C, 0xA1, 0x00, 0x30, 0xFD, 0x00, 0x7B, 0xBE, 0x59, 0xC3, 0x00, 0xEA, 0xA7,
|
||||
0x50, 0x00, 0xBF, 0x3E, 0x23, 0x00, 0x5C, 0x08, 0x80, 0x8A, 0x31, 0x50, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x14, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A,
|
||||
0x01, 0x03, 0x13, 0x00, 0xB0, 0x14, 0x3E, 0x72, 0x03, 0xA1, 0xC5, 0x2C, 0xFA, 0xFE, 0x86, 0x0D, 0xA1, 0x00, 0x1B, 0xFD, 0xD4, 0x49, 0x2C, 0x39, 0x0E, 0x00, 0xE5, 0x41, 0x7C, 0x00, 0x59, 0xEE,
|
||||
0xE7, 0x00, 0x1F, 0xFA, 0x3F, 0x8A, 0x05, 0x19, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x15, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x14, 0x7B,
|
||||
0xB0, 0x44, 0x9E, 0xFA, 0x01, 0xD6, 0x02, 0xC7, 0xCD, 0x0A, 0x8B, 0x0C, 0xA1, 0x00, 0x4C, 0xFD, 0x00, 0x7B, 0x38, 0x8D, 0xE6, 0x00, 0x0D, 0x36, 0xD5, 0x00, 0xBA, 0x5E, 0xC7, 0x00, 0xA0, 0x00,
|
||||
0x80, 0x8A, 0x7F, 0x6E, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x16, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x15, 0x7B, 0xB0, 0x44, 0x9E, 0x17,
|
||||
0x01, 0x24, 0x81, 0x37, 0xE8, 0xFC, 0xEA, 0x0C, 0xA1, 0x00, 0x4C, 0xFD, 0x00, 0x7B, 0xDE, 0x06, 0x10, 0x00, 0xD1, 0x69, 0xDC, 0x00, 0xC5, 0x18, 0x94, 0x00, 0x28, 0x16, 0x80, 0x8A, 0xBE, 0x20,
|
||||
0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x17, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x16, 0x7B, 0xB0, 0x44, 0x2E, 0xDB, 0x01, 0x43, 0xB7, 0x0F,
|
||||
0xCC, 0x0F, 0x25, 0x0D, 0xA1, 0x00, 0x68, 0xFD, 0x00, 0x7B, 0x32, 0x3D, 0x13, 0x00, 0x85, 0x6C, 0x73, 0x00, 0xE0, 0xD5, 0x4F, 0x00, 0x1B, 0xF8, 0xBF, 0x8A, 0x13, 0xA5, 0xB5, 0x62, 0x13, 0x80,
|
||||
0x34, 0x00, 0x02, 0x00, 0x00, 0x18, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x17, 0x7B, 0xB0, 0x04, 0xAC, 0x23, 0x01, 0x3F, 0x2F, 0x63, 0xE2, 0xFA, 0x29, 0x0D,
|
||||
0xA1, 0x00, 0x4A, 0xFD, 0x00, 0x7B, 0x90, 0xA3, 0x66, 0x00, 0x3C, 0x04, 0x20, 0x00, 0x7B, 0x4A, 0x74, 0x00, 0x1E, 0x09, 0x80, 0x8A, 0x67, 0xDD, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00,
|
||||
0x00, 0x19, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x18, 0x7B, 0xB0, 0x04, 0xF3, 0x84, 0x01, 0x2A, 0xEE, 0x52, 0xCB, 0x0A, 0x9F, 0x0D, 0xA1, 0x00, 0x4E, 0xFD,
|
||||
0x00, 0x7B, 0xFC, 0x28, 0x94, 0x00, 0x03, 0x3B, 0x27, 0x00, 0x5D, 0xC2, 0x28, 0x00, 0x06, 0x11, 0x00, 0x8A, 0xBF, 0x71, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1A, 0x15, 0x0C,
|
||||
0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x19, 0x7B, 0xB0, 0x44, 0x12, 0x8B, 0x01, 0xA4, 0xBC, 0x35, 0x56, 0xFE, 0xF0, 0x0C, 0xA1, 0x00, 0x43, 0xFD, 0x00, 0x7B, 0x47, 0x4D,
|
||||
0x92, 0x00, 0xCE, 0xEF, 0x0C, 0x00, 0x55, 0x6B, 0x0E, 0x00, 0xA9, 0x08, 0x00, 0x8A, 0x09, 0xC6, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1B, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C,
|
||||
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1A, 0x7B, 0xB0, 0x44, 0x25, 0xAF, 0x01, 0xD4, 0x10, 0x50, 0x81, 0x14, 0xC4, 0x0C, 0xA1, 0x00, 0x29, 0xFD, 0x00, 0x7B, 0xA9, 0xFD, 0xBE, 0x00, 0x17, 0x91,
|
||||
0x19, 0x00, 0x63, 0x98, 0xC1, 0x00, 0x12, 0xFF, 0x3F, 0x8A, 0x9F, 0x4C, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1D, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A,
|
||||
0x01, 0x03, 0x1C, 0x00, 0xB0, 0x14, 0x3D, 0x4B, 0x03, 0x1C, 0xF4, 0x0E, 0xF2, 0x19, 0x63, 0x0C, 0xA1, 0x00, 0x2E, 0xFD, 0xD4, 0x49, 0x34, 0x1C, 0xC2, 0x00, 0x7E, 0x9D, 0x60, 0x00, 0x79, 0x3B,
|
||||
0x17, 0x00, 0x2A, 0xF6, 0x3F, 0x8A, 0x99, 0x1E, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1E, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1D, 0x00,
|
||||
0xB0, 0x14, 0x9C, 0x70, 0x03, 0x50, 0xC4, 0x2B, 0x21, 0xFC, 0xF9, 0x0C, 0xA1, 0x00, 0x44, 0xFD, 0xD4, 0x49, 0x07, 0x9B, 0x6A, 0x00, 0x77, 0x0C, 0x90, 0x00, 0xE5, 0x6F, 0x9E, 0x00, 0xF8, 0xFD,
|
||||
0x3F, 0x8A, 0x8C, 0x9F, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1F, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1E, 0x7B, 0xB0, 0x04, 0x9F, 0xDA,
|
||||
0x01, 0x5F, 0x6C, 0x55, 0x80, 0x08, 0xD4, 0x0C, 0xA1, 0x00, 0x5E, 0xFD, 0x00, 0x7B, 0xCB, 0xAE, 0x6A, 0x00, 0x9B, 0x04, 0x0E, 0x00, 0x96, 0x65, 0x3A, 0x00, 0x5F, 0x07, 0x80, 0x8A, 0xAA, 0xFA,
|
||||
0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x20, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1F, 0x7B, 0xB0, 0x44, 0x7E, 0x41, 0x01, 0x92, 0xEF, 0x2A,
|
||||
0x99, 0x09, 0x6C, 0x0D, 0xA1, 0x00, 0x40, 0xFD, 0x00, 0x7B, 0x3C, 0xB6, 0x3E, 0x00, 0x0C, 0xA2, 0x9E, 0x00, 0x27, 0x24, 0xDF, 0x00, 0xE0, 0xFF, 0xBF, 0x8A, 0xEB, 0xFB, 0xB5, 0x62, 0x13, 0x80,
|
||||
0x24, 0x00, 0x02, 0x00, 0x01, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x23, 0x00, 0xB0, 0x44, 0x55, 0xF1, 0x01, 0x0A, 0x01, 0xB6, 0x8F, 0x10, 0x40, 0x8D,
|
||||
0x04, 0x00, 0x8A, 0x08, 0x0E, 0x00, 0x92, 0x02, 0xB5, 0x62, 0x13, 0x80, 0x24, 0x00, 0x02, 0x00, 0x01, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x30, 0x00,
|
||||
0xB0, 0x44, 0x66, 0xC5, 0x03, 0x31, 0x1B, 0xBF, 0xC2, 0x02, 0x40, 0x8D, 0x04, 0x00, 0x8A, 0x08, 0x0E, 0x00, 0x02, 0x61, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x01, 0x15, 0x0C,
|
||||
0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x9F, 0xBD, 0xD2, 0x04, 0x7B, 0x94, 0x00, 0x0C, 0xC5, 0x40, 0x6B, 0x08, 0x38, 0xC3, 0x24, 0xFD, 0xC5, 0xC3, 0xA5, 0x57, 0xE1, 0x21,
|
||||
0x3E, 0x01, 0x58, 0x1D, 0x78, 0x3A, 0x38, 0x13, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x02, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA0, 0xBD,
|
||||
0xB2, 0x04, 0x91, 0x39, 0x00, 0x56, 0xDD, 0x3F, 0x2B, 0x17, 0x59, 0xC0, 0x82, 0xEF, 0x6C, 0x9A, 0xA8, 0x57, 0x7C, 0x9D, 0x72, 0x07, 0xBA, 0x27, 0x78, 0x3A, 0xB1, 0x11, 0xB5, 0x62, 0x13, 0x80,
|
||||
0x2C, 0x00, 0x02, 0x00, 0x06, 0x03, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA1, 0xBD, 0xD2, 0x04, 0xBE, 0x31, 0x00, 0xB5, 0xD6, 0x3F, 0x6B, 0x19, 0x87, 0xDB,
|
||||
0x80, 0xFE, 0x42, 0x0C, 0xAB, 0x57, 0xDE, 0xA0, 0x21, 0x07, 0xF9, 0x23, 0x74, 0x3A, 0x7E, 0x46, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x04, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A,
|
||||
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA2, 0xBD, 0xB2, 0x04, 0x57, 0x31, 0x00, 0x4B, 0xBE, 0x3F, 0xAB, 0x21, 0x5E, 0x0B, 0x3F, 0xFC, 0x75, 0x74, 0xAD, 0x57, 0x5F, 0xB2, 0x07, 0x03, 0x1B, 0x2B,
|
||||
0x70, 0x3A, 0xBB, 0x0F, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x05, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA3, 0xBD, 0xD2, 0x04, 0x33, 0x11,
|
||||
0x00, 0x49, 0xAC, 0x3F, 0x6B, 0x28, 0xE3, 0x3A, 0x7D, 0xFD, 0x5F, 0xDB, 0xAF, 0x57, 0x9D, 0x88, 0x4D, 0x02, 0x72, 0x2B, 0x6C, 0x3A, 0x3E, 0x71, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00,
|
||||
0x06, 0x06, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA4, 0xBD, 0xD2, 0x04, 0xEC, 0x1E, 0x00, 0xD0, 0xF5, 0x3F, 0x2B, 0x37, 0x2E, 0xF3, 0xBA, 0x80, 0x9A, 0xA6,
|
||||
0xB2, 0x57, 0xF7, 0x5D, 0x55, 0x03, 0xF4, 0x1C, 0x68, 0x3A, 0x19, 0x49, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x07, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A,
|
||||
0x01, 0x03, 0xA5, 0xBD, 0xD2, 0x84, 0xCD, 0x4A, 0x02, 0x75, 0xE1, 0x3F, 0x6B, 0x39, 0x75, 0x51, 0x48, 0x81, 0x45, 0x3F, 0xA1, 0x57, 0x5D, 0xA0, 0x16, 0x06, 0x27, 0x24, 0x84, 0x3A, 0xA8, 0x47,
|
||||
0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x08, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA6, 0xBD, 0xD2, 0x04, 0x3F, 0xAB, 0x00, 0xC5, 0xCE, 0x3F,
|
||||
0xAB, 0x41, 0x2F, 0x8F, 0x06, 0x82, 0x68, 0x8F, 0xA3, 0x57, 0xB1, 0xB2, 0x4E, 0x07, 0x51, 0x24, 0x90, 0x3A, 0x81, 0x71, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x09, 0x15, 0x0C,
|
||||
0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA7, 0xBD, 0xD2, 0x04, 0xEF, 0x93, 0x00, 0x15, 0x7A, 0x40, 0xAB, 0x4F, 0xD9, 0xD5, 0x4F, 0xFF, 0xD6, 0x42, 0xA5, 0x57, 0xAC, 0x90,
|
||||
0x39, 0x06, 0x3F, 0x11, 0x94, 0x3B, 0xA2, 0xFC, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x0A, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA8, 0xBD,
|
||||
0xD2, 0x84, 0x00, 0xC3, 0x00, 0xBA, 0x16, 0x40, 0x6B, 0x56, 0xF5, 0x1B, 0x8E, 0x82, 0xD8, 0x8B, 0xA7, 0x57, 0x1B, 0x06, 0xE9, 0x06, 0x2D, 0x21, 0x94, 0x3B, 0x71, 0x55, 0xB5, 0x62, 0x13, 0x80,
|
||||
0x2C, 0x00, 0x02, 0x00, 0x06, 0x0B, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA9, 0xBD, 0xD2, 0x04, 0xD3, 0x18, 0x00, 0x90, 0x2C, 0x40, 0x2B, 0x58, 0xCF, 0x2D,
|
||||
0x8C, 0x7E, 0xEF, 0x12, 0xAA, 0x57, 0xD2, 0xB1, 0xAD, 0x01, 0x45, 0x27, 0x94, 0x3B, 0x8F, 0x20, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x0C, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A,
|
||||
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAA, 0xBD, 0xD2, 0x04, 0x7F, 0x3D, 0x00, 0x5E, 0x7A, 0x40, 0xEB, 0x67, 0x2C, 0x45, 0xCA, 0xF6, 0x48, 0xA8, 0xAC, 0x57, 0xF8, 0xD5, 0x66, 0x04, 0x36, 0x22,
|
||||
0x94, 0x3B, 0x5B, 0x01, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x0D, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAB, 0xBD, 0xD2, 0x84, 0xC1, 0x1E,
|
||||
0x00, 0xC6, 0xFF, 0x3F, 0xAB, 0x6F, 0xFE, 0x69, 0x28, 0x82, 0xE4, 0x06, 0xAF, 0x57, 0x3D, 0x34, 0x38, 0x02, 0xFB, 0x20, 0x94, 0x3B, 0xC8, 0xB3, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00,
|
||||
0x06, 0x0E, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAC, 0xBD, 0xB2, 0x04, 0x41, 0xAE, 0x00, 0xFC, 0x51, 0x40, 0x6B, 0x76, 0x2D, 0x7B, 0xA6, 0xFD, 0x9C, 0x9F,
|
||||
0xB1, 0x57, 0xDA, 0xAF, 0xDE, 0x01, 0xB5, 0x1B, 0x98, 0x3B, 0x8D, 0x75, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x0F, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A,
|
||||
0x01, 0x03, 0xAD, 0xBD, 0xD2, 0x04, 0x32, 0x99, 0x02, 0x17, 0x61, 0x40, 0x2B, 0x78, 0x76, 0xB4, 0xD3, 0xFC, 0x10, 0x45, 0xA0, 0x57, 0x67, 0xC7, 0xEF, 0x02, 0x93, 0x20, 0x90, 0x3B, 0xC3, 0x1E,
|
||||
0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x10, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAE, 0xBD, 0xD2, 0x04, 0x70, 0x64, 0x02, 0x10, 0xC5, 0x40,
|
||||
0xEB, 0x87, 0x72, 0x87, 0xF1, 0x80, 0x8E, 0xF2, 0xA2, 0x57, 0x57, 0x0A, 0x76, 0x0C, 0xD9, 0x17, 0x88, 0x3B, 0x91, 0xAA, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x11, 0x15, 0x0C,
|
||||
0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAF, 0xBD, 0xD2, 0x04, 0x95, 0xB0, 0x00, 0x24, 0x2D, 0x40, 0x2B, 0x89, 0x3B, 0x4D, 0x5B, 0xF0, 0xAB, 0x5C, 0xA4, 0x57, 0x50, 0x95,
|
||||
0x23, 0x04, 0xB1, 0x3A, 0x0C, 0x3A, 0x59, 0x64, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x12, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB0, 0xBD,
|
||||
0xD2, 0x04, 0x61, 0xBD, 0x00, 0xC7, 0x14, 0x40, 0x6B, 0x97, 0x82, 0x8D, 0xD9, 0xFC, 0xB9, 0xB4, 0xA6, 0x57, 0x71, 0xE6, 0x0F, 0x05, 0x96, 0x40, 0x10, 0x3A, 0xD3, 0x7B, 0xB5, 0x62, 0x13, 0x80,
|
||||
0x2C, 0x00, 0x02, 0x00, 0x06, 0x13, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB1, 0xBD, 0xD2, 0x04, 0x61, 0x35, 0x00, 0xC3, 0xC6, 0x3F, 0xEB, 0x98, 0x44, 0x01,
|
||||
0x98, 0x85, 0xA8, 0xE9, 0xA8, 0x57, 0xC2, 0xA4, 0x0D, 0x01, 0xFD, 0x45, 0x10, 0x3A, 0x94, 0x41, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x14, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A,
|
||||
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB2, 0xBD, 0xD2, 0x04, 0xB1, 0x18, 0x00, 0x5D, 0x11, 0x40, 0xAB, 0xA0, 0xC8, 0xDF, 0x15, 0x82, 0xB1, 0xB9, 0xAB, 0x57, 0xF1, 0xE9, 0xC1, 0x03, 0x4A, 0x46,
|
||||
0x10, 0x3A, 0xA7, 0x43, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x15, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB3, 0xBD, 0xD2, 0x04, 0x28, 0x00,
|
||||
0x02, 0x5E, 0x5E, 0x40, 0x2B, 0xA9, 0x27, 0xA6, 0x73, 0x88, 0xE6, 0x73, 0xAE, 0x57, 0xCC, 0x8C, 0xAD, 0x02, 0x36, 0x3F, 0x14, 0x3A, 0xAF, 0x7C, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00,
|
||||
0x06, 0x16, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB4, 0xBD, 0xD2, 0x04, 0x85, 0xEC, 0x00, 0x91, 0xEE, 0x3F, 0x6B, 0xB7, 0x72, 0xF2, 0xD1, 0x84, 0x7D, 0xBE,
|
||||
0xB0, 0x57, 0xEE, 0x05, 0x09, 0x08, 0x71, 0x43, 0x18, 0x3A, 0x1D, 0x65, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x17, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A,
|
||||
0x01, 0x03, 0xB5, 0xBD, 0xD2, 0x04, 0xB1, 0x72, 0x02, 0x0E, 0xDA, 0x3E, 0xEB, 0xB8, 0xE4, 0xB4, 0xAF, 0x80, 0x21, 0xAF, 0xB3, 0x57, 0x7C, 0x50, 0x49, 0x00, 0x24, 0x43, 0x18, 0x3A, 0x26, 0xE7,
|
||||
0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x18, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB6, 0xBD, 0xD2, 0x04, 0xE1, 0x9D, 0x00, 0xA2, 0x0C, 0x40,
|
||||
0xAB, 0xC0, 0xEA, 0x39, 0xDD, 0xFD, 0x09, 0xEC, 0xA1, 0x57, 0x92, 0xAE, 0x92, 0x03, 0x96, 0x2B, 0x08, 0x3A, 0x64, 0xD1, 0xB5, 0x62, 0x13, 0x80, 0x78, 0x00, 0x03, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x19, 0x00, 0x00, 0x05, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x07, 0x00, 0x8A, 0x08, 0x89, 0x08, 0x12, 0x07,
|
||||
0x12, 0x00, 0xC1, 0x03, 0x00, 0x00, 0x19, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x32, 0x00, 0x00, 0x80, 0xB2, 0x00, 0x00, 0x80, 0xB3, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0xEC, 0x47, 0x00, 0x00,
|
||||
0x60, 0xC8, 0x00, 0x00, 0x80, 0xC7, 0x00, 0x00, 0x50, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x22, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x03, 0x00, 0x06, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x12, 0x00, 0x06, 0x07, 0x11, 0x00, 0x06, 0x15, 0x01, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xBD, 0x3A, 0xBD, 0x02, 0x92, 0xC7,
|
||||
0x1E, 0x00, 0xBD, 0x3A, 0x00, 0x00, 0x83, 0xEB, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x02, 0x15, 0x0C, 0x04, 0x14, 0x0F, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x01, 0x5E,
|
||||
0xAD, 0x14, 0x0D, 0xD9, 0x01, 0x99, 0x8A, 0x08, 0x57, 0xFD, 0x00, 0x00, 0x00, 0xC4, 0xA0, 0xFF, 0xAF, 0x13, 0x31, 0x04, 0x00, 0xED, 0x07, 0xBB, 0xE2, 0xC1, 0xE2, 0xA6, 0xA2, 0x5F, 0x18, 0xC2,
|
||||
0x8E, 0x08, 0x42, 0xC9, 0xD5, 0x17, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x07, 0x20, 0x00, 0x50, 0xF8, 0xAB, 0xA6, 0xD0, 0xC2, 0x7C, 0xE2, 0xDC, 0x80, 0x36, 0x92, 0x07, 0x9C, 0x36, 0xA1, 0x2E,
|
||||
0x78, 0x0C, 0x91, 0xCE, 0x7E, 0xE6, 0x3E, 0x63, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x05, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x04, 0x5E,
|
||||
0xAD, 0x14, 0xBB, 0x54, 0x01, 0x85, 0x8A, 0x08, 0x58, 0xFD, 0x00, 0x00, 0x40, 0xC4, 0xA9, 0xFF, 0xAF, 0x13, 0xEE, 0xD1, 0x3F, 0xF4, 0xE8, 0xBA, 0x02, 0x42, 0xDB, 0xA6, 0xE2, 0x4F, 0x93, 0xCC,
|
||||
0x86, 0x08, 0x5E, 0xE0, 0xFB, 0x01, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0xB2, 0xC2, 0xA1, 0xA2, 0x5A, 0xF1, 0x5A, 0x67, 0xD2, 0x32, 0xCB, 0x87, 0x73, 0xEA, 0xA6, 0x22, 0x7E, 0xCE,
|
||||
0xB7, 0xF8, 0x59, 0xCB, 0x13, 0xCF, 0x90, 0x3D, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x07, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x06, 0x5E,
|
||||
0xAD, 0x14, 0x1C, 0x84, 0x01, 0x3C, 0x8A, 0x08, 0x58, 0x01, 0x00, 0x00, 0x40, 0x44, 0x5B, 0x01, 0xA0, 0x13, 0xB1, 0x77, 0x00, 0xF4, 0xE8, 0xBA, 0x02, 0x02, 0xDC, 0xA6, 0x62, 0x0D, 0x9B, 0x10,
|
||||
0x8D, 0x08, 0xE8, 0xB3, 0x12, 0x04, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0xD3, 0xB5, 0xB7, 0x0A, 0x9E, 0x12, 0x42, 0xA2, 0x14, 0xB9, 0xAD, 0xE8, 0xD6, 0xBA, 0xA1, 0x04, 0xEB, 0x56,
|
||||
0xE5, 0x29, 0xD2, 0xF1, 0x3E, 0xD4, 0x51, 0xD3, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x09, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x08, 0x5E,
|
||||
0xAD, 0x14, 0xAE, 0x75, 0x01, 0xEB, 0x8A, 0x08, 0x58, 0x7D, 0x00, 0x00, 0x40, 0x44, 0x27, 0x00, 0xA0, 0x13, 0x2A, 0x09, 0x80, 0x01, 0xE8, 0xBA, 0x02, 0xC2, 0xDC, 0xA6, 0x42, 0x7D, 0x43, 0x25,
|
||||
0x97, 0x08, 0x0E, 0x55, 0xE8, 0x19, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x34, 0x43, 0x60, 0xE2, 0x59, 0x42, 0xAE, 0xE1, 0xE5, 0x34, 0x86, 0x80, 0xA7, 0xDF, 0xA3, 0xE9, 0x4E, 0xB1,
|
||||
0xF7, 0x28, 0xB4, 0xBC, 0x8B, 0xD9, 0x5E, 0x5F, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x0D, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x0C, 0x5E,
|
||||
0xAD, 0x14, 0x79, 0x8D, 0x01, 0x81, 0x8A, 0x08, 0x58, 0x01, 0x00, 0x00, 0x40, 0x44, 0x91, 0x01, 0xA0, 0x13, 0x16, 0xD5, 0x3F, 0xF4, 0xE8, 0xBA, 0x02, 0x42, 0xDC, 0xA6, 0x62, 0x60, 0x15, 0x2D,
|
||||
0x81, 0x08, 0x74, 0x9A, 0x0E, 0x09, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x43, 0x1D, 0xEA, 0x22, 0xB7, 0x2E, 0xD8, 0x3E, 0x59, 0x3A, 0x55, 0x75, 0x09, 0xE7, 0x0A, 0x39, 0xC6, 0x02,
|
||||
0x6D, 0xFD, 0xE5, 0xF4, 0x5E, 0xEB, 0x85, 0x41, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x10, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x0F, 0x5E,
|
||||
0xAD, 0x14, 0xB3, 0xBB, 0x01, 0x4E, 0x8A, 0x08, 0x58, 0xFD, 0x00, 0x00, 0x40, 0xC4, 0x49, 0xFE, 0xAF, 0x13, 0x9A, 0xA4, 0x3F, 0xF5, 0xE8, 0xBA, 0x02, 0x02, 0xDC, 0xA6, 0xA2, 0x33, 0xC9, 0x6D,
|
||||
0x90, 0x08, 0x5A, 0x9A, 0xE3, 0x00, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x0D, 0xDD, 0x6D, 0xCD, 0xC2, 0x40, 0x3A, 0x97, 0x5C, 0x01, 0x02, 0x3D, 0x12, 0x48, 0x55, 0xDE, 0xBA, 0x35,
|
||||
0x8E, 0xFB, 0xE1, 0xF2, 0x92, 0xCE, 0x5C, 0xFB, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x14, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x13, 0x5E,
|
||||
0xAD, 0x14, 0x31, 0xC2, 0x01, 0x0F, 0x8A, 0x08, 0x58, 0x81, 0x00, 0x00, 0x40, 0x44, 0xF0, 0xFF, 0xAF, 0x13, 0x98, 0x87, 0x3F, 0xF7, 0xE8, 0xBA, 0x02, 0xC2, 0xDC, 0xA6, 0x42, 0x50, 0xFF, 0x9B,
|
||||
0x8B, 0x08, 0x16, 0xF0, 0x21, 0x1C, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x93, 0x50, 0xE6, 0x06, 0xCF, 0xB8, 0x8C, 0x20, 0xB6, 0x0C, 0x26, 0x4A, 0xC1, 0xC6, 0x7E, 0x22, 0xAC, 0xC6,
|
||||
0x13, 0x14, 0x27, 0xFF, 0x18, 0xD2, 0xBA, 0xBA, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x1D, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x1C, 0x5E,
|
||||
0xAD, 0x14, 0x13, 0x8D, 0x01, 0xBC, 0x8A, 0x08, 0x58, 0xFD, 0x00, 0x00, 0x40, 0xC4, 0x8F, 0xFE, 0xAF, 0x13, 0x52, 0xDC, 0x00, 0xF5, 0xE8, 0xBA, 0x02, 0xC2, 0xDC, 0xA6, 0xC2, 0x76, 0x7B, 0x55,
|
||||
0x91, 0x08, 0x2A, 0xA2, 0xE2, 0x18, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x0F, 0xB0, 0x0B, 0x57, 0x2E, 0x66, 0x57, 0xE9, 0x32, 0x5E, 0x4E, 0x14, 0x13, 0x5E, 0xFF, 0x22, 0xFA, 0x2A,
|
||||
0x77, 0xDB, 0x2C, 0xC6, 0xC6, 0xDE, 0x74, 0x97, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x1E, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x1D, 0x5E,
|
||||
0xAD, 0x14, 0x8D, 0x68, 0x01, 0xBB, 0x8A, 0x08, 0x58, 0xFD, 0x00, 0x00, 0x40, 0x44, 0x28, 0xFF, 0xAF, 0x13, 0x5F, 0x5B, 0x00, 0x04, 0xE8, 0xBA, 0x02, 0x42, 0xDC, 0xA6, 0x22, 0x7D, 0x16, 0x76,
|
||||
0x89, 0x08, 0xDE, 0x80, 0xDF, 0x08, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0xE3, 0x37, 0xB1, 0x7F, 0xE8, 0xDA, 0x6C, 0x66, 0x21, 0x07, 0x1F, 0x55, 0x27, 0x27, 0x42, 0x1B, 0x68, 0x58,
|
||||
0x2E, 0x2E, 0x19, 0xA5, 0xC5, 0xE3, 0xBB, 0x38
|
||||
};
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
//Your WiFi credentials
|
||||
const char ssid[] = "TRex";
|
||||
const char password[] = "hasBigTeeth";
|
||||
|
||||
//Your AssistNow token
|
||||
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";
|
||||
|
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
Use ESP32 WiFi to get AssistNow Offline data from u-blox Thingstream
|
||||
By: SparkFun Electronics / Paul Clark
|
||||
Date: November 26th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to obtain AssistNow Offline data from u-blox Thingstream over WiFi
|
||||
and push it over I2C to a u-blox module.
|
||||
|
||||
The module still needs to be given time assistance to achieve a fast fix. This example
|
||||
uses network time to do that. If you don't have a WiFi connection, you may have to use
|
||||
a separate RTC to provide the time.
|
||||
|
||||
Note: AssistNow Offline is not supported by the ZED-F9P! "The ZED-F9P supports AssistNow Online only."
|
||||
|
||||
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
|
||||
|
||||
Update secrets.h with your:
|
||||
- WiFi credentials
|
||||
- AssistNow token string
|
||||
|
||||
Uncomment the "#define USE_MGA_ACKs" below to test the more robust method of using the
|
||||
UBX_MGA_ACK_DATA0 acknowledgements to confirm that each MGA message has been accepted.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
|
||||
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
//#define USE_MGA_ACKs // Uncomment this line to use the UBX_MGA_ACK_DATA0 acknowledgements
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include "secrets.h"
|
||||
|
||||
const char assistNowServer[] = "https://offline-live1.services.u-blox.com";
|
||||
//const char assistNowServer[] = "https://offline-live2.services.u-blox.com"; // Alternate server
|
||||
|
||||
const char getQuery[] = "GetOfflineData.ashx?";
|
||||
const char tokenPrefix[] = "token=";
|
||||
const char tokenSuffix[] = ";";
|
||||
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
|
||||
const char getFormat[] = "format=mga;"; // Data format. Leave set to mga for M8 onwards. Can be aid.
|
||||
const char getPeriod[] = "period=1;"; // Optional. The number of weeks into the future that the data will be valid. Can be 1-5. Default = 4.
|
||||
const char getMgaResolution[] = "resolution=1;"; // Optional. Data resolution: 1 = every day; 2 = every other day; 3 = every 3rd day.
|
||||
//Note: always use resolution=1. findMGAANOForDate does not yet support finding the 'closest' date. It needs an exact match.
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
#include "time.h"
|
||||
|
||||
const char* ntpServer = "pool.ntp.org"; // The Network Time Protocol Server
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void setup()
|
||||
{
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("AssistNow Example"));
|
||||
|
||||
while (Serial.available()) Serial.read(); // Empty the serial buffer
|
||||
Serial.println(F("Press any key to begin..."));
|
||||
while (!Serial.available()); // Wait for a keypress
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Start I2C. Connect to the GNSS.
|
||||
|
||||
Wire.begin(); //Start I2C
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
Serial.println(F("u-blox module connected"));
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Connect to WiFi.
|
||||
|
||||
Serial.print(F("Connecting to local WiFi"));
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(F("."));
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
Serial.println(F("WiFi connected!"));
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Set the RTC using network time. (Code taken from the SimpleTime example.)
|
||||
|
||||
// Request the time from the NTP server and use it to set the ESP32's RTC.
|
||||
configTime(0, 0, ntpServer); // Set the GMT and daylight offsets to zero. We need UTC, not local time.
|
||||
|
||||
struct tm timeinfo;
|
||||
if(!getLocalTime(&timeinfo))
|
||||
{
|
||||
Serial.println("Failed to obtain time");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(&timeinfo, "Time is: %A, %B %d %Y %H:%M:%S");
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Use HTTP GET to receive the AssistNow_Online data
|
||||
|
||||
const int URL_BUFFER_SIZE = 256;
|
||||
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
|
||||
int payloadSize = 0; // This will be updated with the length of the data we get from the server
|
||||
String payload; // This will store the data we get from the server
|
||||
|
||||
// Assemble the URL
|
||||
// Note the slash after the first %s (assistNowServer)
|
||||
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s%s%s",
|
||||
assistNowServer,
|
||||
getQuery,
|
||||
tokenPrefix,
|
||||
myAssistNowToken,
|
||||
tokenSuffix,
|
||||
getGNSS,
|
||||
getFormat,
|
||||
getPeriod,
|
||||
getMgaResolution
|
||||
);
|
||||
|
||||
Serial.print(F("HTTP URL is: "));
|
||||
Serial.println(theURL);
|
||||
|
||||
HTTPClient http;
|
||||
|
||||
http.begin(theURL);
|
||||
|
||||
int httpCode = http.GET(); // HTTP GET
|
||||
|
||||
// httpCode will be negative on error
|
||||
if(httpCode > 0)
|
||||
{
|
||||
// HTTP header has been sent and Server response header has been handled
|
||||
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
|
||||
|
||||
// If the GET was successful, read the data
|
||||
if(httpCode == HTTP_CODE_OK) // Check for code 200
|
||||
{
|
||||
payloadSize = http.getSize();
|
||||
Serial.printf("Server returned %d bytes\r\n", payloadSize);
|
||||
|
||||
payload = http.getString(); // Get the payload
|
||||
|
||||
// Pretty-print the payload as HEX
|
||||
/*
|
||||
int i;
|
||||
for(i = 0; i < payloadSize; i++)
|
||||
{
|
||||
if (payload[i] < 0x10) // Print leading zero
|
||||
Serial.print("0");
|
||||
Serial.print(payload[i], HEX);
|
||||
Serial.print(" ");
|
||||
if ((i % 16) == 15)
|
||||
Serial.println();
|
||||
}
|
||||
if ((i % 16) != 15)
|
||||
Serial.println();
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
|
||||
}
|
||||
|
||||
http.end();
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Find where the AssistNow data for today starts and ends
|
||||
|
||||
size_t todayStart = 0; // Default to sending all the data
|
||||
size_t tomorrowStart = (size_t)payloadSize;
|
||||
|
||||
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
|
||||
//myGNSS.enableDebugging(Serial, true);
|
||||
|
||||
if (payloadSize > 0)
|
||||
{
|
||||
if(getLocalTime(&timeinfo))
|
||||
{
|
||||
// Find the start of today's data
|
||||
todayStart = myGNSS.findMGAANOForDate(payload, (size_t)payloadSize, timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday);
|
||||
if (todayStart < (size_t)payloadSize)
|
||||
{
|
||||
Serial.print(F("Found the data for today starting at location "));
|
||||
Serial.println(todayStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Could not find the data for today. This will not work well. The GNSS needs help to start up quickly.");
|
||||
}
|
||||
|
||||
// Find the start of tomorrow's data
|
||||
tomorrowStart = myGNSS.findMGAANOForDate(payload, (size_t)payloadSize, timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, 1);
|
||||
if (tomorrowStart < (size_t)payloadSize)
|
||||
{
|
||||
Serial.print(F("Found the data for tomorrow starting at location "));
|
||||
Serial.println(tomorrowStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Could not find the data for tomorrow. (Today's data may be the last?)");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
|
||||
}
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Push the RTC time to the module
|
||||
|
||||
if(getLocalTime(&timeinfo)) // Get the local time again, just to make sure we are using the most accurate time
|
||||
{
|
||||
// setUTCTimeAssistance uses a default time accuracy of 2 seconds which should be OK here.
|
||||
// Have a look at the library source code for more details.
|
||||
myGNSS.setUTCTimeAssistance(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
|
||||
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Push the AssistNow data for today to the module - without the time
|
||||
|
||||
if (payloadSize > 0)
|
||||
{
|
||||
|
||||
#ifndef USE_MGA_ACKs
|
||||
|
||||
// ***** Don't use the UBX_MGA_ACK_DATA0 messages *****
|
||||
|
||||
// Push the AssistNow data for today. Don't use UBX_MGA_ACK_DATA0's. Use the default delay of 7ms between messages.
|
||||
myGNSS.pushAssistNowData(todayStart, true, payload, tomorrowStart - todayStart);
|
||||
|
||||
#else
|
||||
|
||||
// ***** Use the UBX_MGA_ACK_DATA0 messages *****
|
||||
|
||||
// Tell the module to return UBX_MGA_ACK_DATA0 messages when we push the AssistNow data
|
||||
myGNSS.setAckAiding(1);
|
||||
|
||||
// Speed things up by setting setI2CpollingWait to 1ms
|
||||
myGNSS.setI2CpollingWait(1);
|
||||
|
||||
// Push the AssistNow data for today.
|
||||
myGNSS.pushAssistNowData(todayStart, true, payload, tomorrowStart - todayStart, SFE_UBLOX_MGA_ASSIST_ACK_YES, 100);
|
||||
|
||||
// Set setI2CpollingWait to 125ms to avoid pounding the I2C bus
|
||||
myGNSS.setI2CpollingWait(125);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Disconnect the WiFi as it's no longer needed
|
||||
|
||||
WiFi.disconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
Serial.println(F("WiFi disconnected"));
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
byte fixType = myGNSS.getFixType();
|
||||
Serial.print(F(" Fix: "));
|
||||
if(fixType == 0) Serial.print(F("No fix"));
|
||||
else if(fixType == 1) Serial.print(F("Dead reckoning"));
|
||||
else if(fixType == 2) Serial.print(F("2D"));
|
||||
else if(fixType == 3) Serial.print(F("3D"));
|
||||
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
|
||||
else if(fixType == 5) Serial.print(F("Time only"));
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
//Your WiFi credentials
|
||||
const char ssid[] = "TRex";
|
||||
const char password[] = "hasBigTeeth";
|
||||
|
||||
//Your AssistNow token
|
||||
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";
|
||||
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
Use ESP32 WiFi to get AssistNow Online data from u-blox Thingstream
|
||||
By: SparkFun Electronics / Paul Clark
|
||||
Date: November 24th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to obtain AssistNow Online data from u-blox Thingstream over WiFi
|
||||
and push it over I2C to a u-blox module.
|
||||
|
||||
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
|
||||
|
||||
Update secrets.h with your:
|
||||
- WiFi credentials
|
||||
- AssistNow token string
|
||||
|
||||
Uncomment the "#define USE_MGA_ACKs" below to test the more robust method of using the
|
||||
UBX_MGA_ACK_DATA0 acknowledgements to confirm that each MGA message has been accepted.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
|
||||
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
//#define USE_MGA_ACKs // Uncomment this line to use the UBX_MGA_ACK_DATA0 acknowledgements
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include "secrets.h"
|
||||
|
||||
const char assistNowServer[] = "https://online-live1.services.u-blox.com";
|
||||
//const char assistNowServer[] = "https://online-live2.services.u-blox.com"; // Alternate server
|
||||
|
||||
const char getQuery[] = "GetOnlineData.ashx?";
|
||||
const char tokenPrefix[] = "token=";
|
||||
const char tokenSuffix[] = ";";
|
||||
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
|
||||
const char getDataType[] = "datatype=eph,alm,aux;"; // Data type can be: eph,alm,aux,pos
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void setup()
|
||||
{
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("AssistNow Example"));
|
||||
|
||||
while (Serial.available()) Serial.read(); // Empty the serial buffer
|
||||
Serial.println(F("Press any key to begin..."));
|
||||
while (!Serial.available()); // Wait for a keypress
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Start I2C. Connect to the GNSS.
|
||||
|
||||
Wire.begin(); //Start I2C
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
Serial.println(F("u-blox module connected"));
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Connect to WiFi.
|
||||
|
||||
Serial.print(F("Connecting to local WiFi"));
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(F("."));
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
Serial.println(F("WiFi connected!"));
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Use HTTP GET to receive the AssistNow_Online data
|
||||
|
||||
const int URL_BUFFER_SIZE = 256;
|
||||
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
|
||||
int payloadSize = 0; // This will be updated with the length of the data we get from the server
|
||||
String payload; // This will store the data we get from the server
|
||||
|
||||
// Assemble the URL
|
||||
// Note the slash after the first %s (assistNowServer)
|
||||
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s",
|
||||
assistNowServer,
|
||||
getQuery,
|
||||
tokenPrefix,
|
||||
myAssistNowToken,
|
||||
tokenSuffix,
|
||||
getGNSS,
|
||||
getDataType);
|
||||
|
||||
Serial.print(F("HTTP URL is: "));
|
||||
Serial.println(theURL);
|
||||
|
||||
HTTPClient http;
|
||||
|
||||
http.begin(theURL);
|
||||
|
||||
int httpCode = http.GET(); // HTTP GET
|
||||
|
||||
// httpCode will be negative on error
|
||||
if(httpCode > 0)
|
||||
{
|
||||
// HTTP header has been sent and Server response header has been handled
|
||||
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
|
||||
|
||||
// If the GET was successful, read the data
|
||||
if(httpCode == HTTP_CODE_OK) // Check for code 200
|
||||
{
|
||||
payloadSize = http.getSize();
|
||||
Serial.printf("Server returned %d bytes\r\n", payloadSize);
|
||||
|
||||
payload = http.getString(); // Get the payload
|
||||
|
||||
// Pretty-print the payload as HEX
|
||||
/*
|
||||
int i;
|
||||
for(i = 0; i < payloadSize; i++)
|
||||
{
|
||||
if (payload[i] < 0x10) // Print leading zero
|
||||
Serial.print("0");
|
||||
Serial.print(payload[i], HEX);
|
||||
Serial.print(" ");
|
||||
if ((i % 16) == 15)
|
||||
Serial.println();
|
||||
}
|
||||
if ((i % 16) != 15)
|
||||
Serial.println();
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
|
||||
}
|
||||
|
||||
http.end();
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Push the AssistNow data to the module
|
||||
|
||||
if (payloadSize > 0)
|
||||
{
|
||||
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
|
||||
//myGNSS.enableDebugging(Serial, true);
|
||||
|
||||
#ifndef USE_MGA_ACKs
|
||||
|
||||
// ***** Don't use the UBX_MGA_ACK_DATA0 messages *****
|
||||
|
||||
// Push all the AssistNow data. Don't use UBX_MGA_ACK_DATA0's. Use the default delay of 7ms between messages.
|
||||
myGNSS.pushAssistNowData(payload, (size_t)payloadSize);
|
||||
|
||||
#else
|
||||
|
||||
// ***** Use the UBX_MGA_ACK_DATA0 messages *****
|
||||
|
||||
// Tell the module to return UBX_MGA_ACK_DATA0 messages when we push the AssistNow data
|
||||
myGNSS.setAckAiding(1);
|
||||
|
||||
// Speed things up by setting setI2CpollingWait to 1ms
|
||||
myGNSS.setI2CpollingWait(1);
|
||||
|
||||
// Push all the AssistNow data.
|
||||
// We have called setAckAiding(1) to instruct the module to return MGA-ACK messages.
|
||||
// So, we could set the pushAssistNowData mgaAck parameter to SFE_UBLOX_MGA_ASSIST_ACK_YES.
|
||||
// But, just for giggles, let's use SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE just to confirm that the
|
||||
// MGA-ACK messages are actually enabled.
|
||||
// Wait for up to 100ms for each ACK to arrive! 100ms is a bit excessive... 7ms is nearer the mark.
|
||||
myGNSS.pushAssistNowData(payload, (size_t)payloadSize, SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE, 100);
|
||||
|
||||
// Set setI2CpollingWait to 125ms to avoid pounding the I2C bus
|
||||
myGNSS.setI2CpollingWait(125);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
Serial.println(F("Here we go!"));
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
byte fixType = myGNSS.getFixType();
|
||||
Serial.print(F(" Fix: "));
|
||||
if(fixType == 0) Serial.print(F("No fix"));
|
||||
else if(fixType == 1) Serial.print(F("Dead reckoning"));
|
||||
else if(fixType == 2) Serial.print(F("2D"));
|
||||
else if(fixType == 3) Serial.print(F("3D"));
|
||||
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
|
||||
else if(fixType == 5) Serial.print(F("Time only"));
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
//Your WiFi credentials
|
||||
const char ssid[] = "TRex";
|
||||
const char password[] = "hasBigTeeth";
|
||||
|
||||
//Your AssistNow token
|
||||
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
Use ESP32 WiFi to get AssistNow Online data from u-blox Thingstream
|
||||
By: SparkFun Electronics / Paul Clark
|
||||
Date: November 24th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to obtain AssistNow Online data from u-blox Thingstream over WiFi
|
||||
and push it over I2C to a u-blox module.
|
||||
|
||||
The AssistNow Online data is valid for 2-4 hours, so it can be re-used.
|
||||
BUT you need to provide the time assistance separately.
|
||||
This example shows how to do that.
|
||||
The ESP32's RTC is set from network time.
|
||||
The RTC time is pushed to the module using setUTCTimeAssistance,
|
||||
followed by the AssistNow data (without time).
|
||||
|
||||
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
|
||||
|
||||
Update secrets.h with your:
|
||||
- WiFi credentials
|
||||
- AssistNow token string
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
|
||||
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include "secrets.h"
|
||||
|
||||
const char assistNowServer[] = "https://online-live1.services.u-blox.com";
|
||||
//const char assistNowServer[] = "https://online-live2.services.u-blox.com"; // Alternate server
|
||||
|
||||
const char getQuery[] = "GetOnlineData.ashx?";
|
||||
const char tokenPrefix[] = "token=";
|
||||
const char tokenSuffix[] = ";";
|
||||
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
|
||||
const char getDataType[] = "datatype=eph,alm,aux;"; // Data type can be: eph,alm,aux,pos
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
#include "time.h"
|
||||
|
||||
const char* ntpServer = "pool.ntp.org"; // The Network Time Protocol Server
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void setup()
|
||||
{
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("AssistNow Example"));
|
||||
|
||||
while (Serial.available()) Serial.read(); // Empty the serial buffer
|
||||
Serial.println(F("Press any key to begin..."));
|
||||
while (!Serial.available()); // Wait for a keypress
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Start I2C. Connect to the GNSS.
|
||||
|
||||
Wire.begin(); //Start I2C
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
Serial.println(F("u-blox module connected"));
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Connect to WiFi.
|
||||
|
||||
Serial.print(F("Connecting to local WiFi"));
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(F("."));
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
Serial.println(F("WiFi connected!"));
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Set the RTC using network time. (Code taken from the SimpleTime example.)
|
||||
|
||||
// Request the time from the NTP server and use it to set the ESP32's RTC.
|
||||
configTime(0, 0, ntpServer); // Set the GMT and daylight offsets to zero. We need UTC, not local time.
|
||||
|
||||
struct tm timeinfo;
|
||||
if(!getLocalTime(&timeinfo))
|
||||
{
|
||||
Serial.println("Failed to obtain time");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(&timeinfo, "Time is: %A, %B %d %Y %H:%M:%S");
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Use HTTP GET to receive the AssistNow_Online data
|
||||
|
||||
const int URL_BUFFER_SIZE = 256;
|
||||
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
|
||||
int payloadSize = 0; // This will be updated with the length of the data we get from the server
|
||||
String payload; // This will store the data we get from the server
|
||||
|
||||
// Assemble the URL
|
||||
// Note the slash after the first %s (assistNowServer)
|
||||
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s",
|
||||
assistNowServer,
|
||||
getQuery,
|
||||
tokenPrefix,
|
||||
myAssistNowToken,
|
||||
tokenSuffix,
|
||||
getGNSS,
|
||||
getDataType);
|
||||
|
||||
Serial.print(F("HTTP URL is: "));
|
||||
Serial.println(theURL);
|
||||
|
||||
HTTPClient http;
|
||||
|
||||
http.begin(theURL);
|
||||
|
||||
int httpCode = http.GET(); // HTTP GET
|
||||
|
||||
// httpCode will be negative on error
|
||||
if(httpCode > 0)
|
||||
{
|
||||
// HTTP header has been sent and Server response header has been handled
|
||||
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
|
||||
|
||||
// If the GET was successful, read the data
|
||||
if(httpCode == HTTP_CODE_OK) // Check for code 200
|
||||
{
|
||||
payloadSize = http.getSize();
|
||||
Serial.printf("Server returned %d bytes\r\n", payloadSize);
|
||||
|
||||
payload = http.getString(); // Get the payload
|
||||
|
||||
// Pretty-print the payload as HEX
|
||||
/*
|
||||
int i;
|
||||
for(i = 0; i < payloadSize; i++)
|
||||
{
|
||||
if (payload[i] < 0x10) // Print leading zero
|
||||
Serial.print("0");
|
||||
Serial.print(payload[i], HEX);
|
||||
Serial.print(" ");
|
||||
if ((i % 16) == 15)
|
||||
Serial.println();
|
||||
}
|
||||
if ((i % 16) != 15)
|
||||
Serial.println();
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
|
||||
}
|
||||
|
||||
http.end();
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Push the RTC time to the module
|
||||
|
||||
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
|
||||
//myGNSS.enableDebugging(Serial, true);
|
||||
|
||||
if(getLocalTime(&timeinfo))
|
||||
{
|
||||
// setUTCTimeAssistance uses a default time accuracy of 2 seconds which should be OK here.
|
||||
// Have a look at the library source code for more details.
|
||||
myGNSS.setUTCTimeAssistance(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
|
||||
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Push the AssistNow data to the module - WITHOUT THE TIME
|
||||
|
||||
if (payloadSize > 0)
|
||||
{
|
||||
// Push the AssistNow data. Don't use UBX_MGA_ACK_DATA0's. Use the default delay of 7ms between messages.
|
||||
// The 'true' parameter tells pushAssistNowData not to push any time data from the payload.
|
||||
myGNSS.pushAssistNowData(true, payload, (size_t)payloadSize);
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Disconnect the WiFi as it's no longer needed
|
||||
|
||||
WiFi.disconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
Serial.println(F("WiFi disconnected"));
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
byte fixType = myGNSS.getFixType();
|
||||
Serial.print(F(" Fix: "));
|
||||
if(fixType == 0) Serial.print(F("No fix"));
|
||||
else if(fixType == 1) Serial.print(F("Dead reckoning"));
|
||||
else if(fixType == 2) Serial.print(F("2D"));
|
||||
else if(fixType == 3) Serial.print(F("3D"));
|
||||
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
|
||||
else if(fixType == 5) Serial.print(F("Time only"));
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
//Your WiFi credentials
|
||||
const char ssid[] = "TRex";
|
||||
const char password[] = "hasBigTeeth";
|
||||
|
||||
//Your AssistNow token
|
||||
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
Use ESP32 WiFi to get AssistNow Online data from u-blox Thingstream
|
||||
By: SparkFun Electronics / Paul Clark
|
||||
Date: November 24th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to obtain AssistNow Online data from u-blox Thingstream over WiFi
|
||||
and push it over I2C to a u-blox module.
|
||||
|
||||
This example shows how to provide initial position assistance. Uncomment #define USE_SERVER_ASSISTANCE
|
||||
below to include the position in the AssistNow data request, instead of using setPositionAssistanceLLH.
|
||||
|
||||
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
|
||||
|
||||
Update secrets.h with your:
|
||||
- WiFi credentials
|
||||
- AssistNow token string
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
|
||||
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
//#define USE_SERVER_ASSISTANCE // Uncomment this line to include the position in the AssistNow data request
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include "secrets.h"
|
||||
|
||||
const char assistNowServer[] = "https://online-live1.services.u-blox.com";
|
||||
//const char assistNowServer[] = "https://online-live2.services.u-blox.com"; // Alternate server
|
||||
|
||||
const char getQuery[] = "GetOnlineData.ashx?";
|
||||
const char tokenPrefix[] = "token=";
|
||||
const char tokenSuffix[] = ";";
|
||||
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
|
||||
const char getDataType[] = "datatype=eph,alm,aux;"; // Data type can be: eph,alm,aux,pos
|
||||
|
||||
#ifdef USE_SERVER_ASSISTANCE
|
||||
const char useLatitude[] = "lat=55.0;"; // Use an approximate latitude of 55 degrees north. Replace this with your latitude.
|
||||
const char useLongitude[] = "lon=-1.0;"; // Use an approximate longitude of 1 degree west. Replace this with your longitude.
|
||||
const char useAlt[] = "alt=100;"; // Use an approximate latitude of 100m above WGS84. Replace this with your altitude.
|
||||
const char usePosAcc[] = "pacc=100000;"; // Use a position accuracy of 100000m (100km)
|
||||
#endif
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
#include "time.h"
|
||||
|
||||
const char* ntpServer = "pool.ntp.org"; // The Network Time Protocol Server
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void setup()
|
||||
{
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("AssistNow Example"));
|
||||
|
||||
while (Serial.available()) Serial.read(); // Empty the serial buffer
|
||||
Serial.println(F("Press any key to begin..."));
|
||||
while (!Serial.available()); // Wait for a keypress
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Start I2C. Connect to the GNSS.
|
||||
|
||||
Wire.begin(); //Start I2C
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
Serial.println(F("u-blox module connected"));
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Connect to WiFi.
|
||||
|
||||
Serial.print(F("Connecting to local WiFi"));
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(F("."));
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
Serial.println(F("WiFi connected!"));
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Set the RTC using network time. (Code taken from the SimpleTime example.)
|
||||
|
||||
// Request the time from the NTP server and use it to set the ESP32's RTC.
|
||||
configTime(0, 0, ntpServer); // Set the GMT and daylight offsets to zero. We need UTC, not local time.
|
||||
|
||||
struct tm timeinfo;
|
||||
if(!getLocalTime(&timeinfo))
|
||||
{
|
||||
Serial.println("Failed to obtain time");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(&timeinfo, "Time is: %A, %B %d %Y %H:%M:%S");
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Use HTTP GET to receive the AssistNow_Online data
|
||||
|
||||
const int URL_BUFFER_SIZE = 256;
|
||||
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
|
||||
int payloadSize = 0; // This will be updated with the length of the data we get from the server
|
||||
String payload; // This will store the data we get from the server
|
||||
|
||||
// Assemble the URL
|
||||
// Note the slash after the first %s (assistNowServer)
|
||||
#ifdef USE_SERVER_ASSISTANCE
|
||||
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s%s%s%s%s",
|
||||
assistNowServer,
|
||||
getQuery,
|
||||
tokenPrefix,
|
||||
myAssistNowToken,
|
||||
tokenSuffix,
|
||||
getGNSS,
|
||||
getDataType,
|
||||
useLatitude,
|
||||
useLongitude,
|
||||
useAlt,
|
||||
usePosAcc);
|
||||
#else
|
||||
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s",
|
||||
assistNowServer,
|
||||
getQuery,
|
||||
tokenPrefix,
|
||||
myAssistNowToken,
|
||||
tokenSuffix,
|
||||
getGNSS,
|
||||
getDataType);
|
||||
#endif
|
||||
|
||||
Serial.print(F("HTTP URL is: "));
|
||||
Serial.println(theURL);
|
||||
|
||||
HTTPClient http;
|
||||
|
||||
http.begin(theURL);
|
||||
|
||||
int httpCode = http.GET(); // HTTP GET
|
||||
|
||||
// httpCode will be negative on error
|
||||
if(httpCode > 0)
|
||||
{
|
||||
// HTTP header has been sent and Server response header has been handled
|
||||
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
|
||||
|
||||
// If the GET was successful, read the data
|
||||
if(httpCode == HTTP_CODE_OK) // Check for code 200
|
||||
{
|
||||
payloadSize = http.getSize();
|
||||
Serial.printf("Server returned %d bytes\r\n", payloadSize);
|
||||
|
||||
payload = http.getString(); // Get the payload
|
||||
|
||||
// Pretty-print the payload as HEX
|
||||
/*
|
||||
int i;
|
||||
for(i = 0; i < payloadSize; i++)
|
||||
{
|
||||
if (payload[i] < 0x10) // Print leading zero
|
||||
Serial.print("0");
|
||||
Serial.print(payload[i], HEX);
|
||||
Serial.print(" ");
|
||||
if ((i % 16) == 15)
|
||||
Serial.println();
|
||||
}
|
||||
if ((i % 16) != 15)
|
||||
Serial.println();
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
|
||||
}
|
||||
|
||||
http.end();
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Speed things up by setting setI2CpollingWait to 1ms
|
||||
myGNSS.setI2CpollingWait(1);
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Tell the module to return UBX_MGA_ACK_DATA0 messages when we push the AssistNow data
|
||||
myGNSS.setAckAiding(1);
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Push the RTC time to the module
|
||||
|
||||
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
|
||||
//myGNSS.enableDebugging(Serial, true);
|
||||
|
||||
if(getLocalTime(&timeinfo))
|
||||
{
|
||||
// Provide time assistance. Use the UBX_MGA_ACK_DATA0 acknowledgements. Set tAccS to 2 seconds.
|
||||
myGNSS.setUTCTimeAssistance(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
|
||||
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, 0, 2, 0, 0, SFE_UBLOX_MGA_ASSIST_ACK_YES, 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// If desired - push initial position assistance to the module
|
||||
|
||||
#ifndef USE_SERVER_ASSISTANCE
|
||||
|
||||
// Use 55 degrees (*10^7) north, 1 degree (*10^7) west, 100m (10000cm) altitude, 100km (10000000cm) accuracy. Replace these with your position.
|
||||
// The units for lat and lon are degrees * 1e-7 (WGS84)
|
||||
// The units for alt (WGS84) and posAcc (stddev) are cm.
|
||||
myGNSS.setPositionAssistanceLLH(550000000, -10000000, 10000, 10000000, SFE_UBLOX_MGA_ASSIST_ACK_YES, 100);
|
||||
|
||||
// We could use setPositionAssistanceXYZ instead if needed.
|
||||
|
||||
#endif
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Push the AssistNow data to the module - WITHOUT THE TIME
|
||||
|
||||
if (payloadSize > 0)
|
||||
{
|
||||
// Push the AssistNow data. Use the UBX_MGA_ACK_DATA0 acknowledgements.
|
||||
// The 'true' parameter tells pushAssistNowData not to push any time data from the payload.
|
||||
myGNSS.pushAssistNowData(true, payload, (size_t)payloadSize, SFE_UBLOX_MGA_ASSIST_ACK_YES, 100);
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Disconnect the WiFi as it's no longer needed
|
||||
|
||||
WiFi.disconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
Serial.println(F("WiFi disconnected"));
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Avoid pounding the I2C bus by setting setI2CpollingWait to 125ms
|
||||
myGNSS.setI2CpollingWait(125);
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
byte fixType = myGNSS.getFixType();
|
||||
Serial.print(F(" Fix: "));
|
||||
if(fixType == 0) Serial.print(F("No fix"));
|
||||
else if(fixType == 1) Serial.print(F("Dead reckoning"));
|
||||
else if(fixType == 2) Serial.print(F("2D"));
|
||||
else if(fixType == 3) Serial.print(F("3D"));
|
||||
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
|
||||
else if(fixType == 5) Serial.print(F("Time only"));
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
//Your WiFi credentials
|
||||
const char ssid[] = "TRex";
|
||||
const char password[] = "hasBigTeeth";
|
||||
|
||||
//Your AssistNow token
|
||||
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
Use ESP32 WiFi to get AssistNow Online data from u-blox Thingstream
|
||||
By: SparkFun Electronics / Paul Clark
|
||||
Date: November 24th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to obtain AssistNow Online data from u-blox Thingstream over WiFi
|
||||
and push it to a u-blox module using Serial.
|
||||
|
||||
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
|
||||
|
||||
Update secrets.h with your:
|
||||
- WiFi credentials
|
||||
- AssistNow token string
|
||||
|
||||
Uncomment the "#define USE_MGA_ACKs" below to test the more robust method of using the
|
||||
UBX_MGA_ACK_DATA0 acknowledgements to confirm that each MGA message has been accepted.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
|
||||
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
//#define USE_MGA_ACKs // Uncomment this line to use the UBX_MGA_ACK_DATA0 acknowledgements
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include "secrets.h"
|
||||
|
||||
const char assistNowServer[] = "https://online-live1.services.u-blox.com";
|
||||
//const char assistNowServer[] = "https://online-live2.services.u-blox.com"; // Alternate server
|
||||
|
||||
const char getQuery[] = "GetOnlineData.ashx?";
|
||||
const char tokenPrefix[] = "token=";
|
||||
const char tokenSuffix[] = ";";
|
||||
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
|
||||
const char getDataType[] = "datatype=eph,alm,aux;"; // Data type can be: eph,alm,aux,pos
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
#define mySerial Serial1 // Use Serial1 to communicate with the GNSS module
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void setup()
|
||||
{
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("AssistNow Example"));
|
||||
|
||||
while (Serial.available()) Serial.read(); // Empty the serial buffer
|
||||
Serial.println(F("Press any key to begin..."));
|
||||
while (!Serial.available()); // Wait for a keypress
|
||||
|
||||
mySerial.begin(9600); // Use 9600 baud (for u-blox M8)
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Connect to the GNSS.
|
||||
|
||||
if (myGNSS.begin(mySerial) == false) //Connect to the Ublox module using mySerial
|
||||
{
|
||||
Serial.println(F("u-blox GPS not detected. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
Serial.println(F("u-blox module connected"));
|
||||
|
||||
myGNSS.setUART1Output(COM_TYPE_UBX); //Set the UART port to output UBX only
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Connect to WiFi.
|
||||
|
||||
Serial.print(F("Connecting to local WiFi"));
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(F("."));
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
Serial.println(F("WiFi connected!"));
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Use HTTP GET to receive the AssistNow_Online data
|
||||
|
||||
const int URL_BUFFER_SIZE = 256;
|
||||
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
|
||||
int payloadSize = 0; // This will be updated with the length of the data we get from the server
|
||||
String payload; // This will store the data we get from the server
|
||||
|
||||
// Assemble the URL
|
||||
// Note the slash after the first %s (assistNowServer)
|
||||
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s",
|
||||
assistNowServer,
|
||||
getQuery,
|
||||
tokenPrefix,
|
||||
myAssistNowToken,
|
||||
tokenSuffix,
|
||||
getGNSS,
|
||||
getDataType);
|
||||
|
||||
Serial.print(F("HTTP URL is: "));
|
||||
Serial.println(theURL);
|
||||
|
||||
HTTPClient http;
|
||||
|
||||
http.begin(theURL);
|
||||
|
||||
int httpCode = http.GET(); // HTTP GET
|
||||
|
||||
// httpCode will be negative on error
|
||||
if(httpCode > 0)
|
||||
{
|
||||
// HTTP header has been sent and Server response header has been handled
|
||||
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
|
||||
|
||||
// If the GET was successful, read the data
|
||||
if(httpCode == HTTP_CODE_OK) // Check for code 200
|
||||
{
|
||||
payloadSize = http.getSize();
|
||||
Serial.printf("Server returned %d bytes\r\n", payloadSize);
|
||||
|
||||
payload = http.getString(); // Get the payload
|
||||
|
||||
// Pretty-print the payload as HEX
|
||||
/*
|
||||
int i;
|
||||
for(i = 0; i < payloadSize; i++)
|
||||
{
|
||||
if (payload[i] < 0x10) // Print leading zero
|
||||
Serial.print("0");
|
||||
Serial.print(payload[i], HEX);
|
||||
Serial.print(" ");
|
||||
if ((i % 16) == 15)
|
||||
Serial.println();
|
||||
}
|
||||
if ((i % 16) != 15)
|
||||
Serial.println();
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
|
||||
}
|
||||
|
||||
http.end();
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Push the AssistNow data to the module
|
||||
|
||||
if (payloadSize > 0)
|
||||
{
|
||||
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
|
||||
//myGNSS.enableDebugging(Serial, true);
|
||||
|
||||
#ifndef USE_MGA_ACKs
|
||||
|
||||
// ***** Don't use the UBX_MGA_ACK_DATA0 messages *****
|
||||
|
||||
// Push all the AssistNow data. Don't use UBX_MGA_ACK_DATA0's. Use the default delay of 7ms between messages.
|
||||
myGNSS.pushAssistNowData(payload, (size_t)payloadSize);
|
||||
|
||||
#else
|
||||
|
||||
// ***** Use the UBX_MGA_ACK_DATA0 messages *****
|
||||
|
||||
// Tell the module to return UBX_MGA_ACK_DATA0 messages when we push the AssistNow data
|
||||
myGNSS.setAckAiding(1);
|
||||
|
||||
// Push all the AssistNow data.
|
||||
// We have called setAckAiding(1) to instruct the module to return MGA-ACK messages.
|
||||
// So, we could set the pushAssistNowData mgaAck parameter to SFE_UBLOX_MGA_ASSIST_ACK_YES.
|
||||
// But, just for giggles, let's use SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE just to confirm that the
|
||||
// MGA-ACK messages are actually enabled.
|
||||
// Wait for up to 100ms for each ACK to arrive! 100ms is a bit excessive... 7ms is nearer the mark.
|
||||
myGNSS.pushAssistNowData(payload, (size_t)payloadSize, SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE, 100);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
Serial.println(F("Here we go!"));
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
byte fixType = myGNSS.getFixType();
|
||||
Serial.print(F(" Fix: "));
|
||||
if(fixType == 0) Serial.print(F("No fix"));
|
||||
else if(fixType == 1) Serial.print(F("Dead reckoning"));
|
||||
else if(fixType == 2) Serial.print(F("2D"));
|
||||
else if(fixType == 3) Serial.print(F("3D"));
|
||||
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
|
||||
else if(fixType == 5) Serial.print(F("Time only"));
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
//Your WiFi credentials
|
||||
const char ssid[] = "TRex";
|
||||
const char password[] = "hasBigTeeth";
|
||||
|
||||
//Your AssistNow token
|
||||
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
Use ESP32 WiFi to get AssistNow Online (MGA) data from PointPerfect (broker) as a Client using MQTT
|
||||
By: Paul Clark / SparkFun
|
||||
Date: March 9th, 2022
|
||||
Based on original code by: u-blox AG / Michael Ammann
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to obtain AssistNow Online (MGA) data from a PointPerfect Broker over WiFi
|
||||
and push it over I2C to a ZED-F9x.
|
||||
It's confusing, but the Arduino is acting as a 'client' to the PointPerfect service.
|
||||
|
||||
You will need to have a valid u-blox Thingstream account and have a PointPerfect Thing and payed plan.
|
||||
To sign up, go to: https://portal.thingstream.io/app/location-services/things
|
||||
|
||||
This is a proof of concept to show how to connect via MQTT to get AssistNow MGA data.
|
||||
|
||||
For more information about MQTT, SPARTN and PointPerfect Correction Services
|
||||
please see: https://www.u-blox.com/en/product/pointperfect
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
|
||||
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <ArduinoMqttClient.h> // Click here to get the library: http://librarymanager/All#ArduinoMqttClient
|
||||
#include "secrets.h"
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> // Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
//Global variables
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
long lastReceived_ms = 0; //5 RTCM messages take approximately ~300ms to arrive at 115200bps
|
||||
int maxTimeBeforeHangup_ms = 10000; //If we fail to get a complete RTCM frame after 10s, then disconnect from caster
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println(F("PointPerfect AssistNow testing"));
|
||||
|
||||
Wire.begin(); //Start I2C
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
Serial.println(F("u-blox module connected"));
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
|
||||
myGNSS.setPortInput(COM_PORT_I2C, COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_SPARTN);
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Set output in Hz.
|
||||
|
||||
Serial.print(F("Connecting to local WiFi"));
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(F("."));
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("WiFi connected with IP: "));
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
while (Serial.available()) Serial.read();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (Serial.available())
|
||||
{
|
||||
beginClient();
|
||||
while (Serial.available()) Serial.read(); //Empty buffer of any newline chars
|
||||
}
|
||||
|
||||
Serial.println(F("Press any key to start MQTT Client."));
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFiClientSecure wifiClient = WiFiClientSecure();
|
||||
MqttClient mqttClient(wifiClient);
|
||||
|
||||
void mqttMessageHandler(int messageSize)
|
||||
{
|
||||
const uint16_t mqttLimit = 512;
|
||||
uint8_t *mqttData = new uint8_t[mqttLimit]; // Allocate memory to hold the MQTT data
|
||||
if (mqttData == NULL)
|
||||
{
|
||||
Serial.println(F("Memory allocation for mqttData failed!"));
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.print(F("Pushing data from "));
|
||||
Serial.print(mqttClient.messageTopic());
|
||||
Serial.println(F(" topic to ZED"));
|
||||
|
||||
while (mqttClient.available())
|
||||
{
|
||||
uint16_t mqttCount = 0;
|
||||
|
||||
while (mqttClient.available())
|
||||
{
|
||||
char ch = mqttClient.read();
|
||||
//Serial.write(ch); //Pipe to serial port is fine but beware, it's a lot of binary data
|
||||
mqttData[mqttCount++] = ch;
|
||||
|
||||
if (mqttCount == mqttLimit)
|
||||
break;
|
||||
}
|
||||
|
||||
if (mqttCount > 0)
|
||||
{
|
||||
//Push KEYS or SPARTN data to GNSS module over I2C
|
||||
myGNSS.pushRawData(mqttData, mqttCount, false);
|
||||
lastReceived_ms = millis();
|
||||
}
|
||||
}
|
||||
|
||||
delete[] mqttData;
|
||||
}
|
||||
|
||||
//Connect to MQTT broker, receive MGA, and push to ZED module over I2C
|
||||
void beginClient()
|
||||
{
|
||||
Serial.println(F("Subscribing to Broker. Press key to stop"));
|
||||
delay(10); //Wait for any serial to arrive
|
||||
while (Serial.available()) Serial.read(); //Flush
|
||||
|
||||
while (Serial.available() == 0)
|
||||
{
|
||||
//Connect if we are not already
|
||||
if (wifiClient.connected() == false)
|
||||
{
|
||||
// Connect to AWS IoT
|
||||
wifiClient.setCACert(AWS_CERT_CA);
|
||||
wifiClient.setCertificate(AWS_CERT_CRT);
|
||||
wifiClient.setPrivateKey(AWS_CERT_PRIVATE);
|
||||
mqttClient.setId(MQTT_CLIENT_ID);
|
||||
mqttClient.setKeepAliveInterval(60*1000);
|
||||
mqttClient.setConnectionTimeout( 5*1000);
|
||||
if (!mqttClient.connect(AWS_IOT_ENDPOINT, AWS_IOT_PORT)) {
|
||||
Serial.print(F("MQTT connection failed! Error code = "));
|
||||
Serial.println(mqttClient.connectError());
|
||||
return;
|
||||
} else {
|
||||
Serial.println(F("You're connected to the PointPerfect MQTT broker: "));
|
||||
Serial.println(AWS_IOT_ENDPOINT);
|
||||
// Subscribe to MQTT and register a callback
|
||||
Serial.println(F("Subscribe to Topics"));
|
||||
mqttClient.onMessage(mqttMessageHandler);
|
||||
mqttClient.subscribe(MQTT_TOPIC_ASSISTNOW);
|
||||
lastReceived_ms = millis();
|
||||
} //End attempt to connect
|
||||
} //End connected == false
|
||||
else {
|
||||
mqttClient.poll();
|
||||
}
|
||||
//Close socket if we don't have new data for 10s
|
||||
if (millis() - lastReceived_ms > maxTimeBeforeHangup_ms)
|
||||
{
|
||||
Serial.println(F("Timeout. Disconnecting..."));
|
||||
if (mqttClient.connected() == true)
|
||||
mqttClient.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
delay(10);
|
||||
}
|
||||
|
||||
Serial.println(F("User pressed a key"));
|
||||
Serial.println(F("Disconnecting..."));
|
||||
wifiClient.stop();
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
//Your WiFi credentials
|
||||
const char ssid[] = "<YOUR SSID>";
|
||||
const char password[] = "<YOUR PASSWORD>";
|
||||
|
||||
// Below infomation you can set after signing up with u-blox Thingstream portal
|
||||
// and after add a new New PointPerfect Thing
|
||||
// https://portal.thingstream.io/app/location-services/things
|
||||
// in the new PointPerfect Thing you go to the credentials page and copy past the values and certificate into this.
|
||||
|
||||
// <Your PointPerfect Thing> -> Credentials -> Hostname
|
||||
const char AWS_IOT_ENDPOINT[] = "pp.services.u-blox.com";
|
||||
const unsigned short AWS_IOT_PORT = 8883;
|
||||
// <Your PointPerfect Thing> -> Credentials -> AssistNow (MGA) topic
|
||||
const char MQTT_TOPIC_ASSISTNOW[] = "/pp/ubx/mga";
|
||||
|
||||
// <Your PointPerfect Thing> -> Credentials -> Client Id
|
||||
static const char MQTT_CLIENT_ID[] = "<ADD YOUR CLIENT ID HERE>";
|
||||
|
||||
// <Your PointPerfect Thing> -> Credentials -> Amazon Root Certificate
|
||||
static const char AWS_CERT_CA[] PROGMEM = R"EOF(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
<ADD YOUR CERTICICATE HERE>
|
||||
-----END CERTIFICATE-----
|
||||
)EOF";
|
||||
|
||||
// <Your PointPerfect Thing> -> Credentials -> Client Certificate
|
||||
static const char AWS_CERT_CRT[] PROGMEM = R"KEY(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
<ADD YOUR CERTICICATE HERE>
|
||||
-----END CERTIFICATE-----
|
||||
)KEY";
|
||||
|
||||
// Get this from Thingstream Portal
|
||||
// <Your PointPerfect Thing> -> Credentials -> Client Key
|
||||
static const char AWS_CERT_PRIVATE[] PROGMEM = R"KEY(
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
<ADD YOUR KEY HERE>
|
||||
-----END RSA PRIVATE KEY-----
|
||||
)KEY";
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
# SparkFun u-blox Arduino GNSS Library - AssistNow<sup>TM</sup>
|
||||
|
||||
v2.1.0 of the library adds support for u-blox [AssistNow<sup>TM</sup> Assisted GNSS (A-GNSS)](https://www.u-blox.com/en/product/assistnow) which can dramatically reduce the time-to-first-fix.
|
||||
|
||||
To use AssistNow Online or AssistNow Offline, you will need a token to access the u-blox Thingstream server. See [below](#AssistNow-Service-Token) for details.
|
||||
|
||||
## AssistNow<sup>TM</sup> Online
|
||||
|
||||
With AssistNow Online, an Internet connected host downloads assistance data from the u-blox AssistNow Online service to the receiver at system start-up. AssistNow Online data is valid for 2 - 4 hours; beyond that fresh data must be downloaded.
|
||||
|
||||
Please see the [AssistNow_Online](./AssistNow_Online) examples for more details. These examples were written for the ESP32, but will run on other platforms too.
|
||||
|
||||
The new functions we've added to the library to support AssistNow Online are described [Support for AssistNow below](#Support-for-AssistNow).
|
||||
|
||||
## AssistNow<sup>TM</sup> Offline
|
||||
|
||||
With the AssistNow Offline service, users can download long-term orbit data over the Internet at their convenience. The orbit data can be stored in the memory of the application processor. The function requires no connectivity at system start-up, enabling a position fix within seconds, even when no network is available. AssistNow Offline offers augmentation for up to 35 days.
|
||||
|
||||
Please see the [AssistNow_Offline](./AssistNow_Offline) examples for more details. These examples were written for the ESP32, but will run on other platforms too.
|
||||
|
||||
**Note: AssistNow Offline is not supported by the ZED-F9P. "The ZED-F9P supports AssistNow Online only."**
|
||||
|
||||
The new functions we've added to the library to support AssistNow Offline are described [Support for AssistNow](#Support-for-AssistNow) and [Additional Support for AssistNow Offline](#Additional-Support-for-AssistNow-Offline).
|
||||
|
||||
## AssistNow<sup>TM</sup> Autonomous
|
||||
|
||||
AssistNow Autonomous provides aiding information without the need for a host or external network connection. Based on previous broadcast satellite ephemeris data downloaded to and stored by the GNSS receiver, AssistNow Autonomous automatically generates accurate predictions of satellite orbital data (“AssistNow Autonomous data”) that is usable for future GNSS position fixes.
|
||||
|
||||
The benefits of AssistNow Autonomous are:
|
||||
|
||||
* Faster fix in situations where GNSS satellite signals are weak
|
||||
* No connectivity required
|
||||
* Compatible with AssistNow Online (can work stand-alone, or in tandem with AssistNow Online service)
|
||||
* No integration effort; calculations are done in the background, transparent to the user
|
||||
|
||||
AssistNow Autonomous offers augmentation for up to 6 days.
|
||||
|
||||
Please see the [AssistNow_Autonomous](./AssistNow_Autonomous) examples for more details.
|
||||
|
||||
**Note: AssistNow Autonomous does not work on the ZED-F9P. "The ZED-F9P supports AssistNow Online only."**
|
||||
|
||||
The new functions we've added to the library to support AssistNow Autonomous are described [Support for AssistNow Autonomous below](#Support-for-AssistNow-Autonomous).
|
||||
|
||||
## AssistNow Service Token
|
||||
|
||||
To be able to use AssistNow Online or AssistNow Offline, you will need a token to access the u-blox Thingstream server.
|
||||
|
||||
The following u-blox resources contain useful information:
|
||||
|
||||
* [AssistNow - u-blox A-GNSS services](https://www.u-blox.com/en/product/assistnow)
|
||||
* [AssistNow Product Summary](https://www.u-blox.com/sites/default/files/products/documents/AssistNow_ProductSummary_UBX-13003352.pdf)
|
||||
* [AssistNow User Guide](https://www.u-blox.com/sites/default/files/products/documents/MultiGNSS-Assistance_UserGuide_%28UBX-13004360%29.pdf)
|
||||
* [Thingstream Pricing](https://portal.thingstream.io/pricing)
|
||||
|
||||
You can apply for a _free_ AssistNow Service Evaluation Token by completing the request form:
|
||||
|
||||
* [AssistNow Service evaluation token request form](https://www.u-blox.com/en/assistnow-service-evaluation-token-request-form)
|
||||
|
||||
The _free_ AssistNow Developer token entitles you to:
|
||||
|
||||
* AssistNow Online Developer: 100K free location requests per month. Capped.
|
||||
* AssistNow Offline Developer: 20K free location requests per month. Capped.
|
||||
* CellLocate Developer: 5K free location requests per month. Capped.
|
||||
|
||||
The free token will expire after 90 days, but you can continue to use it beyond that by registering it on [Thingstream](https://portal.thingstream.io/).
|
||||
|
||||
## Initial Position Assistance
|
||||
|
||||
You can further decrease the time-to-first-fix by providing the receiver's approximate position - if known. There are two ways to do this:
|
||||
|
||||
* The position can be specified when requesting AssistNow Online data from the server:
|
||||
* include the key name ```lat``` with the approximate user latitude in WGS 84 expressed in degrees and fractional degrees. Must be in range -90 to 90. Example: ```lat=47.2;```
|
||||
* include the key name ```lon``` with the approximate user longitude in WGS 84 expressed in degrees and fractional degrees. Must be in range -180 to 180. Example: ```lon=8.55;```
|
||||
* include the key name ```alt``` with the approximate user altitude above WGS 84 Ellipsoid in meters. If this value is not provided, the server assumes an altitude of 0 meters. Must be in range -1000 to 50000
|
||||
* include the key name ```pacc``` with the approximate accuracy of submitted position in meters. If this value is not provided, the server assumes an accuracy of 300 km. Must be in range 0 to 6000000
|
||||
* the position assistance data will then be automatically included in the AssistNow Online data
|
||||
* Provide initial position assistance data by calling one of:
|
||||
* <b>bool setPositionAssistanceXYZ(int32_t ecefX, int32_t ecefY, int32_t ecefZ, uint32_t posAcc, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
|
||||
* The units for ```ecefX/Y/Z``` and ```posAcc``` (stddev) are cm
|
||||
* <b>bool setPositionAssistanceLLH(int32_t lat, int32_t lon, int32_t alt, uint32_t posAcc, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
|
||||
* The units for ```lat``` and ```lon``` are degrees * 1e-7 (WGS84). The units for ```alt``` (WGS84) and ```posAcc``` (stddev) are cm (not m)
|
||||
|
||||
## Support for AssistNow
|
||||
|
||||
```pushAssistNowData``` allows AssistNow Online, Offline or Autonomous data to be pushed to the module. As the ESP32 HTTP GET function returns a ```String```, we've included overloaded functions which allow you to pass the data as a ```String``` or as ```const uint8_t *```.
|
||||
|
||||
The String-based function declarations are:
|
||||
|
||||
* <b>size_t pushAssistNowData(const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
|
||||
* <b>size_t pushAssistNowData(bool skipTime, const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
|
||||
* <b>size_t pushAssistNowData(size_t offset, bool skipTime, const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
|
||||
|
||||
The const uint8_t * function declarations are:
|
||||
|
||||
* <b>size_t pushAssistNowData(const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
|
||||
* <b>size_t pushAssistNowData(bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
|
||||
* <b>size_t pushAssistNowData(size_t offset, bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
|
||||
|
||||
```dataBytes``` is a pointer to the AssistNow data.
|
||||
<br>
|
||||
```numDataBytes``` is the length of the AssistNow data.
|
||||
<br>
|
||||
|
||||
```pushAssistNowData``` pushes individual packets of data to the u-blox module. Sending all of the data contiguously would overload the module, so ```pushAssistNowData``` can either:
|
||||
|
||||
* insert a small delay between each packet (the default is 7ms)
|
||||
* or use the ```UBX-MGA-ACK-DATA0``` acknowledgement message to acknowledge each packet
|
||||
|
||||
```mgaAck``` controls which method is used.
|
||||
|
||||
* if ```mgaAck``` is ```SFE_UBLOX_MGA_ASSIST_ACK_NO``` (**default**), a delay of ```maxWait``` milliseconds is inserted between each packet. ```maxWait``` defaults to 7ms.
|
||||
* if ```mgaAck``` is ```SFE_UBLOX_MGA_ASSIST_ACK_YES```, acknowledgement messages will be expected with a _timeout_ of ```maxWait``` milliseconds. The default timeout is again 7ms, but you can change this if required by passing a different value.
|
||||
* if ```mgaAck``` is ```SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE```, the code will poll the module to enquire if the acknowledgement messages are enabled. If they are, they will be used. If not, a delay is used.
|
||||
|
||||
```setAckAiding``` enables or disables the acknowledgement messages. By default they are disabled. ```setAckAiding(1)``` will enable them. ```setAckAiding(0)``` will disable them again.
|
||||
|
||||
* <b>bool setAckAiding(uint8_t ackAiding, uint16_t maxWait);</b>
|
||||
|
||||
```getAckAiding``` returns 1 if the acknowledgement messages are enabled, 0 if they are disabled. 255 indicates an error or timeout.
|
||||
|
||||
* <b>uint8_t getAckAiding(uint16_t maxWait);</b>
|
||||
|
||||
```pushAssistNowData``` returns the number of _bytes_ pushed (not the number of _packets_). The return value should be equal to ```numDataBytes``` if all data was valid and pushed successfully.
|
||||
|
||||
AssistNow Online data is valid for 2-4 hours. 'Stale' data can be re-used but:
|
||||
|
||||
* ```pushAssistNowData``` needs to be told to skip the time information contained in the AssistNow data
|
||||
* the user needs to provide the module with UTC time separately
|
||||
|
||||
The ```skipTime``` parameter tells ```pushAssistNowData``` to skip any time information in the data. ```skipTime``` is bool. Set it to ```true``` to skip the time information.
|
||||
<br>
|
||||
|
||||
UTC time can be pushed to the module first by calling ```setUTCTimeAssistance```:
|
||||
|
||||
* <b>bool setUTCTimeAssistance(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t nanos, uint16_t tAccS, uint32_t tAccNs, uint8_t source, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
|
||||
|
||||
Only the ```year```, ```month```, ```day```, ```hour```, ```minute``` and ```second``` parameters are mandatory. The others default to sensible values. Again ```mgaAck``` and ```maxWait``` control if a delay is used when configuring the time, or if an acknowledgement message will be expected.
|
||||
<br>
|
||||
|
||||
```nanos``` (nanoseconds), ```tAccS``` (time accuracy estimate (seconds)), ```tAccNs``` (time accuracy estimate (nanoseconds)) and ```source``` (if a clock signal will be provided on EXT_INT) are optional, but are available for advanced users.
|
||||
<br>
|
||||
|
||||
```year``` numbering starts at 0; 2021 is 2021, not 121 (years since 1900). ```month``` and ```day``` numbering starts at 1, not 0.
|
||||
<br>
|
||||
|
||||
Call ```setUTCTimeAssistance``` _before_ ```pushAssistNowData```.
|
||||
|
||||
## Additional Support for AssistNow Offline
|
||||
|
||||
AssistNow Offline data downloaded from the u-blox server can contain 1-5 weeks of data. However, only the data for _today_ should be pushed the module. Sending data for past or future days will confuse the module.
|
||||
```findMGAANOForDate``` can be used to find the location of the start of the UBX-MGA-ANO data for the specified date within the offline data. That location can then be passed to ```pushAssistNowData``` using the ```offset``` parameter.
|
||||
|
||||
* <b>size_t findMGAANOForDate(const uint8_t *dataBytes, size_t numDataBytes, uint16_t year, uint8_t month, uint8_t day, uint8_t daysIntoFuture);</b>
|
||||
|
||||
The sequence of events is:
|
||||
|
||||
* call ```findMGAANOForDate``` passing the ```year```, ```month``` and ```day``` for today. ```findMGAANOForDate``` will return the location / offset of the data for today within the offline data.
|
||||
* call ```findMGAANOForDate``` again passing the ```year```, ```month``` and ```day``` for _today_ but also set ```daysIntoFuture``` to 1. ```findMGAANOForDate``` will then return the location / offset of the data for _tomorrow_ (one day into the future).
|
||||
* call ```pushAssistNowData``` setting:
|
||||
* ```offset``` to the location (offset) of today's data within the offline data
|
||||
* ```skipTime``` to ```true```
|
||||
* ```numDataBytes``` to ((tomorrow's location) - (today's location)). Only the offline data for today will be pushed.
|
||||
|
||||
```findMGAANOForDate``` will return a value of numDataBytes if the data for the chosen day cannot be found.
|
||||
<br>
|
||||
|
||||
Again, call ```setUTCTimeAssistance``` _before_ ```pushAssistNowData```.
|
||||
|
||||
## Support for AssistNow Autonomous
|
||||
|
||||
AssistNow Autonomous is disabled by default. You can enable it by calling ```setAopCfg``` and check if it is enabled by calling ```getAopCfg```:
|
||||
|
||||
* <b>uint8_t getAopCfg(uint16_t maxWait);</b>
|
||||
* <b>bool SFE_UBLOX_GNSS::setAopCfg(uint8_t aopCfg, uint16_t aopOrbMaxErr, uint16_t maxWait)</b>
|
||||
|
||||
```getAopCfg``` will return 1 if AssistNow Autonomous is enabled, 0 if disabled. 255 indicates an error or timeout.
|
||||
|
||||
```setAopCfg``` has two parameters:
|
||||
|
||||
* set ```aopCfg``` to 1 to enable AssistNow Autonomous, or 0 to disable it
|
||||
* ```aopOrbMaxErr``` is used to set the 'lifetime' of the AssistNow data. It is recommended to set aopOrbMaxErr to 0 (the default value). This instructs the module to use the firmware default value that corresponds to a default orbit data validity of approximately three days (for GPS satellites observed once) and up to six days (for GPS and GLONASS satellites observed multiple times over a period of at least half a day).
|
||||
|
||||
Once AssistNow Autonomous is enabled, you can monitor its status via the ```status``` field in the UBX-NAV-AOPSTATUS message. You can read the ```status``` by calling the helper function ```getAOPSTATUSstatus```. It will return zero when the AssistNow Autonomous data collection is idle. Non-zero values indicate that data collection is in progress. Only power-off the receiver when the subsystem is idle (that is, when the status shows a steady zero).
|
||||
|
||||
* <b>uint8_t getAOPSTATUSstatus(uint16_t maxWait);</b>
|
||||
* <b>uint8_t getAOPSTATUSuseAOP(uint16_t maxWait);</b>
|
||||
|
||||
We have included full 'auto' support for UBX-NAV-AOPSTATUS, so you can have the message delivered periodically, add a callback for it, and/or log it to the file buffer:
|
||||
|
||||
* <b>bool getAOPSTATUS(uint16_t maxWait);</b>
|
||||
* <b>bool setAutoAOPSTATUS(bool enabled, uint16_t maxWait);</b>
|
||||
* <b>bool setAutoAOPSTATUS(bool enabled, bool implicitUpdate, uint16_t maxWait);</b>
|
||||
* <b>bool setAutoAOPSTATUSrate(uint8_t rate, bool implicitUpdate, uint16_t maxWait);</b>
|
||||
* <b>bool setAutoAOPSTATUScallback(void (*callbackPointer)(UBX_NAV_AOPSTATUS_data_t), uint16_t maxWait);</b>
|
||||
* <b>bool assumeAutoAOPSTATUS(bool enabled, bool implicitUpdate);</b>
|
||||
* <b>void flushAOPSTATUS();</b>
|
||||
* <b>void logAOPSTATUS(bool enabled);</b>
|
||||
|
||||
You can also monitor the AssistNow Autonomous satellite information via the UBX-NAV-SAT message. Again, we have included full 'auto' support for UBX-NAV-SAT. UBX-NAV-SAT contains useful information for each individual satellite which the module has acquired: carrier to noise ratio (signal strength); elevation; azimuth; pseudorange residual; quality indication, health; ephemeris available; almanac available; **AssistNow Offline data availability**; and more. The data can be analyzed using a callback. Please see the AssistNowAutonomous examples for more details.
|
||||
|
||||
* <b>bool getNAVSAT(uint16_t maxWait);</b>
|
||||
* <b>bool setAutoNAVSAT(bool enabled, uint16_t maxWait);</b>
|
||||
* <b>bool setAutoNAVSAT(bool enabled, bool implicitUpdate, uint16_t maxWait);</b>
|
||||
* <b>bool setAutoNAVSATrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait);</b>
|
||||
* <b>bool setAutoNAVSATcallback(void (*callbackPointer)(UBX_NAV_NAVSAT_data_t), uint16_t maxWait);</b>
|
||||
* <b>bool assumeAutoNAVSAT(bool enabled, bool implicitUpdate);</b>
|
||||
* <b>void flushNAVSAT();</b>
|
||||
* <b>void logNAVSAT(bool enabled);</b>
|
||||
|
||||
The AssistNow Autonomous data is stored in the module's RAM memory. If that RAM is Battery-Backed - all SparkFun GNSS boards include battery back-up - then the data will be available after the module is powered down and powered back up again. However, you can also read (poll) the navigation database and store the contents in processor memory. ```readNavigationDatabase``` allows you to do that:
|
||||
|
||||
* <b>size_t readNavigationDatabase(uint8_t *dataBytes, size_t maxNumDataBytes, uint16_t maxWait);</b>
|
||||
|
||||
Data is written to ```dataBytes```. Set ```maxNumDataBytes``` to the (maximum) size of dataBytes. If the database exceeds maxNumDataBytes, the excess bytes will be lost.
|
||||
|
||||
```readNavigationDatabase``` returns the number of database bytes written to ```dataBytes```. The return value will be equal to ```maxNumDataBytes``` if excess data was received.
|
||||
|
||||
```readNavigationDatabase``` will timeout after ```maxWait``` milliseconds - in case the final UBX-MGA-ACK was missed.
|
||||
|
||||
You can then write the database back into the module using ```pushAssistNowData```. Don't forget to call ```setUTCTimeAssistance``` _before_ ```pushAssistNowData```.
|
||||
|
||||
Note: UBX-MGA-DBD messages are only intended to be sent back to the same receiver that generated them. They are firmware-specific.
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
Get the GPGGA NMEA sentence using getLatestNMEAGPGGA
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: January 12th, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
** Please note: this example will not run on Arduino Uno. See https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/blob/main/README.md#memory-usage
|
||||
|
||||
This example shows how to turn on/off the NMEA sentences being output over I2C.
|
||||
It then demonstrates how to use the new getLatestNMEAGPGGA function to retrieve the latest GPGGA message.
|
||||
getLatestNMEAGPGGA returns immediately - it is not blocking.
|
||||
It returns:
|
||||
0 if no data is available
|
||||
1 if the data is valid but is stale (you have read it before)
|
||||
2 if the data is valid and fresh
|
||||
|
||||
If the module is using multiple GNSS constellations, the GGA message will be prefixed with Talker ID "GN" instead of "GP".
|
||||
The library includes a getLatestNMEAGNGGA function too.
|
||||
This example shows how to use both functions - and how to change the Talker ID so the GNGGA messages become GPGGA.
|
||||
|
||||
This example turns off all sentences except for GGA.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a RedBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("SparkFun u-blox GNSS Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false)
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
//Disable or enable various NMEA sentences over the I2C interface
|
||||
myGNSS.setI2COutput(COM_TYPE_NMEA | COM_TYPE_UBX); // Turn on both UBX and NMEA sentences on I2C. (Turn off RTCM and SPARTN)
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C); // Several of these are on by default on ublox board so let's disable them
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C);
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C); // Leave only GGA enabled at current navigation rate
|
||||
|
||||
// Set the Main Talker ID to "GP". The NMEA GGA messages will be GPGGA instead of GNGGA
|
||||
myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_GP);
|
||||
//myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_DEFAULT); // Uncomment this line to restore the default main talker ID
|
||||
|
||||
myGNSS.setHighPrecisionMode(true); // Enable High Precision Mode - include extra decimal places in the GGA messages
|
||||
|
||||
//myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save only the ioPort and message settings to NVM
|
||||
|
||||
Serial.println(F("Messages configured"));
|
||||
|
||||
//myGNSS.setNMEAOutputPort(Serial); // Uncomment this line to echo all NMEA data to Serial for debugging
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// getLatestNMEAGPGGA calls checkUblox for us. We don't need to do it here
|
||||
|
||||
NMEA_GGA_data_t data; // Storage for the GPGGA data
|
||||
uint8_t result = myGNSS.getLatestNMEAGPGGA(&data); // Get the latest GPGGA data (if any)
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
Serial.println(F("No GPGGA data available"));
|
||||
}
|
||||
else if (result == 1)
|
||||
{
|
||||
Serial.println(F("GPGGA data is available but is stale"));
|
||||
}
|
||||
else // if (result == 2)
|
||||
{
|
||||
// Data contains .length and .nmea
|
||||
Serial.print(F("Latest GPGGA: Length: "));
|
||||
Serial.print(data.length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.println((const char *)data.nmea); // .nmea is printable (NULL-terminated)
|
||||
}
|
||||
|
||||
result = myGNSS.getLatestNMEAGNGGA(&data); // Get the latest GNGGA data (if any)
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
Serial.println(F("No GNGGA data available"));
|
||||
}
|
||||
else if (result == 1)
|
||||
{
|
||||
Serial.println(F("GNGGA data is available but is stale"));
|
||||
}
|
||||
else // if (result == 2)
|
||||
{
|
||||
// Data contains .length and .nmea
|
||||
Serial.print(F("Latest GNGGA: Length: "));
|
||||
Serial.print(data.length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.println((const char *)data.nmea); // .nmea is printable (NULL-terminated)
|
||||
}
|
||||
|
||||
delay(250);
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
Get the latest GPGGA / GNGGA NMEA sentence using callbacks
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: January 12th, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
** Please note: this example will not run on Arduino Uno. See https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/blob/main/README.md#memory-usage
|
||||
|
||||
This example shows how to turn on/off the NMEA sentences being output over I2C.
|
||||
It then demonstrates how to get the latest GPGGA or GNGGA message autonomously using callbacks.
|
||||
|
||||
If the module is using multiple GNSS constellations, the GGA message will be prefixed with Talker ID "GN" instead of "GP".
|
||||
This example shows how to change the Talker ID so the GNGGA messages become GPGGA.
|
||||
It also shows how to enable "high precision mode" to include extra decimal places in the GGA messages.
|
||||
|
||||
This example turns off all sentences except for GGA.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a RedBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
// Callback: printGPGGA will be called when new GPGGA NMEA data arrives
|
||||
// See u-blox_structs.h for the full definition of NMEA_GGA_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGPGGAcallback
|
||||
// / _____ This _must_ be NMEA_GGA_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printGPGGA(NMEA_GGA_data_t *nmeaData)
|
||||
{
|
||||
Serial.print(F("\r\nGPGGA: Length: "));
|
||||
Serial.print(nmeaData->length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
|
||||
}
|
||||
|
||||
// Callback: printGNGGA will be called if new GNGGA NMEA data arrives
|
||||
// See u-blox_structs.h for the full definition of NMEA_GGA_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGNGGAcallback
|
||||
// / _____ This _must_ be NMEA_GGA_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printGNGGA(NMEA_GGA_data_t *nmeaData)
|
||||
{
|
||||
Serial.print(F("\r\nGNGGA: Length: "));
|
||||
Serial.print(nmeaData->length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("SparkFun u-blox GNSS Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false)
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
// Disable or enable various NMEA sentences over the I2C interface
|
||||
myGNSS.setI2COutput(COM_TYPE_NMEA | COM_TYPE_UBX); // Turn on both UBX and NMEA sentences on I2C. (Turn off RTCM and SPARTN)
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C); // Several of these are on by default on ublox board so let's disable them
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C);
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C); // Leave only GGA enabled at current navigation rate
|
||||
|
||||
// Set the Main Talker ID to "GP". The NMEA GGA messages will be GPGGA instead of GNGGA
|
||||
myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_GP);
|
||||
//myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_DEFAULT); // Uncomment this line to restore the default main talker ID
|
||||
|
||||
myGNSS.setHighPrecisionMode(true); // Enable High Precision Mode - include extra decimal places in the GGA messages
|
||||
|
||||
//myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save only the ioPort and message settings to NVM
|
||||
|
||||
Serial.println(F("Messages configured"));
|
||||
|
||||
//myGNSS.setNMEAOutputPort(Serial); // Uncomment this line to echo all NMEA data to Serial for debugging
|
||||
|
||||
// Set up the callback for GPGGA
|
||||
myGNSS.setNMEAGPGGAcallbackPtr(&printGPGGA);
|
||||
|
||||
// Set up the callback for GNGGA
|
||||
myGNSS.setNMEAGNGGAcallbackPtr(&printGNGGA);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
Serial.print(".");
|
||||
delay(50);
|
||||
}
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
Get the NMEA sentence using getLatestNMEAGPxxx (GGA, VTG, RMC, ZDA)
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: March 2nd, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
** Please note: this example will not run on Arduino Uno. See https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/blob/main/README.md#memory-usage
|
||||
|
||||
This example shows how to turn on/off the NMEA sentences being output over I2C.
|
||||
It then demonstrates how to use the new getLatestNMEAGPxxx function to retrieve the latest GPGGA message.
|
||||
getLatestNMEAGPxxx returns immediately - it is not blocking.
|
||||
It returns:
|
||||
0 if no data is available
|
||||
1 if the data is valid but is stale (you have read it before)
|
||||
2 if the data is valid and fresh
|
||||
|
||||
If the module is using multiple GNSS constellations, the GGA message will be prefixed with Talker ID "GN" instead of "GP".
|
||||
The library includes getLatestNMEAGNxxx functions too.
|
||||
This example shows how to use both functions - and how to change the Talker ID so the GNGGA messages become GPGGA etc..
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a RedBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("SparkFun u-blox GNSS Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false)
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
//Disable or enable various NMEA sentences over the I2C interface
|
||||
myGNSS.setI2COutput(COM_TYPE_NMEA | COM_TYPE_UBX); // Turn on both UBX and NMEA sentences on I2C. (Turn off RTCM and SPARTN)
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C);
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C);
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C);
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C);
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_ZDA, COM_PORT_I2C);
|
||||
|
||||
// Set the Main Talker ID to "GP". The NMEA GGA messages will be GPGGA instead of GNGGA
|
||||
myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_GP);
|
||||
//myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_DEFAULT); // Uncomment this line to restore the default main talker ID
|
||||
|
||||
myGNSS.setHighPrecisionMode(true); // Enable High Precision Mode - include extra decimal places in the GGA messages
|
||||
|
||||
//myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save only the ioPort and message settings to NVM
|
||||
|
||||
Serial.println(F("Messages configured"));
|
||||
|
||||
//myGNSS.setNMEAOutputPort(Serial); // Uncomment this line to echo all NMEA data to Serial for debugging
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// getLatestNMEAGPGGA calls checkUblox for us. We don't need to do it here
|
||||
|
||||
NMEA_GGA_data_t dataGGA; // Storage for the GPGGA data
|
||||
uint8_t result = myGNSS.getLatestNMEAGPGGA(&dataGGA); // Get the latest GPGGA data (if any)
|
||||
|
||||
if (result == 2)
|
||||
{
|
||||
// Data contains .length and .nmea
|
||||
Serial.print(F("Latest GPGGA: Length: "));
|
||||
Serial.print(dataGGA.length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)dataGGA.nmea); // .nmea is printable (NULL-terminated)
|
||||
}
|
||||
|
||||
result = myGNSS.getLatestNMEAGNGGA(&dataGGA); // Get the latest GNGGA data (if any)
|
||||
|
||||
if (result == 2)
|
||||
{
|
||||
// Data contains .length and .nmea
|
||||
Serial.print(F("Latest GNGGA: Length: "));
|
||||
Serial.print(dataGGA.length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)dataGGA.nmea); // .nmea is printable (NULL-terminated)
|
||||
}
|
||||
|
||||
// getLatestNMEAGPVTG calls checkUblox for us. We don't need to do it here
|
||||
|
||||
NMEA_VTG_data_t dataVTG; // Storage for the GPVTG data
|
||||
result = myGNSS.getLatestNMEAGPVTG(&dataVTG); // Get the latest GPVTG data (if any)
|
||||
|
||||
if (result == 2)
|
||||
{
|
||||
// Data contains .length and .nmea
|
||||
Serial.print(F("Latest GPVTG: Length: "));
|
||||
Serial.print(dataVTG.length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)dataVTG.nmea); // .nmea is printable (NULL-terminated)
|
||||
}
|
||||
|
||||
result = myGNSS.getLatestNMEAGNVTG(&dataVTG); // Get the latest GNVTG data (if any)
|
||||
|
||||
if (result == 2)
|
||||
{
|
||||
// Data contains .length and .nmea
|
||||
Serial.print(F("Latest GNVTG: Length: "));
|
||||
Serial.print(dataVTG.length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)dataVTG.nmea); // .nmea is printable (NULL-terminated)
|
||||
}
|
||||
|
||||
// getLatestNMEAGPRMC calls checkUblox for us. We don't need to do it here
|
||||
|
||||
NMEA_RMC_data_t dataRMC; // Storage for the GPRMC data
|
||||
result = myGNSS.getLatestNMEAGPRMC(&dataRMC); // Get the latest GPRMC data (if any)
|
||||
|
||||
if (result == 2)
|
||||
{
|
||||
// Data contains .length and .nmea
|
||||
Serial.print(F("Latest GPRMC: Length: "));
|
||||
Serial.print(dataRMC.length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)dataRMC.nmea); // .nmea is printable (NULL-terminated)
|
||||
}
|
||||
|
||||
result = myGNSS.getLatestNMEAGNRMC(&dataRMC); // Get the latest GNRMC data (if any)
|
||||
|
||||
if (result == 2)
|
||||
{
|
||||
// Data contains .length and .nmea
|
||||
Serial.print(F("Latest GNRMC: Length: "));
|
||||
Serial.print(dataRMC.length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)dataRMC.nmea); // .nmea is printable (NULL-terminated)
|
||||
}
|
||||
|
||||
// getLatestNMEAGPZDA calls checkUblox for us. We don't need to do it here
|
||||
|
||||
NMEA_ZDA_data_t dataZDA; // Storage for the GPZDA data
|
||||
result = myGNSS.getLatestNMEAGPZDA(&dataZDA); // Get the latest GPZDA data (if any)
|
||||
|
||||
if (result == 2)
|
||||
{
|
||||
// Data contains .length and .nmea
|
||||
Serial.print(F("Latest GPZDA: Length: "));
|
||||
Serial.print(dataZDA.length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)dataZDA.nmea); // .nmea is printable (NULL-terminated)
|
||||
}
|
||||
|
||||
result = myGNSS.getLatestNMEAGNZDA(&dataZDA); // Get the latest GNZDA data (if any)
|
||||
|
||||
if (result == 2)
|
||||
{
|
||||
// Data contains .length and .nmea
|
||||
Serial.print(F("Latest GNZDA: Length: "));
|
||||
Serial.print(dataZDA.length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)dataZDA.nmea); // .nmea is printable (NULL-terminated)
|
||||
}
|
||||
|
||||
delay(250);
|
||||
}
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
Get the latest GGA, VTG, RMC, ZDA NMEA sentence using callbacks
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: March 2nd, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
** Please note: this example will not run on Arduino Uno. See https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/blob/main/README.md#memory-usage
|
||||
|
||||
This example shows how to turn on/off the NMEA sentences being output over I2C.
|
||||
It then demonstrates how to get the latest GGA, VTG, RMC or ZDA message autonomously using callbacks.
|
||||
|
||||
If the module is using multiple GNSS constellations, the GGA message will be prefixed with Talker ID "GN" instead of "GP".
|
||||
This example shows how to change the Talker ID so the GNGGA messages become GPGGA.
|
||||
It also shows how to enable "high precision mode" to include extra decimal places in the GGA messages.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a RedBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
// Callback: printGPGGA will be called when new GPGGA NMEA data arrives
|
||||
// See u-blox_structs.h for the full definition of NMEA_GGA_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGPGGAcallback
|
||||
// / _____ This _must_ be NMEA_GGA_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printGPGGA(NMEA_GGA_data_t *nmeaData)
|
||||
{
|
||||
Serial.print(F("\r\nGPGGA: Length: "));
|
||||
Serial.print(nmeaData->length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
|
||||
}
|
||||
|
||||
// Callback: printGNGGA will be called if new GNGGA NMEA data arrives
|
||||
// See u-blox_structs.h for the full definition of NMEA_GGA_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGNGGAcallback
|
||||
// / _____ This _must_ be NMEA_GGA_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printGNGGA(NMEA_GGA_data_t *nmeaData)
|
||||
{
|
||||
Serial.print(F("\r\nGNGGA: Length: "));
|
||||
Serial.print(nmeaData->length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
|
||||
}
|
||||
|
||||
// Callback: printGPVTG will be called when new GPVTG NMEA data arrives
|
||||
// See u-blox_structs.h for the full definition of NMEA_VTG_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGPVTGcallback
|
||||
// / _____ This _must_ be NMEA_VTG_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printGPVTG(NMEA_VTG_data_t *nmeaData)
|
||||
{
|
||||
Serial.print(F("\r\nGPVTG: Length: "));
|
||||
Serial.print(nmeaData->length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
|
||||
}
|
||||
|
||||
// Callback: printGNVTG will be called if new GNVTG NMEA data arrives
|
||||
// See u-blox_structs.h for the full definition of NMEA_VTG_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGNVTGcallback
|
||||
// / _____ This _must_ be NMEA_VTG_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printGNVTG(NMEA_VTG_data_t *nmeaData)
|
||||
{
|
||||
Serial.print(F("\r\nGNVTG: Length: "));
|
||||
Serial.print(nmeaData->length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
|
||||
}
|
||||
|
||||
// Callback: printGPRMC will be called when new GPRMC NMEA data arrives
|
||||
// See u-blox_structs.h for the full definition of NMEA_RMC_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGPRMCcallback
|
||||
// / _____ This _must_ be NMEA_RMC_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printGPRMC(NMEA_RMC_data_t *nmeaData)
|
||||
{
|
||||
Serial.print(F("\r\nGPRMC: Length: "));
|
||||
Serial.print(nmeaData->length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
|
||||
}
|
||||
|
||||
// Callback: printGNRMC will be called if new GNRMC NMEA data arrives
|
||||
// See u-blox_structs.h for the full definition of NMEA_RMC_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGNRMCcallback
|
||||
// / _____ This _must_ be NMEA_RMC_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printGNRMC(NMEA_RMC_data_t *nmeaData)
|
||||
{
|
||||
Serial.print(F("\r\nGNRMC: Length: "));
|
||||
Serial.print(nmeaData->length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
|
||||
}
|
||||
|
||||
// Callback: printGPZDA will be called when new GPZDA NMEA data arrives
|
||||
// See u-blox_structs.h for the full definition of NMEA_ZDA_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGPZDAcallback
|
||||
// / _____ This _must_ be NMEA_ZDA_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printGPZDA(NMEA_ZDA_data_t *nmeaData)
|
||||
{
|
||||
Serial.print(F("\r\nGPZDA: Length: "));
|
||||
Serial.print(nmeaData->length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
|
||||
}
|
||||
|
||||
// Callback: printGNZDA will be called if new GNZDA NMEA data arrives
|
||||
// See u-blox_structs.h for the full definition of NMEA_ZDA_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGNZDAcallback
|
||||
// / _____ This _must_ be NMEA_ZDA_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printGNZDA(NMEA_ZDA_data_t *nmeaData)
|
||||
{
|
||||
Serial.print(F("\r\nGNZDA: Length: "));
|
||||
Serial.print(nmeaData->length);
|
||||
Serial.print(F("\tData: "));
|
||||
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("SparkFun u-blox GNSS Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false)
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
// Disable or enable various NMEA sentences over the I2C interface
|
||||
myGNSS.setI2COutput(COM_TYPE_NMEA | COM_TYPE_UBX); // Turn on both UBX and NMEA sentences on I2C. (Turn off RTCM and SPARTN)
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C);
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C);
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C);
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C);
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_ZDA, COM_PORT_I2C);
|
||||
|
||||
// Set the Main Talker ID to "GP". The NMEA GGA messages will be GPGGA instead of GNGGA
|
||||
myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_GP);
|
||||
//myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_DEFAULT); // Uncomment this line to restore the default main talker ID
|
||||
|
||||
myGNSS.setHighPrecisionMode(true); // Enable High Precision Mode - include extra decimal places in the GGA messages
|
||||
|
||||
//myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save only the ioPort and message settings to NVM
|
||||
|
||||
Serial.println(F("Messages configured"));
|
||||
|
||||
//myGNSS.setNMEAOutputPort(Serial); // Uncomment this line to echo all NMEA data to Serial for debugging
|
||||
|
||||
// Set up the callback for GPGGA
|
||||
myGNSS.setNMEAGPGGAcallbackPtr(&printGPGGA);
|
||||
|
||||
// Set up the callback for GNGGA
|
||||
myGNSS.setNMEAGNGGAcallbackPtr(&printGNGGA);
|
||||
|
||||
// Set up the callback for GPVTG
|
||||
myGNSS.setNMEAGPVTGcallbackPtr(&printGPVTG);
|
||||
|
||||
// Set up the callback for GNVTG
|
||||
myGNSS.setNMEAGNVTGcallbackPtr(&printGNVTG);
|
||||
|
||||
// Set up the callback for GPRMC
|
||||
myGNSS.setNMEAGPRMCcallbackPtr(&printGPRMC);
|
||||
|
||||
// Set up the callback for GNRMC
|
||||
myGNSS.setNMEAGNRMCcallbackPtr(&printGNRMC);
|
||||
|
||||
// Set up the callback for GPZDA
|
||||
myGNSS.setNMEAGPZDAcallbackPtr(&printGPZDA);
|
||||
|
||||
// Set up the callback for GNZDA
|
||||
myGNSS.setNMEAGNZDAcallbackPtr(&printGNZDA);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
Serial.print(".");
|
||||
delay(50);
|
||||
}
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
Callback Example: ESF RAW (100Hz!)
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: September 8th, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example configures the External Sensor Fusion RAW IMU sensor messages on the NEO-M8U / ZED-F9R and
|
||||
uses callbacks to process and display the ESF data automatically.
|
||||
|
||||
Notes:
|
||||
On the ZED-F9R, each ESF RAW message contains _one_ set of IMU sensor data: seven readings in total (3 x Accel, 3 x Gyro, 1 x Temperature).
|
||||
However, on the NEO-M8U, each message contains _ten_ sets of IMU sensor data, seventy readings in total.
|
||||
The NEO-M8U data is all timestamped and it is possible to reconstruct the full data stream, you just need to do it
|
||||
ten samples at a time...
|
||||
Also, note that the sensor data is 24-bit signed (two's complement). You need to be careful when converting to int32_t.
|
||||
Data will arrive at 100Hz! (10Hz x 10 on the NEO-M8U)
|
||||
400kHz I2C is essential...
|
||||
Serial printing needs to be kept short and the baud rate needs to be at least 230400.
|
||||
|
||||
Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary:
|
||||
https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
NEO-M8U: https://www.sparkfun.com/products/16329
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a Redboard Qwiic
|
||||
If you don't have a platform with a Qwiic connection use the
|
||||
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GPS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
// Callback: printESFRAWdata will be called when new ESF RAW data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_ESF_RAW_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoESFRAWcallback
|
||||
// / _____ This _must_ be UBX_ESF_RAW_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printESFRAWdata(UBX_ESF_RAW_data_t *ubxDataStruct)
|
||||
{
|
||||
// ubxDataStruct->numEsfRawBlocks indicates how many sensor readings the UBX_ESF_RAW_data_t contains.
|
||||
// On the ZED-F9R, numEsfRawBlocks will be 7: 3 x Accel, 3 x Gyro, 1 x Temperature.
|
||||
// On the NEO-M8U, numEsfRawBlocks will be 70: 10 sets of sensor data. The sensor time tag (sTag)
|
||||
// indicates the timing of each sample.
|
||||
// Serial output will be approx. 110 bytes depending on how many digits are in the sensor readings.
|
||||
// To keep up, Serial needs to be running at 100k baud minimum. 230400 is recommended.
|
||||
|
||||
uint32_t sTag = 0xFFFFFFFF; // Sensor time tag
|
||||
|
||||
// Only print the first seven sensor readings (on the NEO-M8U)
|
||||
for (uint8_t i = 0; (i < ubxDataStruct->numEsfRawBlocks) && (i < 7); i++)
|
||||
// For fun, and to prove it works, uncomment use this line instead to get the full 100Hz data on the NEO-M8U
|
||||
//for (uint8_t i = 0; i < ubxDataStruct->numEsfRawBlocks; i++)
|
||||
{
|
||||
// Print sTag the first time - and also if it changes
|
||||
if (sTag != ubxDataStruct->data[i].sTag)
|
||||
{
|
||||
sTag = ubxDataStruct->data[i].sTag;
|
||||
Serial.print(F("Time:"));
|
||||
Serial.println(sTag);
|
||||
}
|
||||
|
||||
// Print the sensor data type
|
||||
// From the M8 interface description:
|
||||
// 0: None
|
||||
// 1-4: Reserved
|
||||
// 5: z-axis gyroscope angular rate deg/s * 2^-12 signed
|
||||
// 6: front-left wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 7: front-right wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 8: rear-left wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 9: rear-right wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 10: speed ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 11: speed m/s * 1e-3 signed
|
||||
// 12: gyroscope temperature deg Celsius * 1e-2 signed
|
||||
// 13: y-axis gyroscope angular rate deg/s * 2^-12 signed
|
||||
// 14: x-axis gyroscope angular rate deg/s * 2^-12 signed
|
||||
// 16: x-axis accelerometer specific force m/s^2 * 2^-10 signed
|
||||
// 17: y-axis accelerometer specific force m/s^2 * 2^-10 signed
|
||||
// 18: z-axis accelerometer specific force m/s^2 * 2^-10 signed
|
||||
switch (ubxDataStruct->data[i].data.bits.dataType)
|
||||
{
|
||||
case 5:
|
||||
Serial.print(F("Zgyr:"));
|
||||
break;
|
||||
case 12:
|
||||
Serial.print(F("Temp:"));
|
||||
break;
|
||||
case 13:
|
||||
Serial.print(F("Ygyr:"));
|
||||
break;
|
||||
case 14:
|
||||
Serial.print(F("Xgyr:"));
|
||||
break;
|
||||
case 16:
|
||||
Serial.print(F("Xacc:"));
|
||||
break;
|
||||
case 17:
|
||||
Serial.print(F("Yacc:"));
|
||||
break;
|
||||
case 18:
|
||||
Serial.print(F("Zacc:"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Gyro data
|
||||
if ((ubxDataStruct->data[i].data.bits.dataType == 5) || (ubxDataStruct->data[i].data.bits.dataType == 13) || (ubxDataStruct->data[i].data.bits.dataType == 14))
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t signed32;
|
||||
uint32_t unsigned32;
|
||||
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
|
||||
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
|
||||
signedUnsigned.unsigned32 = ubxDataStruct->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
|
||||
float rate = signedUnsigned.signed32; // Extract the signed data. Convert to float
|
||||
rate /= 256.0; // Divide by 256 to undo the shift
|
||||
rate *= 0.000244140625; // Convert from deg/s * 2^-12 to deg/s
|
||||
Serial.println(rate);
|
||||
}
|
||||
// Accelerometer data
|
||||
else if ((ubxDataStruct->data[i].data.bits.dataType == 16) || (ubxDataStruct->data[i].data.bits.dataType == 17) || (ubxDataStruct->data[i].data.bits.dataType == 18))
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t signed32;
|
||||
uint32_t unsigned32;
|
||||
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
|
||||
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
|
||||
signedUnsigned.unsigned32 = ubxDataStruct->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
|
||||
float force = signedUnsigned.signed32; // Extract the signed data. Convert to float
|
||||
force /= 256.0; // Divide by 256 to undo the shift
|
||||
force *= 0.0009765625; // Convert from m/s^2 * 2^-10 to m/s^2
|
||||
Serial.println(force);
|
||||
}
|
||||
// Gyro Temperature
|
||||
else if (ubxDataStruct->data[i].data.bits.dataType == 12)
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t signed32;
|
||||
uint32_t unsigned32;
|
||||
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
|
||||
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
|
||||
signedUnsigned.unsigned32 = ubxDataStruct->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
|
||||
float temperature = signedUnsigned.signed32; // Extract the signed data. Convert to float
|
||||
temperature /= 256.0; // Divide by 256 to undo the shift
|
||||
temperature *= 0.01; // Convert from C * 1e-2 to C
|
||||
Serial.println(temperature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(230400); // <--- Use >> 100k baud (see notes above)
|
||||
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
Wire.setClock(400000); // <-- Use 400kHz I2C (ESSENTIAL)
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setI2CpollingWait(5); //Allow checkUblox to poll I2C data every 5ms to keep up with the ESF RAW messages
|
||||
|
||||
if (myGNSS.setAutoESFRAWcallbackPtr(&printESFRAWdata) == true) // Enable automatic ESF RAW messages with callback to printESFRAWdata
|
||||
Serial.println(F("setAutoESFRAWcallback successful"));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
}
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
u-blox Example: ESF RAW (100Hz!)
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: September 8th, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example configures the External Sensor Fusion RAW IMU sensor messages on the NEO-M8U / ZED-F9R and
|
||||
shows how to access the ESF data in the loop - without using the callback.
|
||||
|
||||
Notes:
|
||||
On the ZED-F9R, each ESF RAW message contains _one_ set of IMU sensor data: seven readings in total (3 x Accel, 3 x Gyro, 1 x Temperature).
|
||||
However, on the NEO-M8U, each message contains _ten_ sets of IMU sensor data, seventy readings in total.
|
||||
The NEO-M8U data is all timestamped and it is possible to reconstruct the full data stream, you just need to do it
|
||||
ten samples at a time...
|
||||
Also, note that the sensor data is 24-bit signed (two's complement). You need to be careful when converting to int32_t.
|
||||
Data will arrive at 100Hz! (10Hz x 10 on the NEO-M8U)
|
||||
400kHz I2C is essential...
|
||||
Serial printing needs to be kept short and the baud rate needs to be at least 230400.
|
||||
|
||||
Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary:
|
||||
https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
NEO-M8U: https://www.sparkfun.com/products/16329
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a Redboard Qwiic
|
||||
If you don't have a platform with a Qwiic connection use the
|
||||
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GPS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
// Callback: printESFRAWdata will be called when new ESF RAW data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_ESF_RAW_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoESFRAWcallback
|
||||
// / _____ This _must_ be UBX_ESF_RAW_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printESFRAWdata(UBX_ESF_RAW_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println(F("Hey! The ESF RAW callback has been called!"));
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(230400); // <--- Use >> 100k baud (see notes above)
|
||||
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
Wire.setClock(400000); // <-- Use 400kHz I2C (ESSENTIAL)
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setI2CpollingWait(5); //Allow checkUblox to poll I2C data every 5ms to keep up with the ESF RAW messages
|
||||
|
||||
if (myGNSS.setAutoESFRAWcallbackPtr(&printESFRAWdata) == true) // Enable automatic ESF RAW messages with callback to printESFRAWdata
|
||||
Serial.println(F("setAutoESFRAWcallback successful"));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
|
||||
// Check if new ESF RAW data has arrived:
|
||||
// If myGNSS.packetUBXESFRAW->automaticFlags.flags.bits.callbackCopyValid is true, it indicates new ESF RAW data has been received and has been copied.
|
||||
// automaticFlags.flags.bits.callbackCopyValid will be cleared automatically when the callback is called.
|
||||
|
||||
if (myGNSS.packetUBXESFRAW->automaticFlags.flags.bits.callbackCopyValid == true)
|
||||
{
|
||||
// But, we can manually clear the callback flag too. This will prevent the callback from being called!
|
||||
myGNSS.packetUBXESFRAW->automaticFlags.flags.bits.callbackCopyValid = false; // Comment this line if you still want the callback to be called
|
||||
|
||||
// myGNSS.packetUBXESFRAW->callbackData->numEsfRawBlocks indicates how many sensor readings the UBX_ESF_RAW_data_t contains.
|
||||
// On the ZED-F9R, numEsfRawBlocks will be 7: 3 x Accel, 3 x Gyro, 1 x Temperature.
|
||||
// On the NEO-M8U, numEsfRawBlocks will be 70: 10 sets of sensor data. The sensor time tag (sTag)
|
||||
// indicates the timing of each sample.
|
||||
// Serial output will be approx. 110 bytes depending on how many digits are in the sensor readings.
|
||||
// To keep up, Serial needs to be running at 100k baud minimum. 230400 is recommended.
|
||||
|
||||
uint32_t sTag = 0xFFFFFFFF; // Sensor time tag
|
||||
|
||||
// Only print the first seven sensor readings (on the NEO-M8U)
|
||||
for (uint8_t i = 0; (i < myGNSS.packetUBXESFRAW->callbackData->numEsfRawBlocks) && (i < 7); i++)
|
||||
// For fun, and to prove it works, uncomment use this line instead to get the full 100Hz data on the NEO-M8U
|
||||
//for (uint8_t i = 0; i < myGNSS.packetUBXESFRAW->callbackData->numEsfRawBlocks; i++)
|
||||
{
|
||||
// Print sTag the first time - and also if it changes
|
||||
if (sTag != myGNSS.packetUBXESFRAW->callbackData->data[i].sTag)
|
||||
{
|
||||
sTag = myGNSS.packetUBXESFRAW->callbackData->data[i].sTag;
|
||||
Serial.print(F("Time:"));
|
||||
Serial.println(sTag);
|
||||
}
|
||||
|
||||
// Print the sensor data type
|
||||
// From the M8 interface description:
|
||||
// 0: None
|
||||
// 1-4: Reserved
|
||||
// 5: z-axis gyroscope angular rate deg/s * 2^-12 signed
|
||||
// 6: front-left wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 7: front-right wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 8: rear-left wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 9: rear-right wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 10: speed ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 11: speed m/s * 1e-3 signed
|
||||
// 12: gyroscope temperature deg Celsius * 1e-2 signed
|
||||
// 13: y-axis gyroscope angular rate deg/s * 2^-12 signed
|
||||
// 14: x-axis gyroscope angular rate deg/s * 2^-12 signed
|
||||
// 16: x-axis accelerometer specific force m/s^2 * 2^-10 signed
|
||||
// 17: y-axis accelerometer specific force m/s^2 * 2^-10 signed
|
||||
// 18: z-axis accelerometer specific force m/s^2 * 2^-10 signed
|
||||
switch (myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType)
|
||||
{
|
||||
case 5:
|
||||
Serial.print(F("Zgyr:"));
|
||||
break;
|
||||
case 12:
|
||||
Serial.print(F("Temp:"));
|
||||
break;
|
||||
case 13:
|
||||
Serial.print(F("Ygyr:"));
|
||||
break;
|
||||
case 14:
|
||||
Serial.print(F("Xgyr:"));
|
||||
break;
|
||||
case 16:
|
||||
Serial.print(F("Xacc:"));
|
||||
break;
|
||||
case 17:
|
||||
Serial.print(F("Yacc:"));
|
||||
break;
|
||||
case 18:
|
||||
Serial.print(F("Zacc:"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Gyro data
|
||||
if ((myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType == 5) || (myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType == 13) || (myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType == 14))
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t signed32;
|
||||
uint32_t unsigned32;
|
||||
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
|
||||
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
|
||||
signedUnsigned.unsigned32 = myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
|
||||
float rate = signedUnsigned.signed32; // Extract the signed data. Convert to float
|
||||
rate /= 256.0; // Divide by 256 to undo the shift
|
||||
rate *= 0.000244140625; // Convert from deg/s * 2^-12 to deg/s
|
||||
Serial.println(rate);
|
||||
}
|
||||
// Accelerometer data
|
||||
else if ((myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType == 16) || (myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType == 17) || (myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType == 18))
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t signed32;
|
||||
uint32_t unsigned32;
|
||||
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
|
||||
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
|
||||
signedUnsigned.unsigned32 = myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
|
||||
float force = signedUnsigned.signed32; // Extract the signed data. Convert to float
|
||||
force /= 256.0; // Divide by 256 to undo the shift
|
||||
force *= 0.0009765625; // Convert from m/s^2 * 2^-10 to m/s^2
|
||||
Serial.println(force);
|
||||
}
|
||||
// Gyro Temperature
|
||||
else if (myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType == 12)
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t signed32;
|
||||
uint32_t unsigned32;
|
||||
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
|
||||
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
|
||||
signedUnsigned.unsigned32 = myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
|
||||
float temperature = signedUnsigned.signed32; // Extract the signed data. Convert to float
|
||||
temperature /= 256.0; // Divide by 256 to undo the shift
|
||||
temperature *= 0.01; // Convert from C * 1e-2 to C
|
||||
Serial.println(temperature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed. There will not be any in this example, unless you commented the line above
|
||||
}
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
u-blox Example: ESF MEAS (Wheel Ticks)
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: September 8th, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example configures the External Sensor Fusion MEAS sensor messages on the NEO-M8U / ZED-F9R and
|
||||
shows how to access the ESF data in the loop - without using the callback.
|
||||
|
||||
Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary:
|
||||
https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
NEO-M8U: https://www.sparkfun.com/products/16329
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a Redboard Qwiic
|
||||
If you don't have a platform with a Qwiic connection use the
|
||||
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GPS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
// Callback: printESFMEASdata will be called when new ESF MEAS data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_ESF_MEAS_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoESFMEAScallback
|
||||
// / _____ This _must_ be UBX_ESF_MEAS_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printESFMEASdata(UBX_ESF_MEAS_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println(F("Hey! The ESF MEAS callback has been called!"));
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(230400); // <-- Use a fast baud rate to avoid the Serial prints slowing the code
|
||||
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
Wire.setClock(400000); // <-- Use 400kHz I2C
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
if (myGNSS.setAutoESFMEAScallbackPtr(&printESFMEASdata) == true) // Enable automatic ESF MEAS messages with callback to printESFMEASdata
|
||||
Serial.println(F("setAutoESFMEAScallback successful"));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
|
||||
// Check if new ESF MEAS data has arrived:
|
||||
// If myGNSS.packetUBXESFMEAS->automaticFlags.flags.bits.callbackCopyValid is true, it indicates new ESF MEAS data has been received and has been copied.
|
||||
// automaticFlags.flags.bits.callbackCopyValid will be cleared automatically when the callback is called.
|
||||
|
||||
if (myGNSS.packetUBXESFMEAS->automaticFlags.flags.bits.callbackCopyValid == true)
|
||||
{
|
||||
// But, we can manually clear the callback flag too. This will prevent the callback from being called!
|
||||
myGNSS.packetUBXESFMEAS->automaticFlags.flags.bits.callbackCopyValid = false; // Comment this line if you still want the callback to be called
|
||||
|
||||
// Print the timeTag
|
||||
Serial.print(F("Time: "));
|
||||
Serial.println(myGNSS.packetUBXESFMEAS->callbackData->timeTag);
|
||||
|
||||
// myGNSS.packetUBXESFMEAS->callbackData->flags.bits.numMeas indicates how many sensor groups the UBX_ESF_MEAS_data_t contains.
|
||||
for (uint8_t i = 0; i < myGNSS.packetUBXESFMEAS->callbackData->flags.bits.numMeas; i++)
|
||||
{
|
||||
// Print the sensor data type
|
||||
// From the M8 interface description:
|
||||
// 0: None
|
||||
// 1-4: Reserved
|
||||
// 5: z-axis gyroscope angular rate deg/s * 2^-12 signed
|
||||
// 6: front-left wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 7: front-right wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 8: rear-left wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 9: rear-right wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 10: speed ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
|
||||
// 11: speed m/s * 1e-3 signed
|
||||
// 12: gyroscope temperature deg Celsius * 1e-2 signed
|
||||
// 13: y-axis gyroscope angular rate deg/s * 2^-12 signed
|
||||
// 14: x-axis gyroscope angular rate deg/s * 2^-12 signed
|
||||
// 16: x-axis accelerometer specific force m/s^2 * 2^-10 signed
|
||||
// 17: y-axis accelerometer specific force m/s^2 * 2^-10 signed
|
||||
// 18: z-axis accelerometer specific force m/s^2 * 2^-10 signed
|
||||
switch (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType)
|
||||
{
|
||||
case 5:
|
||||
Serial.print(F("Z Gyro: "));
|
||||
break;
|
||||
case 6:
|
||||
Serial.print(F("Front Left: "));
|
||||
break;
|
||||
case 7:
|
||||
Serial.print(F("Front Right: "));
|
||||
break;
|
||||
case 8:
|
||||
Serial.print(F("Rear Left: "));
|
||||
break;
|
||||
case 9:
|
||||
Serial.print(F("Rear Right: "));
|
||||
break;
|
||||
case 10:
|
||||
Serial.print(F("Speed Ticks: "));
|
||||
break;
|
||||
case 11:
|
||||
Serial.print(F("Speed: "));
|
||||
break;
|
||||
case 12:
|
||||
Serial.print(F("Temp: "));
|
||||
break;
|
||||
case 13:
|
||||
Serial.print(F("Y Gyro: "));
|
||||
break;
|
||||
case 14:
|
||||
Serial.print(F("X Gyro: "));
|
||||
break;
|
||||
case 16:
|
||||
Serial.print(F("X Accel: "));
|
||||
break;
|
||||
case 17:
|
||||
Serial.print(F("Y Accel: "));
|
||||
break;
|
||||
case 18:
|
||||
Serial.print(F("Z Accel: "));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Tick data
|
||||
if ((myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType >= 6) && (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType <= 10))
|
||||
{
|
||||
if ((myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField & (1 << 23)) > 0)
|
||||
Serial.print(F("-")); // Backward
|
||||
else
|
||||
Serial.print(F("+")); // Forward
|
||||
Serial.println(myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField & 0x007FFFFF);
|
||||
}
|
||||
// Speed
|
||||
else if (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 11)
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t signed32;
|
||||
uint32_t unsigned32;
|
||||
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
|
||||
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
|
||||
signedUnsigned.unsigned32 = myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
|
||||
float speed = signedUnsigned.signed32; // Extract the signed data. Convert to float
|
||||
speed /= 256.0; // Divide by 256 to undo the shift
|
||||
speed *= 0.001; // Convert from m/s * 1e-3 to m/s
|
||||
Serial.println(speed, 3);
|
||||
}
|
||||
// Gyro data
|
||||
else if ((myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 5) || (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 13) || (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 14))
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t signed32;
|
||||
uint32_t unsigned32;
|
||||
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
|
||||
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
|
||||
signedUnsigned.unsigned32 = myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
|
||||
float rate = signedUnsigned.signed32; // Extract the signed data. Convert to float
|
||||
rate /= 256.0; // Divide by 256 to undo the shift
|
||||
rate *= 0.000244140625; // Convert from deg/s * 2^-12 to deg/s
|
||||
Serial.println(rate);
|
||||
}
|
||||
// Accelerometer data
|
||||
else if ((myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 16) || (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 17) || (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 18))
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t signed32;
|
||||
uint32_t unsigned32;
|
||||
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
|
||||
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
|
||||
signedUnsigned.unsigned32 = myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
|
||||
float force = signedUnsigned.signed32; // Extract the signed data. Convert to float
|
||||
force /= 256.0; // Divide by 256 to undo the shift
|
||||
force *= 0.0009765625; // Convert from m/s^2 * 2^-10 to m/s^2
|
||||
Serial.println(force);
|
||||
}
|
||||
// Gyro Temperature
|
||||
else if (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 12)
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t signed32;
|
||||
uint32_t unsigned32;
|
||||
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
|
||||
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
|
||||
signedUnsigned.unsigned32 = myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
|
||||
float temperature = signedUnsigned.signed32; // Extract the signed data. Convert to float
|
||||
temperature /= 256.0; // Divide by 256 to undo the shift
|
||||
temperature *= 0.01; // Convert from C * 1e-2 to C
|
||||
Serial.println(temperature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed. There will not be any in this example, unless you commented the line above
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send position reports over I2C and display them using a callback
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: December 30th, 2020
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the u-blox GNSS to send navigation reports automatically
|
||||
and access the data via a callback. No more polling!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GPS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
// Callback: printPVTdata will be called when new NAV PVT data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoPVTcallback
|
||||
// / _____ This _must_ be UBX_NAV_PVT_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Time: ")); // Print the time
|
||||
uint8_t hms = ubxDataStruct->hour; // Print the hours
|
||||
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
|
||||
Serial.print(hms);
|
||||
Serial.print(F(":"));
|
||||
hms = ubxDataStruct->min; // Print the minutes
|
||||
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
|
||||
Serial.print(hms);
|
||||
Serial.print(F(":"));
|
||||
hms = ubxDataStruct->sec; // Print the seconds
|
||||
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
|
||||
Serial.print(hms);
|
||||
Serial.print(F("."));
|
||||
unsigned long millisecs = ubxDataStruct->iTOW % 1000; // Print the milliseconds
|
||||
if (millisecs < 100) Serial.print(F("0")); // Print the trailing zeros correctly
|
||||
if (millisecs < 10) Serial.print(F("0"));
|
||||
Serial.print(millisecs);
|
||||
|
||||
long latitude = ubxDataStruct->lat; // Print the latitude
|
||||
Serial.print(F(" Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = ubxDataStruct->lon; // Print the longitude
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = ubxDataStruct->hMSL; // Print the height above mean sea level
|
||||
Serial.print(F(" Height above MSL: "));
|
||||
Serial.print(altitude);
|
||||
Serial.println(F(" (mm)"));
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(2); //Produce two solutions per second
|
||||
|
||||
myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
Serial.print(".");
|
||||
delay(50);
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send odometer reports over I2C and display the data using a callback
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: March 20th, 2023
|
||||
License: MIT. See license file for more information.
|
||||
|
||||
This example shows how to configure the u-blox GNSS to send odometer reports automatically
|
||||
and display the data via a callback. No more polling!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GPS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
// Callback: printODOdata will be called when new NAV ODO data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_NAV_ODO_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVODOcallback
|
||||
// / _____ This _must_ be UBX_NAV_ODO_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printODOdata(UBX_NAV_ODO_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("TOW: ")); // Print the Time Of Week
|
||||
unsigned long iTOW = ubxDataStruct->iTOW; // iTOW is in milliseconds
|
||||
Serial.print(iTOW);
|
||||
Serial.print(F(" (ms)"));
|
||||
|
||||
Serial.print(F(" Distance: "));
|
||||
unsigned long distance = ubxDataStruct->distance; // Print the distance
|
||||
Serial.print(distance);
|
||||
Serial.print(F(" (m)"));
|
||||
|
||||
Serial.print(F(" Total Distance: "));
|
||||
unsigned long totalDistance = ubxDataStruct->totalDistance; // Print the total distance
|
||||
Serial.print(totalDistance);
|
||||
Serial.println(F(" (m)"));
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
delay(1000);
|
||||
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
|
||||
while (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring."));
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one solution per second
|
||||
|
||||
//By default, the odometer is disabled. We need to enable it.
|
||||
//We can enable it using the default settings:
|
||||
myGNSS.enableOdometer();
|
||||
|
||||
//Or we can configure it using our own settings, by performing a read-modify-write:
|
||||
uint8_t flags; // Odometer/Low-speed COG filter flags
|
||||
uint8_t odoCfg; // Odometer filter settings
|
||||
uint8_t cogMaxSpeed; // Speed below which course-over-ground (COG) is computed with the low-speed COG filter : m/s * 0.1
|
||||
uint8_t cogMaxPosAcc; // Maximum acceptable position accuracy for computing COG with the low-speed COG filter
|
||||
uint8_t velLpGain; // Velocity low-pass filter level
|
||||
uint8_t cogLpGain; // COG low-pass filter level
|
||||
|
||||
if (myGNSS.getOdometerConfig(&flags, &odoCfg, &cogMaxSpeed, &cogMaxPosAcc, &velLpGain, &cogLpGain))
|
||||
{
|
||||
flags = UBX_CFG_ODO_USE_ODO; // Enable the odometer
|
||||
odoCfg = UBX_CFG_ODO_CAR; // Use the car profile (others are RUN, CYCLE, SWIM, CUSTOM)
|
||||
myGNSS.setOdometerConfig(flags, odoCfg, cogMaxSpeed, cogMaxPosAcc, velLpGain, cogLpGain); // Set the configuration
|
||||
}
|
||||
else
|
||||
Serial.println("Could not read odometer config!");
|
||||
|
||||
//myGNSS.resetOdometer(); //Uncomment this line to reset the odometer
|
||||
|
||||
myGNSS.setAutoNAVODOcallbackPtr(&printODOdata); // Enable automatic NAV ODO messages with callback to printODOdata
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
Serial.print(".");
|
||||
delay(50);
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send TIM TM2 reports over I2C and display the data using a callback
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: December 30th, 2020
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the u-blox GNSS to send TIM TM2 reports automatically
|
||||
and display the data via a callback. No more polling!
|
||||
|
||||
Connecting the PPS (Pulse Per Second) breakout pin to the INT (Interrupt) pin with a jumper wire
|
||||
will cause a TIM TM2 message to be produced once per second. You can then study the timing of the
|
||||
pulse edges with nanosecond resolution!
|
||||
|
||||
Note: TIM TM2 can only capture the timing of one rising edge and one falling edge per
|
||||
navigation solution. So with setNavigationFrequency set to 1Hz, we can only see the timing
|
||||
of one rising and one falling edge per second. If the frequency of the signal on the INT pin
|
||||
is higher than 1Hz, we will only be able to see the timing of the most recent edges.
|
||||
However, the module can count the number of rising edges too, at rates faster than the navigation rate.
|
||||
|
||||
TIM TM2 messages are only produced when a rising or falling edge is detected on the INT pin.
|
||||
If you disconnect your PPS to INT jumper wire, the messages will stop.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
NEO-M9N: https://www.sparkfun.com/products/17285
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GPS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
int dotsPrinted = 0; // Print dots in rows of 50 while waiting for a TIM TM2 message
|
||||
|
||||
// Callback: printTIMTM2data will be called when new TIM TM2 data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_TIM_TM2_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoTIMTM2callback
|
||||
// / _____ This _must_ be UBX_TIM_TM2_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printTIMTM2data(UBX_TIM_TM2_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("newFallingEdge: ")); // 1 if a new falling edge was detected
|
||||
Serial.print(ubxDataStruct->flags.bits.newFallingEdge);
|
||||
|
||||
Serial.print(F(" newRisingEdge: ")); // 1 if a new rising edge was detected
|
||||
Serial.print(ubxDataStruct->flags.bits.newRisingEdge);
|
||||
|
||||
Serial.print(F(" Rising Edge Counter: ")); // Rising edge counter
|
||||
Serial.print(ubxDataStruct->count);
|
||||
|
||||
Serial.print(F(" towMsR: ")); // Time Of Week of rising edge (ms)
|
||||
Serial.print(ubxDataStruct->towMsR);
|
||||
|
||||
Serial.print(F(" towSubMsR: ")); // Millisecond fraction of Time Of Week of rising edge in nanoseconds
|
||||
Serial.print(ubxDataStruct->towSubMsR);
|
||||
|
||||
Serial.print(F(" towMsF: ")); // Time Of Week of falling edge (ms)
|
||||
Serial.print(ubxDataStruct->towMsF);
|
||||
|
||||
Serial.print(F(" towSubMsF: ")); // Millisecond fraction of Time Of Week of falling edge in nanoseconds
|
||||
Serial.println(ubxDataStruct->towSubMsF);
|
||||
|
||||
dotsPrinted = 0; // Reset dotsPrinted
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one solution per second
|
||||
|
||||
myGNSS.setAutoTIMTM2callbackPtr(&printTIMTM2data); // Enable automatic TIM TM2 messages with callback to printTIMTM2data
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
Serial.print(".");
|
||||
delay(50);
|
||||
if (++dotsPrinted > 50)
|
||||
{
|
||||
Serial.println();
|
||||
dotsPrinted = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: December, 2020
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example configures the High Navigation Rate on the NEO-M8U and then
|
||||
reads and displays the attitude solution, vehicle dynamics information
|
||||
and high rate position, velocity and time.
|
||||
|
||||
This example uses callbacks to process the HNR data automatically. No more polling!
|
||||
|
||||
Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary:
|
||||
https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
NEO-M8U: https://www.sparkfun.com/products/16329
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a Redboard Qwiic
|
||||
If you don't have a platform with a Qwiic connection use the
|
||||
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GPS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
// Callback: printHNRATTdata will be called when new HNR ATT data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_HNR_ATT_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoHNRATTcallback
|
||||
// / _____ This _must_ be UBX_HNR_ATT_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printHNRATTdata(UBX_HNR_ATT_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println();
|
||||
Serial.print(F("Roll: ")); // Print selected data
|
||||
Serial.print((float)ubxDataStruct->roll / 100000.0, 2); // Convert roll to degrees
|
||||
Serial.print(F(" Pitch: "));
|
||||
Serial.print((float)ubxDataStruct->pitch / 100000.0, 2); // Convert pitch to degrees
|
||||
Serial.print(F(" Heading: "));
|
||||
Serial.println((float)ubxDataStruct->heading / 100000.0, 2); // Convert heading to degrees
|
||||
}
|
||||
|
||||
// Callback: printHNRINSdata will be called when new HNR INS data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_HNR_INS_data_t
|
||||
void printHNRINSdata(UBX_HNR_INS_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.print(F("xAccel: ")); // Print selected data
|
||||
Serial.print(ubxDataStruct->xAccel);
|
||||
Serial.print(F(" yAccel: "));
|
||||
Serial.print(ubxDataStruct->yAccel);
|
||||
Serial.print(F(" zAccel: "));
|
||||
Serial.println(ubxDataStruct->zAccel);
|
||||
}
|
||||
|
||||
// Callback: printHNRPVTdata will be called when new HNR PVT data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_HNR_PVT_data_t
|
||||
void printHNRPVTdata(UBX_HNR_PVT_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.print(F("ns: ")); // Print selected data
|
||||
Serial.print(ubxDataStruct->nano);
|
||||
Serial.print(F(" Lat: "));
|
||||
Serial.print(ubxDataStruct->lat);
|
||||
Serial.print(F(" Lon: "));
|
||||
Serial.println(ubxDataStruct->lon);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
if (myGNSS.setHNRNavigationRate(10) == true) //Set the High Navigation Rate to 10Hz
|
||||
Serial.println(F("setHNRNavigationRate was successful"));
|
||||
else
|
||||
Serial.println(F("setHNRNavigationRate was NOT successful"));
|
||||
|
||||
if (myGNSS.setAutoHNRATTcallbackPtr(&printHNRATTdata) == true) // Enable automatic HNR ATT messages with callback to printHNRATTdata
|
||||
Serial.println(F("setAutoHNRATTcallback successful"));
|
||||
|
||||
if (myGNSS.setAutoHNRINScallbackPtr(&printHNRINSdata) == true) // Enable automatic HNR INS messages with callback to printHNRINSdata
|
||||
Serial.println(F("setAutoHNRINScallback successful"));
|
||||
|
||||
if (myGNSS.setAutoHNRPVTcallbackPtr(&printHNRPVTdata) == true) // Enable automatic HNR PVT messages with callback to printHNRPVTdata
|
||||
Serial.println(F("setAutoHNRPVTcallback successful"));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
Serial.print(".");
|
||||
delay(25);
|
||||
}
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: December, 2020
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example configures the External Sensor Fusion messages on the NEO-M8U and
|
||||
uses callbacks to process and display the ESF data automatically. No more polling!
|
||||
|
||||
Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary:
|
||||
https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
NEO-M8U: https://www.sparkfun.com/products/16329
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a Redboard Qwiic
|
||||
If you don't have a platform with a Qwiic connection use the
|
||||
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GPS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
// Callback: printESFALGdata will be called when new ESF ALG data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_ESF_ALG_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoESFALGcallback
|
||||
// / _____ This _must_ be UBX_ESF_ALG_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printESFALGdata(UBX_ESF_ALG_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("TOW: ")); // Print the Time Of Week
|
||||
unsigned long iTOW = ubxDataStruct->iTOW; // iTOW is in milliseconds
|
||||
Serial.print(iTOW);
|
||||
Serial.print(F(" (ms)"));
|
||||
|
||||
Serial.print(F(" Roll: ")); // Print selected data
|
||||
Serial.print((float)ubxDataStruct->roll / 100.0, 2); // Convert roll to degrees
|
||||
|
||||
Serial.print(F(" Pitch: "));
|
||||
Serial.print((float)ubxDataStruct->pitch / 100.0, 2); // Convert pitch to degrees
|
||||
|
||||
Serial.print(F(" Yaw: "));
|
||||
Serial.print((float)ubxDataStruct->yaw / 100.0, 2); // Convert yaw to degrees
|
||||
|
||||
Serial.println(F(" (Degrees)"));
|
||||
}
|
||||
|
||||
// Callback: printESFINSdata will be called when new ESF INS data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_ESF_INS_data_t
|
||||
void printESFINSdata(UBX_ESF_INS_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.print(F("xAccel: ")); // Print selected data
|
||||
Serial.print(ubxDataStruct->xAccel);
|
||||
|
||||
Serial.print(F(" yAccel: "));
|
||||
Serial.print(ubxDataStruct->yAccel);
|
||||
|
||||
Serial.print(F(" zAccel: "));
|
||||
Serial.print(ubxDataStruct->zAccel);
|
||||
|
||||
Serial.println(F(" (m/s^2)"));
|
||||
}
|
||||
|
||||
// Callback: printESFMEASdata will be called when new ESF MEAS data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_ESF_MEAS_data_t
|
||||
// and UBX_ESF_MEAS_sensorData_t
|
||||
void printESFMEASdata(UBX_ESF_MEAS_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("id: ")); // Print selected data
|
||||
Serial.print(ubxDataStruct->id);
|
||||
|
||||
Serial.print(F(" numMeas: "));
|
||||
Serial.println(ubxDataStruct->flags.bits.numMeas);
|
||||
|
||||
for (uint8_t num = 0; num < ubxDataStruct->flags.bits.numMeas; num++) // For each sensor
|
||||
{
|
||||
Serial.print(F("Sensor "));
|
||||
Serial.print(num);
|
||||
|
||||
UBX_ESF_MEAS_sensorData_t sensorData;
|
||||
myGNSS.getSensorFusionMeasurement(&sensorData, *ubxDataStruct, num); // Extract the data for one sensor
|
||||
|
||||
Serial.print(F(": Type: "));
|
||||
Serial.print(sensorData.data.bits.dataType);
|
||||
Serial.print(F(" Data: "));
|
||||
Serial.println(sensorData.data.bits.dataField);
|
||||
}
|
||||
}
|
||||
|
||||
// Callback: printESFSTATUSdata will be called when new ESF STATUS data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_ESF_STATUS_data_t
|
||||
// and UBX_ESF_STATUS_sensorStatus_t
|
||||
void printESFSTATUSdata(UBX_ESF_STATUS_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.print(F("fusionMode: ")); // Print selected data
|
||||
Serial.print(ubxDataStruct->fusionMode);
|
||||
|
||||
Serial.print(F(" numSens: "));
|
||||
Serial.println(ubxDataStruct->numSens);
|
||||
|
||||
for (uint8_t num = 0; num < ubxDataStruct->numSens; num++) // For each sensor
|
||||
{
|
||||
Serial.print(F("Sensor "));
|
||||
Serial.print(num);
|
||||
|
||||
UBX_ESF_STATUS_sensorStatus_t sensorStatus;
|
||||
myGNSS.getSensorFusionStatus(&sensorStatus, *ubxDataStruct, num); // Extract the data for one sensor
|
||||
|
||||
Serial.print(F(": Type: "));
|
||||
Serial.print(sensorStatus.sensStatus1.bits.type);
|
||||
Serial.print(F(" Used: "));
|
||||
Serial.print(sensorStatus.sensStatus1.bits.used);
|
||||
Serial.print(F(" Ready: "));
|
||||
Serial.print(sensorStatus.sensStatus1.bits.ready);
|
||||
Serial.print(F(" Calib Status: "));
|
||||
Serial.print(sensorStatus.sensStatus2.bits.calibStatus);
|
||||
Serial.print(F(" Noisy: "));
|
||||
Serial.println(sensorStatus.faults.bits.noisyMeas);
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one solution per second
|
||||
myGNSS.setHNRNavigationRate(1); //Set the High Navigation Rate to 1Hz
|
||||
|
||||
myGNSS.setI2CpollingWait(50); //Allow checkUblox to poll I2C data every 50ms to keep up with the ESF MEAS messages
|
||||
|
||||
if (myGNSS.setAutoESFALGcallbackPtr(&printESFALGdata) == true) // Enable automatic ESF ALG messages with callback to printESFALGdata
|
||||
Serial.println(F("setAutoESFALGcallback successful"));
|
||||
|
||||
if (myGNSS.setAutoESFINScallbackPtr(&printESFINSdata) == true) // Enable automatic ESF INS messages with callback to printESFINSdata
|
||||
Serial.println(F("setAutoESFINScallback successful"));
|
||||
|
||||
if (myGNSS.setAutoESFMEAScallbackPtr(&printESFMEASdata) == true) // Enable automatic ESF MEAS messages with callback to printESFMEASdata
|
||||
Serial.println(F("setAutoESFMEAScallback successful"));
|
||||
|
||||
if (myGNSS.setAutoESFSTATUScallbackPtr(&printESFSTATUSdata) == true) // Enable automatic ESF STATUS messages with callback to printESFSTATUSdata
|
||||
Serial.println(F("setAutoESFSTATUScallback successful"));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
Serial.print(".");
|
||||
delay(25);
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send RXM RZWX reports over I2C and display them using a callback
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: March 11th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the u-blox GNSS to send RXM RAWX reports automatically
|
||||
and access the data via a callback. No more polling!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GPS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
// Callback: newRAWX will be called when new RXM RAWX data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_RXMRAWX_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMRAWXcallback
|
||||
// / _____ This _must_ be UBX_RXM_RAWX_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void newRAWX(UBX_RXM_RAWX_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("New RAWX data received. It contains "));
|
||||
Serial.print(ubxDataStruct->header.numMeas); // Print numMeas (Number of measurements / blocks)
|
||||
Serial.println(F(" data blocks:"));
|
||||
|
||||
for (uint8_t block = 0; block < ubxDataStruct->header.numMeas; block++) // For each block
|
||||
{
|
||||
Serial.print(F("GNSS ID: "));
|
||||
if (ubxDataStruct->blocks[block].gnssId < 100) Serial.print(F(" ")); // Align the gnssId
|
||||
if (ubxDataStruct->blocks[block].gnssId < 10) Serial.print(F(" ")); // Align the gnssId
|
||||
Serial.print(ubxDataStruct->blocks[block].gnssId);
|
||||
Serial.print(F(" SV ID: "));
|
||||
if (ubxDataStruct->blocks[block].svId < 100) Serial.print(F(" ")); // Align the svId
|
||||
if (ubxDataStruct->blocks[block].svId < 10) Serial.print(F(" ")); // Align the svId
|
||||
Serial.print(ubxDataStruct->blocks[block].svId);
|
||||
|
||||
if (sizeof(double) == 8) // Check if our processor supports 64-bit double
|
||||
{
|
||||
// Convert prMes from uint8_t[8] to 64-bit double
|
||||
// prMes is little-endian
|
||||
double pseudorange;
|
||||
memcpy(&pseudorange, &ubxDataStruct->blocks[block].prMes, 8);
|
||||
Serial.print(F(" PR: "));
|
||||
Serial.print(pseudorange, 3);
|
||||
|
||||
// Convert cpMes from uint8_t[8] to 64-bit double
|
||||
// cpMes is little-endian
|
||||
double carrierPhase;
|
||||
memcpy(&carrierPhase, &ubxDataStruct->blocks[block].cpMes, 8);
|
||||
Serial.print(F(" m CP: "));
|
||||
Serial.print(carrierPhase, 3);
|
||||
Serial.print(F(" cycles"));
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
|
||||
myGNSS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F, so we need to disable the "7F" check in checkUbloxI2C
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one solution per second (RAWX produces a _lot_ of data!)
|
||||
|
||||
myGNSS.setAutoRXMRAWXcallbackPtr(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
Serial.print(".");
|
||||
delay(50);
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send NAV SAT reports over I2C and display them using a callback
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: December 1st, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the u-blox GNSS to send NAV SAT reports automatically
|
||||
and access the data via a callback. No more polling!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GPS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
// Callback: newNAVSAT will be called when new NAV SAT data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_NAV_SAT_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVSATcallback
|
||||
// / _____ This _must_ be UBX_NAV_SAT_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void newNAVSAT(UBX_NAV_SAT_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("New NAV SAT data received. It contains data for "));
|
||||
Serial.print(ubxDataStruct->header.numSvs);
|
||||
if (ubxDataStruct->header.numSvs == 1)
|
||||
Serial.println(F(" SV."));
|
||||
else
|
||||
Serial.println(F(" SVs."));
|
||||
|
||||
// Just for giggles, print the signal strength for each SV as a barchart
|
||||
for (uint16_t block = 0; block < ubxDataStruct->header.numSvs; block++) // For each SV
|
||||
{
|
||||
switch (ubxDataStruct->blocks[block].gnssId) // Print the GNSS ID
|
||||
{
|
||||
case 0:
|
||||
Serial.print(F("GPS "));
|
||||
break;
|
||||
case 1:
|
||||
Serial.print(F("SBAS "));
|
||||
break;
|
||||
case 2:
|
||||
Serial.print(F("Galileo "));
|
||||
break;
|
||||
case 3:
|
||||
Serial.print(F("BeiDou "));
|
||||
break;
|
||||
case 4:
|
||||
Serial.print(F("IMES "));
|
||||
break;
|
||||
case 5:
|
||||
Serial.print(F("QZSS "));
|
||||
break;
|
||||
case 6:
|
||||
Serial.print(F("GLONASS "));
|
||||
break;
|
||||
default:
|
||||
Serial.print(F("UNKNOWN "));
|
||||
break;
|
||||
}
|
||||
|
||||
Serial.print(ubxDataStruct->blocks[block].svId); // Print the SV ID
|
||||
|
||||
if (ubxDataStruct->blocks[block].svId < 10) Serial.print(F(" "));
|
||||
else if (ubxDataStruct->blocks[block].svId < 100) Serial.print(F(" "));
|
||||
else Serial.print(F(" "));
|
||||
|
||||
// Print the signal strength as a bar chart
|
||||
for (uint8_t cno = 0; cno < ubxDataStruct->blocks[block].cno; cno++)
|
||||
Serial.print(F("="));
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one solution per second
|
||||
|
||||
myGNSS.setAutoNAVSATcallbackPtr(&newNAVSAT); // Enable automatic NAV SAT messages with callback to newNAVSAT
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
Serial.print(".");
|
||||
delay(50);
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send NAV SVIN reports over I2C and display them using a callback
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: April 4th, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the u-blox GNSS to send NAV SVIN reports automatically
|
||||
and access the data via a callback. No more polling!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
// Callback: newNAVSVIN will be called when new NAV SVIN data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_NAV_SVIN_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVSVINcallbackPtr
|
||||
// / _____ This _must_ be UBX_NAV_SVIN_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void newNAVSVIN(UBX_NAV_SVIN_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Survey-in is "));
|
||||
if (ubxDataStruct->active == 0)
|
||||
Serial.print(F("not "));
|
||||
Serial.println(F("in progress"));
|
||||
|
||||
Serial.print(F("Survey-in position is "));
|
||||
if (ubxDataStruct->valid == 0)
|
||||
Serial.print(F("not "));
|
||||
Serial.println(F("valid"));
|
||||
|
||||
Serial.print(F("Survey-in observation time (s): "));
|
||||
Serial.println(ubxDataStruct->dur);
|
||||
|
||||
Serial.print(F("ECEF position (cm): "));
|
||||
Serial.print(ubxDataStruct->meanX);
|
||||
Serial.print(F(" ("));
|
||||
if (ubxDataStruct->meanXHP >= 0)
|
||||
Serial.print(F("+"));
|
||||
Serial.print((float)ubxDataStruct->meanXHP * 0.01); // Convert 0.1mm to cm
|
||||
Serial.print(F("), "));
|
||||
Serial.print(ubxDataStruct->meanY);
|
||||
Serial.print(F(" ("));
|
||||
if (ubxDataStruct->meanYHP >= 0)
|
||||
Serial.print(F("+"));
|
||||
Serial.print((float)ubxDataStruct->meanYHP * 0.01); // Convert 0.1mm to cm
|
||||
Serial.print(F("), "));
|
||||
Serial.print(ubxDataStruct->meanZ);
|
||||
Serial.print(F(" ("));
|
||||
if (ubxDataStruct->meanZHP >= 0)
|
||||
Serial.print(F("+"));
|
||||
Serial.print((float)ubxDataStruct->meanZHP * 0.01); // Convert 0.1mm to cm
|
||||
Serial.println(F(")"));
|
||||
|
||||
Serial.print(F("Mean position accuracy (cm): "));
|
||||
Serial.println((float)ubxDataStruct->meanAcc * 0.01); // Convert 0.1mm to cm
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("u-blox Base Station example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
|
||||
//myGNSS.factoryDefault(); delay(5000);
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save the communications port settings to flash and BBR
|
||||
|
||||
// Set up the callback for NAV SVIN. This will enable SVIN messages at the navigation rate
|
||||
myGNSS.setAutoNAVSVINcallbackPtr(&newNAVSVIN);
|
||||
|
||||
while (Serial.available()) Serial.read(); //Clear the serial buffer
|
||||
Serial.println(F("Press any key to begin Survey-In"));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.
|
||||
myGNSS.checkCallbacks(); //Process any waiting callbacks
|
||||
|
||||
if (Serial.available()) // Check if user has pressed a key
|
||||
{
|
||||
bool success = myGNSS.enableSurveyMode(60, 5.000); //Enable Survey in, 60 seconds, 5.0m
|
||||
//bool success = myGNSS.enableSurveyModeFull(86400, 2.000); //Enable Survey in, 24 hours, 2.0m
|
||||
|
||||
Serial.println();
|
||||
|
||||
if (success)
|
||||
{
|
||||
Serial.println(F("Survey-In started!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Survey start failed!"));
|
||||
}
|
||||
|
||||
while (Serial.available()) Serial.read(); //Clear the serial buffer
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send position reports over I2C and display them using a callback
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: April 15th, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to access the callback data from the main loop.
|
||||
The simple way to check if new data is available is to use a global flag: set it in the callback, check it and clear it in the main loop.
|
||||
Or, you can be more sophisticated and use the callback flags themselves.
|
||||
This example shows how to use the sophisticated method.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GPS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
// Callback: callbackPVT will be called when new NAV PVT data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoPVTcallbackPtr
|
||||
// / _____ This _must_ be UBX_NAV_PVT_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void callbackPVT(UBX_NAV_PVT_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println(F("Hey! The NAV PVT callback has been called!"));
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(2); //Produce two solutions per second
|
||||
|
||||
myGNSS.setAutoPVTcallbackPtr(&callbackPVT); // Enable automatic NAV PVT messages with callback to callbackPVT
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
|
||||
// Check if new NAV PVT data has been received:
|
||||
// If myGNSS.packetUBXNAVPVT->automaticFlags.flags.bits.callbackCopyValid is true, it indicates new PVT data has been received and has been copied.
|
||||
// automaticFlags.flags.bits.callbackCopyValid will be cleared automatically when the callback is called.
|
||||
|
||||
if (myGNSS.packetUBXNAVPVT->automaticFlags.flags.bits.callbackCopyValid == true)
|
||||
{
|
||||
// But, we can manually clear the callback flag too. This will prevent the callback from being called!
|
||||
myGNSS.packetUBXNAVPVT->automaticFlags.flags.bits.callbackCopyValid = false; // Comment this line if you still want the callback to be called
|
||||
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Time: ")); // Print the time
|
||||
uint8_t hms = myGNSS.packetUBXNAVPVT->callbackData->hour; // Print the hours
|
||||
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
|
||||
Serial.print(hms);
|
||||
Serial.print(F(":"));
|
||||
hms = myGNSS.packetUBXNAVPVT->callbackData->min; // Print the minutes
|
||||
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
|
||||
Serial.print(hms);
|
||||
Serial.print(F(":"));
|
||||
hms = myGNSS.packetUBXNAVPVT->callbackData->sec; // Print the seconds
|
||||
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
|
||||
Serial.print(hms);
|
||||
Serial.print(F("."));
|
||||
unsigned long millisecs = myGNSS.packetUBXNAVPVT->callbackData->iTOW % 1000; // Print the milliseconds
|
||||
if (millisecs < 100) Serial.print(F("0")); // Print the trailing zeros correctly
|
||||
if (millisecs < 10) Serial.print(F("0"));
|
||||
Serial.print(millisecs);
|
||||
|
||||
long latitude = myGNSS.packetUBXNAVPVT->callbackData->lat; // Print the latitude
|
||||
Serial.print(F(" Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.packetUBXNAVPVT->callbackData->lon; // Print the longitude
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.packetUBXNAVPVT->callbackData->hMSL; // Print the height above mean sea level
|
||||
Serial.print(F(" Height above MSL: "));
|
||||
Serial.print(altitude);
|
||||
Serial.println(F(" (mm)"));
|
||||
}
|
||||
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed. There will not be any in this example, unless you commented the line above
|
||||
|
||||
Serial.print(".");
|
||||
delay(50);
|
||||
}
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send NAV PVT reports over I2C and log them to file on SD card
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: October 18th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the u-blox GNSS to send NAV PVT reports automatically
|
||||
and log the data to SD card in UBX format.
|
||||
|
||||
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
|
||||
but can be adapted by changing the chip select pin and SPI definitions:
|
||||
https://www.sparkfun.com/products/16829
|
||||
https://www.sparkfun.com/products/16401
|
||||
|
||||
Hardware Connections:
|
||||
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
|
||||
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
|
||||
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
|
||||
Connect an antenna to your GNSS board if required.
|
||||
Insert a formatted micro-SD card into the socket on the Carrier Board.
|
||||
Connect the Carrier Board to your computer using a USB-C cable.
|
||||
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
|
||||
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
|
||||
Select "Artemis MicroMod Processor" as the board type.
|
||||
Press upload to upload the code onto the Artemis.
|
||||
Open the Serial Monitor at 115200 baud to see the output.
|
||||
|
||||
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
|
||||
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
|
||||
|
||||
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
|
||||
You can replay and analyze the data using u-center:
|
||||
https://www.u-blox.com/en/product/u-center
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
File myFile; //File that all GNSS data is written to
|
||||
|
||||
//Define the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
|
||||
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#else
|
||||
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
|
||||
#endif
|
||||
#else
|
||||
|
||||
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
|
||||
|
||||
#endif
|
||||
|
||||
#define packetLength 100 // NAV PVT is 92 + 8 bytes in length (including the sync chars, class, id, length and checksum bytes)
|
||||
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
|
||||
|
||||
// Callback: printPVTdata will be called when new NAV PVT data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoPVTcallback
|
||||
// / _____ This _must_ be UBX_NAV_PVT_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Time: ")); // Print the time
|
||||
uint8_t hms = ubxDataStruct->hour; // Print the hours
|
||||
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
|
||||
Serial.print(hms);
|
||||
Serial.print(F(":"));
|
||||
hms = ubxDataStruct->min; // Print the minutes
|
||||
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
|
||||
Serial.print(hms);
|
||||
Serial.print(F(":"));
|
||||
hms = ubxDataStruct->sec; // Print the seconds
|
||||
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
|
||||
Serial.print(hms);
|
||||
Serial.print(F("."));
|
||||
unsigned long millisecs = ubxDataStruct->iTOW % 1000; // Print the milliseconds
|
||||
if (millisecs < 100) Serial.print(F("0")); // Print the trailing zeros correctly
|
||||
if (millisecs < 10) Serial.print(F("0"));
|
||||
Serial.print(millisecs);
|
||||
|
||||
long latitude = ubxDataStruct->lat; // Print the latitude
|
||||
Serial.print(F(" Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = ubxDataStruct->lon; // Print the longitude
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = ubxDataStruct->hMSL; // Print the height above mean sea level
|
||||
Serial.print(F(" Height above MSL: "));
|
||||
Serial.print(altitude);
|
||||
Serial.println(F(" (mm)"));
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin(); // Start I2C communication with the GNSS
|
||||
|
||||
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
|
||||
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
|
||||
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
|
||||
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
|
||||
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
|
||||
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
|
||||
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
|
||||
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
|
||||
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
|
||||
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
|
||||
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
|
||||
#endif
|
||||
#endif
|
||||
|
||||
while (Serial.available()) // Make sure the Serial buffer is empty
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
|
||||
Serial.println(F("Press any key to start logging."));
|
||||
|
||||
while (!Serial.available()) // Wait for the user to press a key
|
||||
{
|
||||
; // Do nothing
|
||||
}
|
||||
|
||||
delay(100); // Wait, just in case multiple characters were sent
|
||||
|
||||
while (Serial.available()) // Empty the Serial buffer
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
|
||||
Serial.println("Initializing SD card...");
|
||||
|
||||
// See if the card is present and can be initialized:
|
||||
if (!SD.begin(sdChipSelect))
|
||||
{
|
||||
Serial.println("Card failed, or not present. Freezing...");
|
||||
// don't do anything more:
|
||||
while (1);
|
||||
}
|
||||
Serial.println("SD card initialized.");
|
||||
|
||||
// Create or open a file called "NAV_PVT.ubx" on the SD card.
|
||||
// If the file already exists, the new data is appended to the end of the file.
|
||||
myFile = SD.open("NAV_PVT.ubx", FILE_WRITE);
|
||||
if(!myFile)
|
||||
{
|
||||
Serial.println(F("Failed to create UBX data file! Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful GNSS debug messages on Serial
|
||||
|
||||
// NAV PVT messages are 100 bytes long.
|
||||
// In this example, the data will arrive no faster than one message per second.
|
||||
// So, setting the file buffer size to 301 bytes should be more than adequate.
|
||||
// I.e. room for three messages plus an empty tail byte.
|
||||
myGNSS.setFileBufferSize(301); // setFileBufferSize must be called _before_ .begin
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
|
||||
// (This will also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
|
||||
//myGNSS.factoryDefault(); delay(5000);
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second
|
||||
|
||||
myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
|
||||
|
||||
myGNSS.logNAVPVT(); // Enable NAV PVT data logging
|
||||
|
||||
myBuffer = new uint8_t[packetLength]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
Serial.println(F("Press any key to stop logging."));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
if (myGNSS.fileBufferAvailable() >= packetLength) // Check to see if a new packetLength-byte NAV PVT message has been stored
|
||||
{
|
||||
myGNSS.extractFileBufferData(myBuffer, packetLength); // Extract exactly packetLength bytes from the UBX file buffer and put them into myBuffer
|
||||
|
||||
myFile.write(myBuffer, packetLength); // Write exactly packetLength bytes from myBuffer to the ubxDataFile on the SD card
|
||||
|
||||
//printBuffer(myBuffer); // Uncomment this line to print the data as Hexadecimal bytes
|
||||
}
|
||||
|
||||
if (Serial.available()) // Check if the user wants to stop logging
|
||||
{
|
||||
myFile.close(); // Close the data file
|
||||
Serial.println(F("\r\nLogging stopped. Freezing..."));
|
||||
while(1); // Do nothing more
|
||||
}
|
||||
|
||||
Serial.print(".");
|
||||
delay(50);
|
||||
}
|
||||
|
||||
// Print the buffer contents as Hexadecimal bytes
|
||||
// You should see:
|
||||
// SYNC CHAR 1: 0xB5
|
||||
// SYNC CHAR 2: 0x62
|
||||
// CLASS: 0x01 for NAV
|
||||
// ID: 0x07 for PVT
|
||||
// LENGTH: 2-bytes Little Endian (0x5C00 = 92 bytes for NAV PVT)
|
||||
// PAYLOAD: LENGTH bytes
|
||||
// CHECKSUM_A
|
||||
// CHECKSUM_B
|
||||
// Please see the u-blox protocol specification for more details
|
||||
void printBuffer(uint8_t *ptr)
|
||||
{
|
||||
for (int i = 0; i < packetLength; i++)
|
||||
{
|
||||
if (ptr[i] < 16) Serial.print("0"); // Print a leading zero if required
|
||||
Serial.print(ptr[i], HEX); // Print the byte as Hexadecimal
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send TIM TM2 reports over I2C and log them to file on SD card
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: October 18th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the u-blox GNSS to send TIM TM2 reports automatically
|
||||
and log the data to SD card in UBX format.
|
||||
|
||||
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
|
||||
but can be adapted by changing the chip select pin and SPI definitions:
|
||||
https://www.sparkfun.com/products/16829
|
||||
https://www.sparkfun.com/products/16401
|
||||
|
||||
Hardware Connections:
|
||||
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
|
||||
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
|
||||
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
|
||||
Connect an antenna to your GNSS board if required.
|
||||
Insert a formatted micro-SD card into the socket on the Carrier Board.
|
||||
Connect the Carrier Board to your computer using a USB-C cable.
|
||||
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
|
||||
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
|
||||
Select "Artemis MicroMod Processor" as the board type.
|
||||
Press upload to upload the code onto the Artemis.
|
||||
Open the Serial Monitor at 115200 baud to see the output.
|
||||
|
||||
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
|
||||
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
|
||||
|
||||
Connecting the PPS (Pulse Per Second) breakout pin to the INT (Interrupt) pin with a jumper wire
|
||||
will cause a TIM TM2 message to be produced once per second. You can then study the timing of the
|
||||
pulse edges with nanosecond resolution!
|
||||
|
||||
Note: TIM TM2 can only capture the timing of one rising edge and one falling edge per
|
||||
navigation solution. So with setNavigationFrequency set to 1Hz, we can only see the timing
|
||||
of one rising and one falling edge per second. If the frequency of the signal on the INT pin
|
||||
is higher than 1Hz, we will only be able to see the timing of the most recent edges.
|
||||
However, the module can count the number of rising edges too, at rates faster than the navigation rate.
|
||||
|
||||
TIM TM2 messages are only produced when a rising or falling edge is detected on the INT pin.
|
||||
If you disconnect your PPS to INT jumper wire, the messages will stop.
|
||||
|
||||
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
|
||||
You can replay and analyze the data using u-center:
|
||||
https://www.u-blox.com/en/product/u-center
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
NEO-M9N: https://www.sparkfun.com/products/17285
|
||||
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
File myFile; //File that all GNSS data is written to
|
||||
|
||||
//Define the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
|
||||
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#else
|
||||
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
|
||||
#endif
|
||||
#else
|
||||
|
||||
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
|
||||
|
||||
#endif
|
||||
|
||||
#define packetLength 36 // TIM TM2 is 28 + 8 bytes in length (including the sync chars, class, id, length and checksum bytes)
|
||||
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
|
||||
|
||||
int dotsPrinted = 0; // Print dots in rows of 50 while waiting for a TIM TM2 message
|
||||
|
||||
// Callback: printTIMTM2data will be called when new TIM TM2 data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_TIM_TM2_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoTIMTM2callback
|
||||
// / _____ This _must_ be UBX_TIM_TM2_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printTIMTM2data(UBX_TIM_TM2_data_t *ubxDataStruct)
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("newFallingEdge: ")); // 1 if a new falling edge was detected
|
||||
Serial.print(ubxDataStruct->flags.bits.newFallingEdge);
|
||||
|
||||
Serial.print(F(" newRisingEdge: ")); // 1 if a new rising edge was detected
|
||||
Serial.print(ubxDataStruct->flags.bits.newRisingEdge);
|
||||
|
||||
Serial.print(F(" Rising Edge Counter: ")); // Rising edge counter
|
||||
Serial.print(ubxDataStruct->count);
|
||||
|
||||
Serial.print(F(" towMsR: ")); // Time Of Week of rising edge (ms)
|
||||
Serial.print(ubxDataStruct->towMsR);
|
||||
|
||||
Serial.print(F(" towSubMsR: ")); // Millisecond fraction of Time Of Week of rising edge in nanoseconds
|
||||
Serial.print(ubxDataStruct->towSubMsR);
|
||||
|
||||
Serial.print(F(" towMsF: ")); // Time Of Week of falling edge (ms)
|
||||
Serial.print(ubxDataStruct->towMsF);
|
||||
|
||||
Serial.print(F(" towSubMsF: ")); // Millisecond fraction of Time Of Week of falling edge in nanoseconds
|
||||
Serial.println(ubxDataStruct->towSubMsF);
|
||||
|
||||
dotsPrinted = 0; // Reset dotsPrinted
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin(); // Start I2C communication with the GNSS
|
||||
|
||||
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
|
||||
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
|
||||
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
|
||||
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
|
||||
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
|
||||
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
|
||||
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
|
||||
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
|
||||
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
|
||||
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
|
||||
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
|
||||
#endif
|
||||
#endif
|
||||
|
||||
while (Serial.available()) // Make sure the Serial buffer is empty
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
|
||||
Serial.println(F("Press any key to start logging."));
|
||||
|
||||
while (!Serial.available()) // Wait for the user to press a key
|
||||
{
|
||||
; // Do nothing
|
||||
}
|
||||
|
||||
delay(100); // Wait, just in case multiple characters were sent
|
||||
|
||||
while (Serial.available()) // Empty the Serial buffer
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
|
||||
Serial.println("Initializing SD card...");
|
||||
|
||||
// See if the card is present and can be initialized:
|
||||
if (!SD.begin(sdChipSelect))
|
||||
{
|
||||
Serial.println("Card failed, or not present. Freezing...");
|
||||
// don't do anything more:
|
||||
while (1);
|
||||
}
|
||||
Serial.println("SD card initialized.");
|
||||
|
||||
// Create or open a file called "TIM_TM2.ubx" on the SD card.
|
||||
// If the file already exists, the new data is appended to the end of the file.
|
||||
myFile = SD.open("TIM_TM2.ubx", FILE_WRITE);
|
||||
if(!myFile)
|
||||
{
|
||||
Serial.println(F("Failed to create UBX data file! Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful GNSS debug messages on Serial
|
||||
|
||||
// TIM TM2 messages are 36 bytes long.
|
||||
// In this example, the data will arrive no faster than one message per second.
|
||||
// So, setting the file buffer size to 109 bytes should be more than adequate.
|
||||
// I.e. room for three messages plus an empty tail byte.
|
||||
myGNSS.setFileBufferSize(109); // setFileBufferSize must be called _before_ .begin
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
|
||||
// (This will also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
|
||||
//myGNSS.factoryDefault(); delay(5000);
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second
|
||||
|
||||
myGNSS.setAutoTIMTM2callbackPtr(&printTIMTM2data); // Enable automatic TIM TM2 messages with callback to printTIMTM2data
|
||||
|
||||
myGNSS.logTIMTM2(); // Enable TIM TM2 data logging
|
||||
|
||||
myBuffer = new uint8_t[packetLength]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
Serial.println(F("Press any key to stop logging."));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
if (myGNSS.fileBufferAvailable() >= packetLength) // Check to see if a new packetLength-byte TIM TM2 message has been stored
|
||||
{
|
||||
myGNSS.extractFileBufferData(myBuffer, packetLength); // Extract exactly packetLength bytes from the UBX file buffer and put them into myBuffer
|
||||
|
||||
myFile.write(myBuffer, packetLength); // Write exactly packetLength bytes from myBuffer to the ubxDataFile on the SD card
|
||||
|
||||
//printBuffer(myBuffer); // Uncomment this line to print the data
|
||||
}
|
||||
|
||||
if (Serial.available()) // Check if the user wants to stop logging
|
||||
{
|
||||
myFile.close(); // Close the data file
|
||||
Serial.println(F("\r\nLogging stopped. Freezing..."));
|
||||
while(1); // Do nothing more
|
||||
}
|
||||
|
||||
Serial.print("."); // Print dots in rows of 50
|
||||
delay(50);
|
||||
if (++dotsPrinted > 50)
|
||||
{
|
||||
Serial.println();
|
||||
dotsPrinted = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Print the buffer contents as Hexadecimal
|
||||
// You should see:
|
||||
// SYNC CHAR 1: 0xB5
|
||||
// SYNC CHAR 2: 0x62
|
||||
// CLASS: 0x0D for TIM
|
||||
// ID: 0x03 for TM2
|
||||
// LENGTH: 2-bytes Little Endian (0x1C00 = 28 bytes for TIM TM2)
|
||||
// PAYLOAD: LENGTH bytes
|
||||
// CHECKSUM_A
|
||||
// CHECKSUM_B
|
||||
// Please see the u-blox protocol specification for more details
|
||||
void printBuffer(uint8_t *ptr)
|
||||
{
|
||||
for (int i = 0; i < packetLength; i++)
|
||||
{
|
||||
if (ptr[i] < 16) Serial.print("0"); // Print a leading zero if required
|
||||
Serial.print(ptr[i], HEX); // Print the byte as Hexadecimal
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
|
@ -0,0 +1,297 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send RXM SFRBX and RAWX reports over I2C and log them to file on SD card
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: October 18th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the u-blox GNSS to send RXM SFRBX and RAWX reports automatically
|
||||
and log the data to SD card in UBX format.
|
||||
|
||||
** Please note: this example will only work on u-blox ADR or High Precision GNSS or Time Sync products **
|
||||
|
||||
** Please note: this example will only work on processors like the Artemis which have plenty of RAM available **
|
||||
|
||||
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
|
||||
You can replay and analyze the data using u-center:
|
||||
https://www.u-blox.com/en/product/u-center
|
||||
Or you can use (e.g.) RTKLIB to analyze the data and extract your precise location or produce
|
||||
Post-Processed Kinematic data:
|
||||
https://rtklibexplorer.wordpress.com/
|
||||
http://rtkexplorer.com/downloads/rtklib-code/
|
||||
|
||||
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
|
||||
but can be adapted by changing the chip select pin and SPI definitions:
|
||||
https://www.sparkfun.com/products/16829
|
||||
https://www.sparkfun.com/products/16401
|
||||
|
||||
Hardware Connections:
|
||||
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
|
||||
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
|
||||
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
|
||||
Connect an antenna to your GNSS board if required.
|
||||
Insert a formatted micro-SD card into the socket on the Carrier Board.
|
||||
Connect the Carrier Board to your computer using a USB-C cable.
|
||||
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
|
||||
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
|
||||
Select "Artemis MicroMod Processor" as the board type.
|
||||
Press upload to upload the code onto the Artemis.
|
||||
Open the Serial Monitor at 115200 baud to see the output.
|
||||
|
||||
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
|
||||
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
File myFile; //File that all GNSS data is written to
|
||||
|
||||
//Define the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
|
||||
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#else
|
||||
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
|
||||
#endif
|
||||
#else
|
||||
|
||||
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
|
||||
|
||||
#endif
|
||||
|
||||
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
|
||||
#define fileBufferSize 16384 // Allocate 16KBytes of RAM for UBX message storage
|
||||
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
|
||||
|
||||
unsigned long lastPrint; // Record when the last Serial print took place
|
||||
|
||||
// Note: we'll keep a count of how many SFRBX and RAWX messages arrive - but the count will not be completely accurate.
|
||||
// If two or more SFRBX messages arrive together as a group and are processed by one call to checkUblox, the count will
|
||||
// only increase by one.
|
||||
|
||||
int numSFRBX = 0; // Keep count of how many SFRBX message groups have been received (see note above)
|
||||
int numRAWX = 0; // Keep count of how many RAWX message groups have been received (see note above)
|
||||
|
||||
// Callback: newSFRBX will be called when new RXM SFRBX data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_RXMSFRBX_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMSFRBXcallback
|
||||
// / _____ This _must_ be UBX_RXM_SFRBX_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void newSFRBX(UBX_RXM_SFRBX_data_t *ubxDataStruct)
|
||||
{
|
||||
numSFRBX++; // Increment the count
|
||||
}
|
||||
|
||||
// Callback: newRAWX will be called when new RXM RAWX data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_RXMRAWX_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMRAWXcallback
|
||||
// / _____ This _must_ be UBX_RXM_RAWX_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void newRAWX(UBX_RXM_RAWX_data_t *ubxDataStruct)
|
||||
{
|
||||
numRAWX++; // Increment the count
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
pinMode(LED_BUILTIN, OUTPUT); // Flash LED_BUILTIN each time we write to the SD card
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
Wire.begin(); // Start I2C communication
|
||||
|
||||
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
|
||||
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
|
||||
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
|
||||
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
|
||||
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
|
||||
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
|
||||
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
|
||||
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
|
||||
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
|
||||
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
|
||||
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
|
||||
#endif
|
||||
#endif
|
||||
|
||||
while (Serial.available()) // Make sure the Serial buffer is empty
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
|
||||
Serial.println(F("Press any key to start logging."));
|
||||
|
||||
while (!Serial.available()) // Wait for the user to press a key
|
||||
{
|
||||
; // Do nothing
|
||||
}
|
||||
|
||||
delay(100); // Wait, just in case multiple characters were sent
|
||||
|
||||
while (Serial.available()) // Empty the Serial buffer
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
|
||||
Serial.println("Initializing SD card...");
|
||||
|
||||
// See if the card is present and can be initialized:
|
||||
if (!SD.begin(sdChipSelect))
|
||||
{
|
||||
Serial.println("Card failed, or not present. Freezing...");
|
||||
// don't do anything more:
|
||||
while (1);
|
||||
}
|
||||
Serial.println("SD card initialized.");
|
||||
|
||||
// Create or open a file called "RXM_RAWX.ubx" on the SD card.
|
||||
// If the file already exists, the new data is appended to the end of the file.
|
||||
myFile = SD.open("RXM_RAWX.ubx", FILE_WRITE);
|
||||
if(!myFile)
|
||||
{
|
||||
Serial.println(F("Failed to create UBX data file! Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable lots of helpful GNSS debug messages on Serial
|
||||
//myGNSS.enableDebugging(Serial, true); // Or, uncomment this line to enable only the important GNSS debug messages on Serial
|
||||
|
||||
myGNSS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F, so we need to disable the "7F" check in checkUbloxI2C
|
||||
|
||||
// RAWX messages can be over 2KBytes in size, so we need to make sure we allocate enough RAM to hold all the data.
|
||||
// SD cards can occasionally 'hiccup' and a write takes much longer than usual. The buffer needs to be big enough
|
||||
// to hold the backlog of data if/when this happens.
|
||||
// getMaxFileBufferAvail will tell us the maximum number of bytes which the file buffer has contained.
|
||||
myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
|
||||
// (This will also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
|
||||
//myGNSS.factoryDefault(); delay(5000);
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second (that's plenty for Precise Point Positioning)
|
||||
|
||||
myGNSS.setAutoRXMSFRBXcallbackPtr(&newSFRBX); // Enable automatic RXM SFRBX messages with callback to newSFRBX
|
||||
|
||||
myGNSS.logRXMSFRBX(); // Enable RXM SFRBX data logging
|
||||
|
||||
myGNSS.setAutoRXMRAWXcallbackPtr(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX
|
||||
|
||||
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
|
||||
|
||||
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
Serial.println(F("Press any key to stop logging."));
|
||||
|
||||
lastPrint = millis(); // Initialize lastPrint
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
|
||||
|
||||
myGNSS.extractFileBufferData(myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
|
||||
|
||||
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
|
||||
|
||||
// In case the SD writing is slow or there is a lot of data to write, keep checking for the arrival of new data
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off again
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
if (millis() > (lastPrint + 1000)) // Print the message count once per second
|
||||
{
|
||||
Serial.print(F("Number of message groups received: SFRBX: ")); // Print how many message groups have been received (see note above)
|
||||
Serial.print(numSFRBX);
|
||||
Serial.print(F(" RAWX: "));
|
||||
Serial.println(numRAWX);
|
||||
|
||||
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now)
|
||||
|
||||
//Serial.print(F("The maximum number of bytes which the file buffer has contained is: ")); // It is a fun thing to watch how full the buffer gets
|
||||
//Serial.println(maxBufferBytes);
|
||||
|
||||
if (maxBufferBytes > ((fileBufferSize / 5) * 4)) // Warn the user if fileBufferSize was more than 80% full
|
||||
{
|
||||
Serial.println(F("Warning: the file buffer has been over 80% full. Some data may have been lost."));
|
||||
}
|
||||
|
||||
lastPrint = millis(); // Update lastPrint
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
if (Serial.available()) // Check if the user wants to stop logging
|
||||
{
|
||||
uint16_t remainingBytes = myGNSS.fileBufferAvailable(); // Check if there are any bytes remaining in the file buffer
|
||||
|
||||
while (remainingBytes > 0) // While there is still data in the file buffer
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
|
||||
|
||||
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
|
||||
if (bytesToWrite > sdWriteSize)
|
||||
{
|
||||
bytesToWrite = sdWriteSize;
|
||||
}
|
||||
|
||||
myGNSS.extractFileBufferData(myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
|
||||
|
||||
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
|
||||
|
||||
remainingBytes -= bytesToWrite; // Decrement remainingBytes
|
||||
}
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off
|
||||
|
||||
myFile.close(); // Close the data file
|
||||
|
||||
Serial.println(F("Logging stopped. Freezing..."));
|
||||
while(1); // Do nothing more
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
}
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send RXM SFRBX and RAWX reports over I2C and log them to file on SD card
|
||||
** without using callbacks **
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: October 18th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the u-blox GNSS to send RXM SFRBX and RAWX reports automatically
|
||||
and log the data to SD card in UBX format ** without using callbacks **
|
||||
|
||||
** Please note: this example will only work on u-blox ADR or High Precision GNSS or Time Sync products **
|
||||
|
||||
** Please note: this example will only work on processors like the Artemis which have plenty of RAM available **
|
||||
|
||||
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
|
||||
You can replay and analyze the data using u-center:
|
||||
https://www.u-blox.com/en/product/u-center
|
||||
Or you can use (e.g.) RTKLIB to analyze the data and extract your precise location or produce
|
||||
Post-Processed Kinematic data:
|
||||
https://rtklibexplorer.wordpress.com/
|
||||
http://rtkexplorer.com/downloads/rtklib-code/
|
||||
|
||||
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
|
||||
but can be adapted by changing the chip select pin and SPI definitions:
|
||||
https://www.sparkfun.com/products/16829
|
||||
https://www.sparkfun.com/products/16401
|
||||
|
||||
Hardware Connections:
|
||||
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
|
||||
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
|
||||
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
|
||||
Connect an antenna to your GNSS board if required.
|
||||
Insert a formatted micro-SD card into the socket on the Carrier Board.
|
||||
Connect the Carrier Board to your computer using a USB-C cable.
|
||||
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
|
||||
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
|
||||
Select "Artemis MicroMod Processor" as the board type.
|
||||
Press upload to upload the code onto the Artemis.
|
||||
Open the Serial Monitor at 115200 baud to see the output.
|
||||
|
||||
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
|
||||
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
File myFile; //File that all GNSS data is written to
|
||||
|
||||
//Define the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
|
||||
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#else
|
||||
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
|
||||
#endif
|
||||
#else
|
||||
|
||||
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
|
||||
|
||||
#endif
|
||||
|
||||
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
|
||||
#define fileBufferSize 16384 // Allocate 16KBytes of RAM for UBX message storage
|
||||
uint8_t *myBuffer; // A buffer to hold the data while we write it to SD card
|
||||
|
||||
unsigned long lastPrint; // Record when the last Serial print took place
|
||||
unsigned long bytesWritten = 0; // Record how many bytes have been written to SD card
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
pinMode(LED_BUILTIN, OUTPUT); // Flash LED_BUILTIN each time we write to the SD card
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
Wire.begin(); // Start I2C communication
|
||||
|
||||
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
|
||||
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
|
||||
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
|
||||
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
|
||||
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
|
||||
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
|
||||
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
|
||||
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
|
||||
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
|
||||
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
|
||||
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
|
||||
#endif
|
||||
#endif
|
||||
|
||||
while (Serial.available()) // Make sure the Serial buffer is empty
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
|
||||
Serial.println(F("Press any key to start logging."));
|
||||
|
||||
while (!Serial.available()) // Wait for the user to press a key
|
||||
{
|
||||
; // Do nothing
|
||||
}
|
||||
|
||||
delay(100); // Wait, just in case multiple characters were sent
|
||||
|
||||
while (Serial.available()) // Empty the Serial buffer
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
|
||||
Serial.println("Initializing SD card...");
|
||||
|
||||
// See if the card is present and can be initialized:
|
||||
if (!SD.begin(sdChipSelect))
|
||||
{
|
||||
Serial.println("Card failed, or not present. Freezing...");
|
||||
// don't do anything more:
|
||||
while (1);
|
||||
}
|
||||
Serial.println("SD card initialized.");
|
||||
|
||||
// Create or open a file called "RXM_RAWX.ubx" on the SD card.
|
||||
// If the file already exists, the new data is appended to the end of the file.
|
||||
myFile = SD.open("RXM_RAWX.ubx", FILE_WRITE);
|
||||
if(!myFile)
|
||||
{
|
||||
Serial.println(F("Failed to create UBX data file! Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable lots of helpful GNSS debug messages on Serial
|
||||
//myGNSS.enableDebugging(Serial, true); // Or, uncomment this line to enable only the important GNSS debug messages on Serial
|
||||
|
||||
myGNSS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F, so we need to disable the "7F" check in checkUbloxI2C
|
||||
|
||||
// RAWX messages can be over 2KBytes in size, so we need to make sure we allocate enough RAM to hold all the data.
|
||||
// SD cards can occasionally 'hiccup' and a write takes much longer than usual. The buffer needs to be big enough
|
||||
// to hold the backlog of data if/when this happens.
|
||||
// getMaxFileBufferAvail will tell us the maximum number of bytes which the file buffer has contained.
|
||||
myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
|
||||
// (This will also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
|
||||
//myGNSS.factoryDefault(); delay(5000);
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second (that's plenty for Precise Point Positioning)
|
||||
|
||||
myGNSS.setAutoRXMSFRBX(true, false); // Enable automatic RXM SFRBX messages: without callback; without implicit update
|
||||
|
||||
myGNSS.logRXMSFRBX(); // Enable RXM SFRBX data logging
|
||||
|
||||
myGNSS.setAutoRXMRAWX(true, false); // Enable automatic RXM RAWX messages: without callback; without implicit update
|
||||
|
||||
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
|
||||
|
||||
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
Serial.println(F("Press any key to stop logging."));
|
||||
|
||||
lastPrint = millis(); // Initialize lastPrint
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
|
||||
|
||||
myGNSS.extractFileBufferData(myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
|
||||
|
||||
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
|
||||
|
||||
bytesWritten += sdWriteSize; // Update bytesWritten
|
||||
|
||||
// In case the SD writing is slow or there is a lot of data to write, keep checking for the arrival of new data
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off again
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
if (millis() > (lastPrint + 1000)) // Print bytesWritten once per second
|
||||
{
|
||||
Serial.print(F("The number of bytes written to SD card is ")); // Print how many bytes have been written to SD card
|
||||
Serial.println(bytesWritten);
|
||||
|
||||
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now)
|
||||
|
||||
//Serial.print(F("The maximum number of bytes which the file buffer has contained is: ")); // It is a fun thing to watch how full the buffer gets
|
||||
//Serial.println(maxBufferBytes);
|
||||
|
||||
if (maxBufferBytes > ((fileBufferSize / 5) * 4)) // Warn the user if fileBufferSize was more than 80% full
|
||||
{
|
||||
Serial.println(F("Warning: the file buffer has been over 80% full. Some data may have been lost."));
|
||||
}
|
||||
|
||||
lastPrint = millis(); // Update lastPrint
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
if (Serial.available()) // Check if the user wants to stop logging
|
||||
{
|
||||
uint16_t remainingBytes = myGNSS.fileBufferAvailable(); // Check if there are any bytes remaining in the file buffer
|
||||
|
||||
while (remainingBytes > 0) // While there is still data in the file buffer
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
|
||||
|
||||
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
|
||||
if (bytesToWrite > sdWriteSize)
|
||||
{
|
||||
bytesToWrite = sdWriteSize;
|
||||
}
|
||||
|
||||
myGNSS.extractFileBufferData(myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
|
||||
|
||||
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
|
||||
|
||||
bytesWritten += bytesToWrite; // Update bytesWritten
|
||||
|
||||
remainingBytes -= bytesToWrite; // Decrement remainingBytes
|
||||
}
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off
|
||||
|
||||
Serial.print(F("The total number of bytes written to SD card is ")); // Print how many bytes have been written to SD card
|
||||
Serial.println(bytesWritten);
|
||||
|
||||
myFile.close(); // Close the data file
|
||||
|
||||
Serial.println(F("Logging stopped. Freezing..."));
|
||||
while(1); // Do nothing more
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
}
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send RXM SFRBX and RAWX reports over I2C and log them to file on SD card
|
||||
without using callbacks and ** as fast as your module can go! **
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: October 18th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the u-blox GNSS to send RXM SFRBX and RAWX reports automatically
|
||||
and log the data to SD card in UBX format without using callbacks and ** as fast as your module can go! **
|
||||
|
||||
** Please note: this example will only work on u-blox ADR or High Precision GNSS or Time Sync products **
|
||||
|
||||
** Please note: this example will only work on processors like the Artemis which have plenty of RAM available **
|
||||
|
||||
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
|
||||
You can replay and analyze the data using u-center:
|
||||
https://www.u-blox.com/en/product/u-center
|
||||
Or you can use (e.g.) RTKLIB to analyze the data and extract your precise location or produce
|
||||
Post-Processed Kinematic data:
|
||||
https://rtklibexplorer.wordpress.com/
|
||||
http://rtkexplorer.com/downloads/rtklib-code/
|
||||
|
||||
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
|
||||
but can be adapted by changing the chip select pin and SPI definitions:
|
||||
https://www.sparkfun.com/products/16829
|
||||
https://www.sparkfun.com/products/16401
|
||||
|
||||
Hardware Connections:
|
||||
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
|
||||
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
|
||||
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
|
||||
Connect an antenna to your GNSS board if required.
|
||||
Insert a formatted micro-SD card into the socket on the Carrier Board.
|
||||
Connect the Carrier Board to your computer using a USB-C cable.
|
||||
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
|
||||
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
|
||||
Select "Artemis MicroMod Processor" as the board type.
|
||||
Press upload to upload the code onto the Artemis.
|
||||
Open the Serial Monitor at 115200 baud to see the output.
|
||||
|
||||
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
|
||||
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
File myFile; //File that all GNSS data is written to
|
||||
|
||||
//Define the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
|
||||
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#else
|
||||
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
|
||||
#endif
|
||||
#else
|
||||
|
||||
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
|
||||
|
||||
#endif
|
||||
|
||||
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
|
||||
#define fileBufferSize 32768 // Allocate 32KBytes of RAM for UBX message storage
|
||||
uint8_t *myBuffer; // A buffer to hold the data while we write it to SD card
|
||||
|
||||
unsigned long lastPrint; // Record when the last Serial print took place
|
||||
unsigned long bytesWritten = 0; // Record how many bytes have been written to SD card
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
pinMode(LED_BUILTIN, OUTPUT); // Flash LED_BUILTIN each time we write to the SD card
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
Wire.begin(); // Start I2C communication
|
||||
|
||||
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
|
||||
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
|
||||
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
|
||||
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
|
||||
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
|
||||
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
|
||||
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
|
||||
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
|
||||
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
|
||||
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
|
||||
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
|
||||
#endif
|
||||
#endif
|
||||
|
||||
while (Serial.available()) // Make sure the Serial buffer is empty
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
|
||||
Serial.println(F("Press any key to start logging."));
|
||||
|
||||
while (!Serial.available()) // Wait for the user to press a key
|
||||
{
|
||||
; // Do nothing
|
||||
}
|
||||
|
||||
delay(100); // Wait, just in case multiple characters were sent
|
||||
|
||||
while (Serial.available()) // Empty the Serial buffer
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
|
||||
Serial.println("Initializing SD card...");
|
||||
|
||||
// See if the card is present and can be initialized:
|
||||
if (!SD.begin(sdChipSelect))
|
||||
{
|
||||
Serial.println("Card failed, or not present. Freezing...");
|
||||
// don't do anything more:
|
||||
while (1);
|
||||
}
|
||||
Serial.println("SD card initialized.");
|
||||
|
||||
// Create or open a file called "Fast_RXM.ubx" on the SD card.
|
||||
// If the file already exists, the new data is appended to the end of the file.
|
||||
myFile = SD.open("Fast_RXM.ubx", FILE_WRITE);
|
||||
if(!myFile)
|
||||
{
|
||||
Serial.println(F("Failed to create UBX data file! Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable lots of helpful GNSS debug messages on Serial
|
||||
//myGNSS.enableDebugging(Serial, true); // Or, uncomment this line to enable only the important GNSS debug messages on Serial
|
||||
|
||||
myGNSS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F, so we need to disable the "7F" check in checkUbloxI2C
|
||||
|
||||
// RAWX messages can be over 2KBytes in size, so we need to make sure we allocate enough RAM to hold all the data.
|
||||
// SD cards can occasionally 'hiccup' and a write takes much longer than usual. The buffer needs to be big enough
|
||||
// to hold the backlog of data if/when this happens.
|
||||
// getMaxFileBufferAvail will tell us the maximum number of bytes which the file buffer has contained.
|
||||
myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
|
||||
// (This will also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
|
||||
//myGNSS.factoryDefault(); delay(5000);
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
// Modules like the ZED-F9P can produce RAW navigation data at rates of up to 25Hz but not while using all of the GNSS constellations.
|
||||
// Please consult the data sheet for the Performance figures for your module.
|
||||
// In this example we make sure GPS is enabled and then disable Galileo, GLONASS, BeiDou, SBAS and QZSS to achieve 25Hz.
|
||||
myGNSS.enableGNSS(true, SFE_UBLOX_GNSS_ID_GPS); // Make sure GPS is enabled (we must leave at least one major GNSS enabled!)
|
||||
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_SBAS); // Disable SBAS
|
||||
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_GALILEO); // Disable Galileo
|
||||
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_BEIDOU); // Disable BeiDou
|
||||
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_IMES); // Disable IMES
|
||||
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_QZSS); // Disable QZSS
|
||||
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_GLONASS); // Disable GLONASS
|
||||
|
||||
delay(2000); // Give the module some extra time to get ready
|
||||
|
||||
//Produce 7 navigation solutions per second. That's a lot of RAWX data - especially when using both GPS bands L1 and L2.
|
||||
//The SD library and card need to be able to cope with the data rate too. You may need a faster SD library to go above 7Hz.
|
||||
myGNSS.setNavigationFrequency(7);
|
||||
|
||||
myGNSS.setAutoRXMSFRBX(true, false); // Enable automatic RXM SFRBX messages: without callback; without implicit update
|
||||
|
||||
myGNSS.logRXMSFRBX(); // Enable RXM SFRBX data logging
|
||||
|
||||
myGNSS.setAutoRXMRAWX(true, false); // Enable automatic RXM RAWX messages: without callback; without implicit update
|
||||
|
||||
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
|
||||
|
||||
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
Serial.println(F("Press any key to stop logging."));
|
||||
|
||||
lastPrint = millis(); // Initialize lastPrint
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
|
||||
|
||||
myGNSS.extractFileBufferData(myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
|
||||
|
||||
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
|
||||
|
||||
bytesWritten += sdWriteSize; // Update bytesWritten
|
||||
|
||||
// In case the SD writing is slow or there is a lot of data to write, keep checking for the arrival of new data
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off again
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
if (millis() > (lastPrint + 1000)) // Print bytesWritten once per second
|
||||
{
|
||||
Serial.print(F("The number of bytes written to SD card is: ")); // Print how many bytes have been written to SD card
|
||||
Serial.println(bytesWritten);
|
||||
|
||||
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now)
|
||||
|
||||
//Serial.print(F("The maximum number of bytes which the file buffer has contained is: ")); // It is a fun thing to watch how full the buffer gets
|
||||
//Serial.println(maxBufferBytes);
|
||||
|
||||
if (maxBufferBytes > ((fileBufferSize / 5) * 4)) // Warn the user if fileBufferSize was more than 80% full
|
||||
{
|
||||
Serial.println(F("Warning: the file buffer has been over 80% full. Some data may have been lost."));
|
||||
}
|
||||
|
||||
lastPrint = millis(); // Update lastPrint
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
if (Serial.available()) // Check if the user wants to stop logging
|
||||
{
|
||||
myGNSS.setAutoRXMSFRBX(false, false); // Disable the automatic RXM SFRBX messages
|
||||
myGNSS.setAutoRXMRAWX(false, false); // Disable the automatic RXM RAWX messages
|
||||
|
||||
delay(1000); // Allow time for any remaining messages to arrive
|
||||
myGNSS.checkUblox(); // Process any remaining data
|
||||
|
||||
uint16_t remainingBytes = myGNSS.fileBufferAvailable(); // Check if there are any bytes remaining in the file buffer
|
||||
|
||||
while (remainingBytes > 0) // While there is still data in the file buffer
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
|
||||
|
||||
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
|
||||
if (bytesToWrite > sdWriteSize)
|
||||
{
|
||||
bytesToWrite = sdWriteSize;
|
||||
}
|
||||
|
||||
myGNSS.extractFileBufferData(myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
|
||||
|
||||
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
|
||||
|
||||
bytesWritten += bytesToWrite; // Update bytesWritten
|
||||
|
||||
remainingBytes -= bytesToWrite; // Decrement remainingBytes
|
||||
}
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off
|
||||
|
||||
Serial.print(F("The total number of bytes written to SD card is: ")); // Print how many bytes have been written to SD card
|
||||
Serial.println(bytesWritten);
|
||||
|
||||
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Show how full the file buffer has been (not how full it is now)
|
||||
Serial.print(F("The maximum number of bytes which the file buffer has contained is: "));
|
||||
Serial.println(maxBufferBytes);
|
||||
|
||||
myFile.close(); // Close the data file
|
||||
|
||||
Serial.println(F("Logging stopped. Freezing..."));
|
||||
while(1); // Do nothing more
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
}
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
Demonstrate how to log NMEA and UBX data simultaneously
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: October 18th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the u-blox GNSS to send PVT reports automatically
|
||||
and log those and any incoming NMEA messages to SD card in UBX format
|
||||
|
||||
** Please note: this example will only work on processors like the Artemis which have plenty of RAM available **
|
||||
|
||||
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
|
||||
but can be adapted by changing the chip select pin and SPI definitions:
|
||||
https://www.sparkfun.com/products/16829
|
||||
https://www.sparkfun.com/products/16401
|
||||
|
||||
Hardware Connections:
|
||||
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
|
||||
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
|
||||
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
|
||||
Connect an antenna to your GNSS board if required.
|
||||
Insert a formatted micro-SD card into the socket on the Carrier Board.
|
||||
Connect the Carrier Board to your computer using a USB-C cable.
|
||||
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
|
||||
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
|
||||
Select "Artemis MicroMod Processor" as the board type.
|
||||
Press upload to upload the code onto the Artemis.
|
||||
Open the Serial Monitor at 115200 baud to see the output.
|
||||
|
||||
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
|
||||
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
ZOE-M8Q: https://www.sparkfun.com/products/15193
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15210
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
File myFile; //File that all GNSS data is written to
|
||||
|
||||
//Define the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
|
||||
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#else
|
||||
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
|
||||
#endif
|
||||
#else
|
||||
|
||||
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
|
||||
|
||||
#endif
|
||||
|
||||
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
|
||||
#define fileBufferSize 16384 // Allocate 16KBytes of RAM for UBX message storage
|
||||
uint8_t *myBuffer; // A buffer to hold the data while we write it to SD card
|
||||
|
||||
unsigned long lastPrint; // Record when the last Serial print took place
|
||||
unsigned long bytesWritten = 0; // Record how many bytes have been written to SD card
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
pinMode(LED_BUILTIN, OUTPUT); // Flash LED_BUILTIN each time we write to the SD card
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
Wire.begin(); // Start I2C communication
|
||||
|
||||
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
|
||||
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
|
||||
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
|
||||
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
|
||||
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
|
||||
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
|
||||
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
|
||||
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
|
||||
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
|
||||
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
|
||||
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
|
||||
#endif
|
||||
#endif
|
||||
|
||||
while (Serial.available()) // Make sure the Serial buffer is empty
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
|
||||
Serial.println(F("Press any key to start logging."));
|
||||
|
||||
while (!Serial.available()) // Wait for the user to press a key
|
||||
{
|
||||
; // Do nothing
|
||||
}
|
||||
|
||||
delay(100); // Wait, just in case multiple characters were sent
|
||||
|
||||
while (Serial.available()) // Empty the Serial buffer
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
|
||||
Serial.println("Initializing SD card...");
|
||||
|
||||
// See if the card is present and can be initialized:
|
||||
if (!SD.begin(sdChipSelect))
|
||||
{
|
||||
Serial.println("Card failed, or not present. Freezing...");
|
||||
// don't do anything more:
|
||||
while (1);
|
||||
}
|
||||
Serial.println("SD card initialized.");
|
||||
|
||||
// Create or open a file called "PVT_NMEA.ubx" on the SD card.
|
||||
// If the file already exists, the new data is appended to the end of the file.
|
||||
myFile = SD.open("PVT_NMEA.ubx", FILE_WRITE);
|
||||
if(!myFile)
|
||||
{
|
||||
Serial.println(F("Failed to create UBX data file! Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable lots of helpful GNSS debug messages on Serial
|
||||
//myGNSS.enableDebugging(Serial, true); // Or, uncomment this line to enable only the important GNSS debug messages on Serial
|
||||
|
||||
//myGNSS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F. Uncomment this line to disable the "7F" check in checkUbloxI2C
|
||||
|
||||
// SD cards can occasionally 'hiccup' and a write takes much longer than usual. The buffer needs to be big enough
|
||||
// to hold the backlog of data if/when this happens.
|
||||
// getMaxFileBufferAvail will tell us the maximum number of bytes which the file buffer has contained.
|
||||
myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
|
||||
// This will (re)enable the standard NMEA messages too
|
||||
// This will also disable any "auto" UBX messages that were enabled and saved by other examples and reduce the load on the I2C bus
|
||||
//myGNSS.factoryDefault(); delay(5000);
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the I2C port to output both UBX and NMEA messages
|
||||
|
||||
//myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Optional: save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second
|
||||
|
||||
myGNSS.setAutoPVT(true, false); // Enable automatic NAV PVT messages: without callback; without implicit update
|
||||
myGNSS.logNAVPVT(); // Enable NAV PVT data logging
|
||||
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C, 1); // Ensure the GxGGA (Global positioning system fix data) message is enabled. Send every measurement.
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C, 1); // Ensure the GxGSA (GNSS DOP and Active satellites) message is enabled. Send every measurement.
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C, 1); // Ensure the GxGSV (GNSS satellites in view) message is enabled. Send every measurement.
|
||||
|
||||
myGNSS.setNMEALoggingMask(SFE_UBLOX_FILTER_NMEA_ALL); // Enable logging of all enabled NMEA messages
|
||||
//myGNSS.setNMEALoggingMask(SFE_UBLOX_FILTER_NMEA_GGA | SFE_UBLOX_FILTER_NMEA_GSA); // Or we can, for example, log only GxGGA & GxGSA and ignore GxGSV
|
||||
|
||||
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
Serial.println(F("Press any key to stop logging."));
|
||||
|
||||
lastPrint = millis(); // Initialize lastPrint
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
|
||||
|
||||
myGNSS.extractFileBufferData(myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
|
||||
|
||||
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
|
||||
|
||||
bytesWritten += sdWriteSize; // Update bytesWritten
|
||||
|
||||
// In case the SD writing is slow or there is a lot of data to write, keep checking for the arrival of new data
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off again
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
if (millis() > (lastPrint + 1000)) // Print bytesWritten once per second
|
||||
{
|
||||
Serial.print(F("The number of bytes written to SD card is ")); // Print how many bytes have been written to SD card
|
||||
Serial.println(bytesWritten);
|
||||
|
||||
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now)
|
||||
|
||||
//Serial.print(F("The maximum number of bytes which the file buffer has contained is: ")); // It is a fun thing to watch how full the buffer gets
|
||||
//Serial.println(maxBufferBytes);
|
||||
|
||||
if (maxBufferBytes > ((fileBufferSize / 5) * 4)) // Warn the user if fileBufferSize was more than 80% full
|
||||
{
|
||||
Serial.println(F("Warning: the file buffer has been over 80% full. Some data may have been lost."));
|
||||
}
|
||||
|
||||
lastPrint = millis(); // Update lastPrint
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
if (Serial.available()) // Check if the user wants to stop logging
|
||||
{
|
||||
uint16_t remainingBytes = myGNSS.fileBufferAvailable(); // Check if there are any bytes remaining in the file buffer
|
||||
|
||||
while (remainingBytes > 0) // While there is still data in the file buffer
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
|
||||
|
||||
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
|
||||
if (bytesToWrite > sdWriteSize)
|
||||
{
|
||||
bytesToWrite = sdWriteSize;
|
||||
}
|
||||
|
||||
myGNSS.extractFileBufferData(myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
|
||||
|
||||
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
|
||||
|
||||
bytesWritten += bytesToWrite; // Update bytesWritten
|
||||
|
||||
remainingBytes -= bytesToWrite; // Decrement remainingBytes
|
||||
}
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off
|
||||
|
||||
Serial.print(F("The total number of bytes written to SD card is ")); // Print how many bytes have been written to SD card
|
||||
Serial.println(bytesWritten);
|
||||
|
||||
myFile.close(); // Close the data file
|
||||
|
||||
Serial.println(F("Logging stopped. Freezing..."));
|
||||
while(1); // Do nothing more
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
}
|
||||
|
|
@ -0,0 +1,340 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send RXM SFRBX and RAWX reports over SPI and log them to file on SD card using full 4-bit SDIO
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: October 20th, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the u-blox GNSS to send RXM SFRBX and RAWX reports automatically
|
||||
and log the data to SD card in UBX format.
|
||||
|
||||
This code is written for the OpenLog ESP32 (DEV-20594) - coming soon!
|
||||
|
||||
Hardware set-up:
|
||||
Close the DSEL jumper on the ZED-F9P breakout - to select SPI mode
|
||||
Connect:
|
||||
OpenLog ESP32 : ZED-F9P
|
||||
GND GND
|
||||
3V3_SW 3V3
|
||||
SCK (18) SCK
|
||||
PICO (23) PICO (MOSI)
|
||||
POCI (19) POCI (MISO)
|
||||
33 CS
|
||||
|
||||
** Please note: this example will only work on u-blox ADR or High Precision GNSS or Time Sync products **
|
||||
|
||||
Data is logged in u-blox UBX format.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
OpenLog ESP32: https://www.sparkfun.com/products/20594
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
*/
|
||||
|
||||
#define GNSS_CS 33 // Connect the ZED-F9P CS pin to OpenLog ESP32 pin 33
|
||||
#define EN_3V3_SW 32 // The 3.3V_SW regulator Enable pin is connected to D32
|
||||
#define STAT_LED 25 // The OpenLog ESP32 STAT LED is connected to pin 25
|
||||
#define IMU_CS 5 // The ISM330 IMU CS is connected to pin 5
|
||||
#define MAG_CS 27 // The MMC5983 Mag CS is connected to pin 27
|
||||
|
||||
#include "FS.h"
|
||||
#include "SD_MMC.h"
|
||||
File myFile;
|
||||
|
||||
#include <SPI.h>
|
||||
#define spiPort SPI
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
#define sdWriteSize 2048 // Write data to the SD card in blocks of n*512 bytes
|
||||
#define fileBufferSize 65530 // Allocate just under 64KBytes of RAM for UBX message storage
|
||||
#define navRate 20 // Set the Nav Rate (Frequency) to 20Hz
|
||||
//#define ubxOnly // Uncomment this line to log UBX (RAWX and SFRBX) only
|
||||
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
|
||||
|
||||
unsigned long lastPrint; // Record when the last Serial print took place
|
||||
|
||||
// Note: we'll keep a count of how many SFRBX and RAWX messages arrive - but the count will not be completely accurate.
|
||||
// If two or more SFRBX messages arrive together as a group and are processed by one call to checkUblox, the count will
|
||||
// only increase by one.
|
||||
|
||||
int numSFRBX = 0; // Keep count of how many SFRBX message groups have been received (see note above)
|
||||
int numRAWX = 0; // Keep count of how many RAWX message groups have been received (see note above)
|
||||
|
||||
// Callback: newSFRBX will be called when new RXM SFRBX data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_RXMSFRBX_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMSFRBXcallback
|
||||
// / _____ This _must_ be UBX_RXM_SFRBX_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void newSFRBX(UBX_RXM_SFRBX_data_t *ubxDataStruct)
|
||||
{
|
||||
numSFRBX++; // Increment the count
|
||||
}
|
||||
|
||||
// Callback: newRAWX will be called when new RXM RAWX data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_RXMRAWX_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMRAWXcallback
|
||||
// / _____ This _must_ be UBX_RXM_RAWX_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void newRAWX(UBX_RXM_RAWX_data_t *ubxDataStruct)
|
||||
{
|
||||
numRAWX++; // Increment the count
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
pinMode(STAT_LED, OUTPUT); // Flash the STAT LED each time we write to the SD card
|
||||
digitalWrite(STAT_LED, LOW);
|
||||
|
||||
pinMode(GNSS_CS, OUTPUT);
|
||||
digitalWrite(GNSS_CS, HIGH);
|
||||
pinMode(IMU_CS, OUTPUT);
|
||||
digitalWrite(IMU_CS, HIGH);
|
||||
pinMode(MAG_CS, OUTPUT);
|
||||
digitalWrite(MAG_CS, HIGH);
|
||||
|
||||
spiPort.begin();
|
||||
|
||||
// Do a fake transaction to initialize the SPI pins
|
||||
spiPort.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
spiPort.transfer(0);
|
||||
spiPort.endTransaction();
|
||||
|
||||
pinMode(EN_3V3_SW, OUTPUT); // Enable power for the microSD card and GNSS
|
||||
digitalWrite(EN_3V3_SW, HIGH);
|
||||
|
||||
delay(3000); // Allow time for the GNSS and SD card to start up and for Tera Term to reconnect
|
||||
Serial.println(F("SparkFun OpenLog ESP32 GNSS Logging : SPI and SDIO"));
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Initialize the GNSS
|
||||
|
||||
Serial.println(F("Initializing the GNSS..."));
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to see helpful debug messages on Serial
|
||||
|
||||
myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
|
||||
|
||||
// Connect to the u-blox module using SPI port, csPin and speed setting
|
||||
// ublox devices generally work up to 5MHz. We'll use 4MHz for this example:
|
||||
bool begun = false;
|
||||
do
|
||||
{
|
||||
begun = myGNSS.begin(spiPort, GNSS_CS, 4000000);
|
||||
if (!begun)
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected on SPI bus."));
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
while (!begun);
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Wait for a 3D fix. Get the date and time for the log file
|
||||
|
||||
//myGNSS.factoryDefault(); delay(5000); // Uncomment this line to reset the module back to its factory defaults
|
||||
|
||||
#ifdef ubxOnly
|
||||
myGNSS.setSPIOutput(COM_TYPE_UBX); //Set the SPI port to output only UBX
|
||||
#else
|
||||
myGNSS.setSPIOutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the SPI port to output both UBX and NMEA messages
|
||||
#endif
|
||||
|
||||
//myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Optional: save (only) the communications port settings to flash and BBR
|
||||
|
||||
Serial.print(F("Waiting for a 3D fix"));
|
||||
|
||||
uint8_t fix = 0;
|
||||
|
||||
do
|
||||
{
|
||||
fix = myGNSS.getFixType();
|
||||
delay(1000);
|
||||
Serial.print(F("."));
|
||||
}
|
||||
while ( fix != 3 ); // Wait for a 3D fix
|
||||
|
||||
Serial.println();
|
||||
|
||||
uint16_t y = myGNSS.getYear();
|
||||
uint8_t M = myGNSS.getMonth();
|
||||
uint8_t d = myGNSS.getDay();
|
||||
uint8_t h = myGNSS.getHour();
|
||||
uint8_t m = myGNSS.getMinute();
|
||||
uint8_t s = myGNSS.getSecond();
|
||||
|
||||
char szBuffer[40] = {'\0'};
|
||||
snprintf(szBuffer, sizeof(szBuffer), "/%04d%02d%02d%02d%02d%02d.ubx", y, M, d, h, m, s);
|
||||
|
||||
Serial.println(F("GNSS initialized."));
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Initialize the SD card. Open the log file
|
||||
|
||||
Serial.println(F("Initializing SD card..."));
|
||||
|
||||
// Begin the SD card
|
||||
if(!SD_MMC.begin())
|
||||
{
|
||||
Serial.println(F("Card mount failed. Freezing..."));
|
||||
while(1);
|
||||
}
|
||||
|
||||
// Open the log file for writing
|
||||
Serial.printf("Log file is: %s\r\n", szBuffer);
|
||||
myFile = SD_MMC.open((const char *)szBuffer, FILE_WRITE);
|
||||
if(!myFile)
|
||||
{
|
||||
Serial.println(F("Failed to open log file for writing. Freezing..."));
|
||||
while(1);
|
||||
}
|
||||
|
||||
Serial.println(F("SD card initialized."));
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Wait for a key press
|
||||
|
||||
while (Serial.available()) // Make sure the Serial buffer is empty
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
|
||||
Serial.println(F("Press any key to start logging."));
|
||||
|
||||
while (!Serial.available()) // Wait for the user to press a key
|
||||
{
|
||||
; // Do nothing
|
||||
}
|
||||
|
||||
delay(100); // Wait, just in case multiple characters were sent
|
||||
|
||||
while (Serial.available()) // Empty the Serial buffer
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Enable RAWX and SFRBX
|
||||
|
||||
myGNSS.setAutoRXMSFRBXcallbackPtr(&newSFRBX); // Enable automatic RXM SFRBX messages with callback to newSFRBX
|
||||
|
||||
myGNSS.logRXMSFRBX(); // Enable RXM SFRBX data logging
|
||||
|
||||
myGNSS.setAutoRXMRAWXcallbackPtr(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX
|
||||
|
||||
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
|
||||
|
||||
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
#ifndef ubxOnly
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_SPI, navRate); // Ensure the GxGGA (Global positioning system fix data) message is enabled. Send every second.
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GSA, COM_PORT_SPI, navRate); // Ensure the GxGSA (GNSS DOP and Active satellites) message is enabled. Send every second.
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GSV, COM_PORT_SPI, navRate); // Ensure the GxGSV (GNSS satellites in view) message is enabled. Send every second.
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GST, COM_PORT_SPI, navRate); // Ensure the GxGST (Position error statistics) message is enabled. Send every second.
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_RMC, COM_PORT_SPI, navRate); // Ensure the GxRMC (Recommended minimum: position, velocity and time) message is enabled. Send every second.
|
||||
myGNSS.setNMEALoggingMask(SFE_UBLOX_FILTER_NMEA_GGA | SFE_UBLOX_FILTER_NMEA_GSA | SFE_UBLOX_FILTER_NMEA_GSV | SFE_UBLOX_FILTER_NMEA_GST | SFE_UBLOX_FILTER_NMEA_RMC); // Log only these NMEA messages
|
||||
#endif
|
||||
|
||||
myGNSS.setNavigationFrequency(navRate); // Set navigation rate
|
||||
|
||||
Serial.println(F("Press any key to stop logging."));
|
||||
|
||||
lastPrint = millis(); // Initialize lastPrint
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer
|
||||
{
|
||||
digitalWrite(STAT_LED, HIGH); // Flash the STAT LED each time we write to the SD card
|
||||
|
||||
myGNSS.extractFileBufferData(myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
|
||||
|
||||
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
|
||||
|
||||
// In case the SD writing is slow or there is a lot of data to write, keep checking for the arrival of new data
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
digitalWrite(STAT_LED, LOW); // Turn the STAT LED off again
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
if (millis() > (lastPrint + 1000)) // Print the message count once per second
|
||||
{
|
||||
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now)
|
||||
float bufferHigh = 100.0 * (float)maxBufferBytes / (float)fileBufferSize;
|
||||
|
||||
Serial.print(F("Message groups received: SFRBX: ")); // Print how many message groups have been received (see note above)
|
||||
Serial.print(numSFRBX);
|
||||
Serial.print(F(" RAWX: "));
|
||||
Serial.print(numRAWX);
|
||||
Serial.print(F(" \tBuffer high tide: "));
|
||||
Serial.print(bufferHigh, 1); // It is a fun thing to watch how full the buffer gets
|
||||
if (bufferHigh > 90.)
|
||||
Serial.println(F("%!!"));
|
||||
else if (bufferHigh > 80.)
|
||||
Serial.println(F("%!"));
|
||||
else
|
||||
Serial.println(F("%"));
|
||||
|
||||
lastPrint = millis(); // Update lastPrint
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
if (Serial.available()) // Check if the user wants to stop logging
|
||||
{
|
||||
uint16_t remainingBytes = myGNSS.fileBufferAvailable(); // Check if there are any bytes remaining in the file buffer
|
||||
|
||||
while (remainingBytes > 0) // While there is still data in the file buffer
|
||||
{
|
||||
digitalWrite(STAT_LED, HIGH); // Flash the STAT LED while we write to the SD card
|
||||
|
||||
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
|
||||
if (bytesToWrite > sdWriteSize)
|
||||
{
|
||||
bytesToWrite = sdWriteSize;
|
||||
}
|
||||
|
||||
myGNSS.extractFileBufferData(myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
|
||||
|
||||
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
|
||||
|
||||
remainingBytes -= bytesToWrite; // Decrement remainingBytes
|
||||
}
|
||||
|
||||
digitalWrite(STAT_LED, LOW); // Turn the STAT LED off
|
||||
|
||||
myFile.close(); // Close the data file
|
||||
|
||||
myGNSS.setNavigationFrequency(1); // Set navigation rate to 1Hz
|
||||
|
||||
myGNSS.disableMessage(UBX_CLASS_RXM, UBX_RXM_RAWX, COM_PORT_SPI);
|
||||
myGNSS.disableMessage(UBX_CLASS_RXM, UBX_RXM_SFRBX, COM_PORT_SPI);
|
||||
|
||||
myGNSS.setSPIOutput(COM_TYPE_UBX | COM_TYPE_NMEA); // Re-enable NMEA
|
||||
|
||||
Serial.println(F("Logging stopped. Freezing..."));
|
||||
while(1); // Do nothing more
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
By: Elias Santistevan
|
||||
SparkFun Electronics
|
||||
Date: May, 2020
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
NEO-M8U: https://www.sparkfun.com/products/16329
|
||||
ZED-F9R: https://www.sparkfun.com/products/16344
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a Redboard Qwiic
|
||||
If you don't have a platform with a Qwiic connection use the
|
||||
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
|
||||
To take advantage of the internal IMU of either the Dead Reckoning GNSS
|
||||
boards (ZED-F9R, NEO-M8U), you must first calibrate it. This includes securing the GNSS module
|
||||
to your vehicle so that it is stable within 2 degrees and that the frame of
|
||||
reference of the board is consistent with the picture outlined in the
|
||||
Receiver-Description-Prot-Spec Datasheet under Automotive/Untethered Dead
|
||||
Reckoning. You may also check either the ZED-F9R or NEO-M8U Hookup Guide for
|
||||
more information. After the board is secure, you'll need to put the module
|
||||
through certain conditions for proper calibration: acceleration, turning,
|
||||
stopping for a few minutes, getting to a speed over 30km/h all under a clear sky
|
||||
with good GNSS signal. This example simply looks at the
|
||||
"fusionMode" status which indicates whether the SparkFun Dead Reckoning is
|
||||
initializing - 0, calibrated - 1, or if an error has occurred - 2,3.
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
|
||||
//myGNSS.resetIMUalignment(); // Uncomment this line to reset the IMU alignment
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// ESF data is produced at the navigation rate, so by default we'll get fresh data once per second
|
||||
if (myGNSS.getEsfInfo()) // Poll new ESF STATUS data
|
||||
{
|
||||
Serial.print(F("Fusion Mode: "));
|
||||
Serial.print(myGNSS.packetUBXESFSTATUS->data.fusionMode);
|
||||
if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 0)
|
||||
Serial.println(F(" Sensor is initializing..."));
|
||||
else if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 1)
|
||||
Serial.println(F(" Sensor is calibrated!"));
|
||||
else if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 2)
|
||||
Serial.println(F(" Sensor fusion is suspended!"));
|
||||
else if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 3)
|
||||
Serial.println(F(" Sensor fusion is disabled!"));
|
||||
}
|
||||
|
||||
delay(250);
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
By: Elias Santistevan
|
||||
SparkFun Electronics
|
||||
Date: May, 2020
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
NEO-M8U: https://www.sparkfun.com/products/16329
|
||||
ZED-F9R: https://www.sparkfun.com/products/16344
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a Redboard Qwiic
|
||||
If you don't have a platform with a Qwiic connection use the
|
||||
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
|
||||
After calibrating the module, also known as "Fusion Mode", you can get
|
||||
data directly from the IMU. This data is integrated directly into the GNSS
|
||||
output, but is provided by the module as well.
|
||||
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
|
||||
if (myGNSS.getEsfInfo()){
|
||||
|
||||
Serial.print(F("Fusion Mode: "));
|
||||
Serial.println(myGNSS.packetUBXESFSTATUS->data.fusionMode);
|
||||
|
||||
if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 1){
|
||||
Serial.println(F("Fusion Mode is Initialized!"));
|
||||
}
|
||||
else {
|
||||
Serial.println(F("Fusion Mode is either disabled or not initialized!"));
|
||||
Serial.println(F("Please see the previous example for more information."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// ESF data is produced at the navigation rate, so by default we'll get fresh data once per second
|
||||
if (myGNSS.getEsfIns()) // Poll new ESF INS data
|
||||
{
|
||||
Serial.print(F("X Ang Rate: "));
|
||||
Serial.print(myGNSS.packetUBXESFINS->data.xAngRate);
|
||||
Serial.print(F(" Y Ang Rate: "));
|
||||
Serial.print(myGNSS.packetUBXESFINS->data.yAngRate);
|
||||
Serial.print(F(" Z Ang Rate: "));
|
||||
Serial.print(myGNSS.packetUBXESFINS->data.zAngRate);
|
||||
Serial.print(F(" X Accel: "));
|
||||
Serial.print(myGNSS.packetUBXESFINS->data.xAccel);
|
||||
Serial.print(F(" Y Accel: "));
|
||||
Serial.print(myGNSS.packetUBXESFINS->data.yAccel);
|
||||
Serial.print(F(" Z Accel: "));
|
||||
Serial.print(myGNSS.packetUBXESFINS->data.zAccel);
|
||||
|
||||
// These values also have "validity checks" that can be provided by the
|
||||
// ublox library by reading bitfield0
|
||||
Serial.print(F(" Validity: "));
|
||||
Serial.print(myGNSS.packetUBXESFINS->data.bitfield0.bits.xAngRateValid);
|
||||
Serial.print(myGNSS.packetUBXESFINS->data.bitfield0.bits.yAngRateValid);
|
||||
Serial.print(myGNSS.packetUBXESFINS->data.bitfield0.bits.zAngRateValid);
|
||||
Serial.print(myGNSS.packetUBXESFINS->data.bitfield0.bits.xAccelValid);
|
||||
Serial.print(myGNSS.packetUBXESFINS->data.bitfield0.bits.yAccelValid);
|
||||
Serial.println(myGNSS.packetUBXESFINS->data.bitfield0.bits.zAccelValid);
|
||||
}
|
||||
|
||||
delay(250);
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
By: Elias Santistevan
|
||||
SparkFun Electronics
|
||||
Date: May, 2020
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
NEO-M8U: https://www.sparkfun.com/products/16329
|
||||
ZED-F9R: https://www.sparkfun.com/products/16344
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a Redboard Qwiic
|
||||
If you don't have a platform with a Qwiic connection use the
|
||||
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
|
||||
After calibrating the module, also known as "Fusion Mode", you can get
|
||||
data directly from the IMU. This example code walks you through trouble
|
||||
shooting or identifying the different states of any individual
|
||||
"external" (which include internal) sensors you've hooked up (vehicle speed
|
||||
sensor) or the internal IMU used by the modules. You can see if the sensor is
|
||||
being used, if it's calibrated, ready, what data type it returns, the state
|
||||
of the measurement etc.
|
||||
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
|
||||
// GetEsfInfo also gets the number of sensors used by the ublox module, this
|
||||
// includes (in the case of the ZED-F9R) wheel tick input from the vehicle
|
||||
// speed sensor attached to the module.
|
||||
if (myGNSS.getEsfInfo()){
|
||||
|
||||
Serial.print(F("Fusion Mode: "));
|
||||
Serial.println(myGNSS.packetUBXESFSTATUS->data.fusionMode);
|
||||
|
||||
if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 1){
|
||||
Serial.println(F("Fusion Mode is Initialized!"));
|
||||
}
|
||||
else {
|
||||
Serial.println(F("Fusion Mode is either disabled or not initialized!"));
|
||||
Serial.println(F("Please see the previous example for more information."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// ESF data is produced at the navigation rate, so by default we'll get fresh data once per second
|
||||
if (myGNSS.getEsfInfo()) // Poll new ESF STATUS data
|
||||
{
|
||||
UBX_ESF_STATUS_sensorStatus_t sensorStatus; // Create storage for the individual sensor status
|
||||
|
||||
//See ublox receiver description or our hookup guide for information on the return values
|
||||
|
||||
Serial.println(F(" "));
|
||||
Serial.println(F(" C "));
|
||||
Serial.println(F(" a "));
|
||||
Serial.println(F(" l "));
|
||||
Serial.println(F(" i "));
|
||||
Serial.println(F(" b M "));
|
||||
Serial.println(F(" r i N"));
|
||||
Serial.println(F(" a B s o"));
|
||||
Serial.println(F(" S t T B a s i"));
|
||||
Serial.println(F("S e B i i a d e s"));
|
||||
Serial.println(F("e n e o m d d y"));
|
||||
Serial.println(F("n s i I n e T "));
|
||||
Serial.println(F("s o n s M i M M"));
|
||||
Serial.println(F("o r g S S e m e e"));
|
||||
Serial.println(F("r R t t a e a a"));
|
||||
Serial.println(F(" T U e a a s s s"));
|
||||
Serial.println(F("N y s a t t u T u u"));
|
||||
Serial.println(F("o p e d u u r a r r"));
|
||||
Serial.println(F(". e d y s s e g e e"));
|
||||
Serial.println(F(" "));
|
||||
|
||||
for(uint8_t i = 0; i < myGNSS.packetUBXESFSTATUS->data.numSens; i++)
|
||||
{
|
||||
myGNSS.getSensorFusionStatus(&sensorStatus, i); // Extract the individual sensor data for this sensor
|
||||
|
||||
Serial.print(i); Serial.print(F(" ")); // Print the sensor number
|
||||
|
||||
// Print the sensor type
|
||||
Serial.print(sensorStatus.sensStatus1.bits.type);
|
||||
if (sensorStatus.sensStatus1.bits.type < 10) Serial.print(F(" "));
|
||||
Serial.print(F(" "));
|
||||
|
||||
Serial.print(sensorStatus.sensStatus1.bits.used); Serial.print(F(" ")); // Print the used flag
|
||||
Serial.print(sensorStatus.sensStatus1.bits.ready); Serial.print(F(" ")); // Print the ready flag
|
||||
|
||||
Serial.print(sensorStatus.sensStatus2.bits.calibStatus); Serial.print(F(" ")); // Print the calibration status
|
||||
Serial.print(sensorStatus.sensStatus2.bits.timeStatus); Serial.print(F(" ")); // Print the time status
|
||||
|
||||
Serial.print(sensorStatus.faults.bits.badMeas); Serial.print(F(" ")); // Print the bad measurement flag
|
||||
Serial.print(sensorStatus.faults.bits.badTTag); Serial.print(F(" ")); // Print the time tag flag
|
||||
Serial.print(sensorStatus.faults.bits.missingMeas); Serial.print(F(" ")); // Print the missing measurement flag
|
||||
Serial.print(sensorStatus.faults.bits.noisyMeas); // Print the noisy measure flag
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
||||
delay(250);
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
By: Elias Santistevan
|
||||
SparkFun Electronics
|
||||
Date: May, 2020
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
NEO-M8U: https://www.sparkfun.com/products/16329
|
||||
ZED-F9R: https://www.sparkfun.com/products/16344
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a Redboard Qwiic
|
||||
If you don't have a platform with a Qwiic connection use the
|
||||
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
|
||||
getEsfAlignment (UBX-ESF-ALG) reports the status and alignment angles of the IMU within the vehicle.
|
||||
These define the rotation of the IMU frame within the vehicle (installation frame) - not the heading
|
||||
of the vehicle itself. The vehicle attitude solution is reported separately by getNAVATT (UBX-NAV-ATT).
|
||||
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
|
||||
myGNSS.setESFAutoAlignment(true); //Enable Automatic IMU-mount Alignment
|
||||
|
||||
if (myGNSS.getEsfInfo()){
|
||||
|
||||
Serial.print(F("Fusion Mode: "));
|
||||
Serial.println(myGNSS.packetUBXESFSTATUS->data.fusionMode);
|
||||
|
||||
if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 1){
|
||||
Serial.println(F("Fusion Mode is Initialized!"));
|
||||
}
|
||||
else {
|
||||
Serial.println(F("Fusion Mode is either disabled or not initialized!"));
|
||||
Serial.println(F("Please see the previous example for more information."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// ESF data is produced at the navigation rate, so by default we'll get fresh data once per second
|
||||
if (myGNSS.getEsfAlignment()) // Poll new ESF ALG data
|
||||
{
|
||||
Serial.print(F("IMU-Mount Alignment: On/Off: "));
|
||||
Serial.print(myGNSS.packetUBXESFALG->data.flags.bits.autoMntAlgOn);
|
||||
Serial.print(F(" Status: "));
|
||||
Serial.print(myGNSS.packetUBXESFALG->data.flags.bits.status);
|
||||
Serial.print(F(" Roll: "));
|
||||
Serial.print(myGNSS.getESFroll(), 2); // Use the helper function to get the roll in degrees
|
||||
Serial.print(F(" Pitch: "));
|
||||
Serial.print(myGNSS.getESFpitch(), 2); // Use the helper function to get the pitch in degrees
|
||||
Serial.print(F(" Yaw: "));
|
||||
Serial.print(myGNSS.getESFyaw(), 2); // Use the helper function to get the yaw in degrees
|
||||
Serial.print(F(" Errors: "));
|
||||
Serial.print(myGNSS.packetUBXESFALG->data.error.bits.tiltAlgError);
|
||||
Serial.print(myGNSS.packetUBXESFALG->data.error.bits.yawAlgError);
|
||||
Serial.println(myGNSS.packetUBXESFALG->data.error.bits.angleError);
|
||||
}
|
||||
|
||||
if (myGNSS.getNAVATT()) // Poll new NAV ATT data
|
||||
{
|
||||
Serial.print(F("Vehicle Attitude: Roll: "));
|
||||
Serial.print(myGNSS.getATTroll(), 2); // Use the helper function to get the roll in degrees
|
||||
Serial.print(F(" Pitch: "));
|
||||
Serial.print(myGNSS.getATTpitch(), 2); // Use the helper function to get the pitch in degrees
|
||||
Serial.print(F(" Heading: "));
|
||||
Serial.println(myGNSS.getATTheading(), 2); // Use the helper function to get the heading in degrees
|
||||
}
|
||||
|
||||
delay(250);
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: December, 2020
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example configures the High Navigation Rate on the NEO-M8U and then
|
||||
polls and displays the attitude solution, vehicle dynamics information
|
||||
and high rate position, velocity and time.
|
||||
|
||||
This example polls the high rate data.
|
||||
(The next example uses "autoHNR" to receive the HNR data automatically.)
|
||||
|
||||
Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary:
|
||||
https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
NEO-M8U: https://www.sparkfun.com/products/16329
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a Redboard Qwiic
|
||||
If you don't have a platform with a Qwiic connection use the
|
||||
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GPS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("Warning! u-blox GPS did not begin correctly."));
|
||||
Serial.println(F("(This may be because the I2C port is busy with HNR messages.)"));
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
if (myGNSS.setHNRNavigationRate(10) == true) //Set the High Navigation Rate to 10Hz
|
||||
Serial.println(F("setHNRNavigationRate was successful"));
|
||||
else
|
||||
Serial.println(F("setHNRNavigationRate was NOT successful"));
|
||||
|
||||
myGNSS.setAutoHNRATT(false); //Make sure auto HNR attitude messages are disabled
|
||||
myGNSS.setAutoHNRINS(false); //Make sure auto HNR vehicle dynamics messages are disabled
|
||||
myGNSS.setAutoHNRPVT(false); //Make sure auto HNR PVT messages are disabled
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Poll and print selected HNR data
|
||||
if (myGNSS.getHNRAtt(125) == true) // Request HNR Att data using a 125ms timeout
|
||||
{
|
||||
Serial.print(F("Roll: "));
|
||||
Serial.print(myGNSS.getHNRroll(), 2); // Use the helper function to get the roll in degrees
|
||||
Serial.print(F(" Pitch: "));
|
||||
Serial.print(myGNSS.getHNRpitch(), 2); // Use the helper function to get the pitch in degrees
|
||||
Serial.print(F(" Heading: "));
|
||||
Serial.println(myGNSS.getHNRheading(), 2); // Use the helper function to get the heading in degrees
|
||||
}
|
||||
if (myGNSS.getHNRDyn(125) == true) // Request HNR Dyn data using a 125ms timeout
|
||||
{
|
||||
Serial.print(F("xAccel: "));
|
||||
Serial.print(myGNSS.packetUBXHNRINS->data.xAccel);
|
||||
Serial.print(F(" yAccel: "));
|
||||
Serial.print(myGNSS.packetUBXHNRINS->data.yAccel);
|
||||
Serial.print(F(" zAccel: "));
|
||||
Serial.println(myGNSS.packetUBXHNRINS->data.zAccel);
|
||||
}
|
||||
if (myGNSS.getHNRPVT(125) == true) // Request HNR PVT data using a 125ms timeout
|
||||
{
|
||||
Serial.print(F("ns: "));
|
||||
Serial.print(myGNSS.packetUBXHNRPVT->data.nano);
|
||||
Serial.print(F(" Lat: "));
|
||||
Serial.print(myGNSS.packetUBXHNRPVT->data.lat);
|
||||
Serial.print(F(" Lon: "));
|
||||
Serial.println(myGNSS.packetUBXHNRPVT->data.lon);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: December, 2020
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example configures the High Navigation Rate on the NEO-M8U and then
|
||||
reads and displays the attitude solution, vehicle dynamics information
|
||||
and high rate position, velocity and time.
|
||||
|
||||
This example uses "autoHNR" to receive the HNR data automatically.
|
||||
|
||||
Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary:
|
||||
https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
NEO-M8U: https://www.sparkfun.com/products/16329
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a Redboard Qwiic
|
||||
If you don't have a platform with a Qwiic connection use the
|
||||
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GPS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
bool usingAutoHNRAtt = false;
|
||||
bool usingAutoHNRDyn = false;
|
||||
bool usingAutoHNRPVT = false;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("Warning! u-blox GPS did not begin correctly."));
|
||||
Serial.println(F("(This may be because the I2C port is busy with HNR messages.)"));
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
if (myGNSS.setHNRNavigationRate(10) == true) //Set the High Navigation Rate to 10Hz
|
||||
Serial.println(F("setHNRNavigationRate was successful"));
|
||||
else
|
||||
Serial.println(F("setHNRNavigationRate was NOT successful"));
|
||||
|
||||
usingAutoHNRAtt = myGNSS.setAutoHNRATT(true); //Attempt to enable auto HNR attitude messages
|
||||
if (usingAutoHNRAtt)
|
||||
Serial.println(F("AutoHNRATT successful"));
|
||||
|
||||
usingAutoHNRDyn = myGNSS.setAutoHNRINS(true); //Attempt to enable auto HNR vehicle dynamics messages
|
||||
if (usingAutoHNRDyn)
|
||||
Serial.println(F("AutoHNRINS successful"));
|
||||
|
||||
usingAutoHNRPVT = myGNSS.setAutoHNRPVT(true); //Attempt to enable auto HNR PVT messages
|
||||
if (usingAutoHNRPVT)
|
||||
Serial.println(F("AutoHNRPVT successful"));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (usingAutoHNRAtt && (myGNSS.getHNRAtt() == true)) // If setAutoHNRAtt was successful and new data is available
|
||||
{
|
||||
Serial.print(F("Roll: ")); // Print selected data
|
||||
Serial.print(myGNSS.getHNRroll(), 2); // Use the helper function to get the roll in degrees
|
||||
Serial.print(F(" Pitch: "));
|
||||
Serial.print(myGNSS.getHNRpitch(), 2); // Use the helper function to get the pitch in degrees
|
||||
Serial.print(F(" Heading: "));
|
||||
Serial.println(myGNSS.getHNRheading(), 2); // Use the helper function to get the heading in degrees
|
||||
myGNSS.flushHNRATT(); // Mark data as stale
|
||||
}
|
||||
if (usingAutoHNRDyn && (myGNSS.getHNRDyn() == true)) // If setAutoHNRDyn was successful and new data is available
|
||||
{
|
||||
Serial.print(F("xAccel: ")); // Print selected data
|
||||
Serial.print(myGNSS.packetUBXHNRINS->data.xAccel);
|
||||
Serial.print(F(" yAccel: "));
|
||||
Serial.print(myGNSS.packetUBXHNRINS->data.yAccel);
|
||||
Serial.print(F(" zAccel: "));
|
||||
Serial.println(myGNSS.packetUBXHNRINS->data.zAccel);
|
||||
myGNSS.flushHNRINS(); // Mark data as stale
|
||||
}
|
||||
if (usingAutoHNRPVT && (myGNSS.getHNRPVT() == true)) // If setAutoHNRPVT was successful and new data is available
|
||||
{
|
||||
Serial.print(F("ns: ")); // Print selected data
|
||||
Serial.print(myGNSS.packetUBXHNRPVT->data.nano);
|
||||
Serial.print(F(" Lat: "));
|
||||
Serial.print(myGNSS.packetUBXHNRPVT->data.lat);
|
||||
Serial.print(F(" Lon: "));
|
||||
Serial.println(myGNSS.packetUBXHNRPVT->data.lon);
|
||||
myGNSS.flushHNRPVT(); // Mark data as stale
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: August, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example configures the AutoAlignment option for the IMU.
|
||||
The ZED-F9R Integration guide recommends enabling Auto Alignment once
|
||||
the device has been attached to the vehicle's frame.
|
||||
Enabling auto-alignment will cause the the sensor fusion status
|
||||
to begin initialization. After driving around a few turns, the sensors
|
||||
should enter 'Calibrated' state. See example 1 for fusion state or
|
||||
monitor UBX-ESF-STATUS.
|
||||
|
||||
As of writing the ZED-F9R is using HPS v1.2 firmware. Please update using u-center if necessary.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9R: https://www.sparkfun.com/products/16344
|
||||
ZED-F9R pHat: https://www.sparkfun.com/products/16475
|
||||
NEO-M8U: https://www.sparkfun.com/products/16329
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GPS and a Redboard Qwiic
|
||||
If you don't have a platform with a Qwiic connection use the
|
||||
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/17912)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GPS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("Warning! u-blox GPS did not begin correctly."));
|
||||
Serial.println(F("(This may be because the I2C port is busy with HNR messages.)"));
|
||||
}
|
||||
|
||||
bool esfAutoAlignment = myGNSS.getESFAutoAlignment();
|
||||
Serial.print(F("esfAutoAlignment: "));
|
||||
if (esfAutoAlignment == true)
|
||||
Serial.println(F("True"));
|
||||
else
|
||||
Serial.println(F("False"));
|
||||
|
||||
myGNSS.setESFAutoAlignment(true); //Enable UBX-CFG-ESFALG Automatic IMU-mount Alignment
|
||||
|
||||
myGNSS.setAutoHNRATT(false); //Make sure auto HNR attitude messages are disabled
|
||||
myGNSS.setAutoHNRINS(false); //Make sure auto HNR vehicle dynamics messages are disabled
|
||||
myGNSS.setAutoHNRPVT(false); //Make sure auto HNR PVT messages are disabled
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// ESF data is produced at the navigation rate, so by default we'll get fresh data once per second
|
||||
if (myGNSS.getEsfInfo()) // Poll new ESF STATUS data
|
||||
{
|
||||
Serial.print(F("Fusion Mode: "));
|
||||
Serial.print(myGNSS.packetUBXESFSTATUS->data.fusionMode);
|
||||
if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 0)
|
||||
Serial.println(F(" Sensor is initializing..."));
|
||||
else if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 1)
|
||||
Serial.println(F(" Sensor is calibrated!"));
|
||||
else if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 2)
|
||||
Serial.println(F(" Sensor fusion is suspended!"));
|
||||
else if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 3)
|
||||
Serial.println(F(" Sensor fusion is disabled!"));
|
||||
}
|
||||
|
||||
// Poll and print selected HNR data
|
||||
if (myGNSS.getHNRAtt(125) == true) // Request HNR Att data using a 125ms timeout
|
||||
{
|
||||
Serial.print(F("Roll: "));
|
||||
Serial.print(myGNSS.getHNRroll(), 2); // Use the helper function to get the roll in degrees
|
||||
Serial.print(F(" Pitch: "));
|
||||
Serial.print(myGNSS.getHNRpitch(), 2); // Use the helper function to get the pitch in degrees
|
||||
Serial.print(F(" Heading: "));
|
||||
Serial.println(myGNSS.getHNRheading(), 2); // Use the helper function to get the heading in degrees
|
||||
}
|
||||
if (myGNSS.getHNRDyn(125) == true) // Request HNR Dyn data using a 125ms timeout
|
||||
{
|
||||
Serial.print(F("xAccel: "));
|
||||
Serial.print(myGNSS.packetUBXHNRINS->data.xAccel);
|
||||
Serial.print(F(" yAccel: "));
|
||||
Serial.print(myGNSS.packetUBXHNRINS->data.yAccel);
|
||||
Serial.print(F(" zAccel: "));
|
||||
Serial.println(myGNSS.packetUBXHNRINS->data.zAccel);
|
||||
}
|
||||
if (myGNSS.getHNRPVT(125) == true) // Request HNR PVT data using a 125ms timeout
|
||||
{
|
||||
Serial.print(F("ns: "));
|
||||
Serial.print(myGNSS.packetUBXHNRPVT->data.nano);
|
||||
Serial.print(F(" Lat: "));
|
||||
Serial.print(myGNSS.packetUBXHNRPVT->data.lat);
|
||||
Serial.print(F(" Lon: "));
|
||||
Serial.println(myGNSS.packetUBXHNRPVT->data.lon);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
By: Paul CLark
|
||||
SparkFun Electronics
|
||||
Date: January, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9R: https://www.sparkfun.com/products/16344
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a Redboard Qwiic
|
||||
If you don't have a platform with a Qwiic connection use the
|
||||
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
|
||||
After calibrating the module and securing it to your vehicle such that it's
|
||||
stable within 2 degrees, and the board is oriented correctly with regards to
|
||||
the vehicle's frame, you can now read the vehicle's "attitude". The attitude
|
||||
includes the vehicle's heading, pitch, and roll.
|
||||
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// PVAT data is produced at the navigation rate, so by default we'll get fresh data once per second
|
||||
if (myGNSS.getNAVPVAT()) // Poll new PVAT
|
||||
{
|
||||
Serial.print(F("Roll: "));
|
||||
Serial.print((float)myGNSS.getVehicleRoll() / 100000.0, 5); // Use the helper function to get the roll in degrees * 10^-5
|
||||
|
||||
Serial.print(F(" Pitch: "));
|
||||
Serial.print((float)myGNSS.getVehiclePitch() / 100000.0, 5); // Use the helper function to get the pitch in degrees * 10^-5
|
||||
|
||||
Serial.print(F(" Heading: "));
|
||||
Serial.print((float)myGNSS.getVehicleHeading() / 100000.0, 5); // Use the helper function to get the heading in degrees * 10^-5
|
||||
|
||||
// We don't have helper functions to extract the roll, pitch and heading valid flags from the PVAT message. But we can do it manually:
|
||||
|
||||
Serial.print(F(" Roll Valid: "));
|
||||
Serial.print(myGNSS.packetUBXNAVPVAT->data.flags.bits.vehRollValid);
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.vehRollValid = false; // Mark the data as stale
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
|
||||
|
||||
Serial.print(F(" Pitch Valid: "));
|
||||
Serial.print(myGNSS.packetUBXNAVPVAT->data.flags.bits.vehPitchValid);
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.vehPitchValid = false; // Mark the data as stale
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
|
||||
|
||||
Serial.print(F(" Heading Valid: "));
|
||||
Serial.print(myGNSS.packetUBXNAVPVAT->data.flags.bits.vehHeadingValid);
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.vehHeadingValid = false; // Mark the data as stale
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
|
||||
|
||||
// We don't have helper functions to extract the roll, pitch and heading accuracy from the PVAT message. But we can do it manually:
|
||||
|
||||
Serial.print(F(" Roll Acc: "));
|
||||
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.accRoll) / 100, 2);
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.accRoll = false; // Mark the data as stale
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
|
||||
|
||||
Serial.print(F(" Pitch Acc: "));
|
||||
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.accPitch) / 100, 2);
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.accPitch = false; // Mark the data as stale
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
|
||||
|
||||
Serial.print(F(" Heading Acc: "));
|
||||
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.accHeading) / 100, 2);
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.accHeading = false; // Mark the data as stale
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
|
||||
|
||||
// We don't have helper functions to extract the lat and lon from the PVAT message. But we can do it manually:
|
||||
|
||||
Serial.print(F(" Lat: "));
|
||||
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.lat) / 10000000.0, 7);
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.lat = false; // Mark the data as stale
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
|
||||
|
||||
Serial.print(F(" Lon: "));
|
||||
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.lon) / 10000000.0, 7);
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.lon = false; // Mark the data as stale
|
||||
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
delay(250);
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
Reading two altitudes - Mean Sea Level and Ellipsode
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: January 3rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to query a u-blox module for its lat/long/altitude.
|
||||
|
||||
getAltitude() reports mm above ellipsode model of the globe. There are some
|
||||
instances where altitude above Mean Sea Level is better. This example shows how
|
||||
to use getAltitudeMSL(). The difference varies but is ~20m.
|
||||
Ellipsoid model: https://www.esri.com/news/arcuser/0703/geoid1of3.html
|
||||
Difference between Ellipsoid Model and Mean Sea Level: https://eos-gnss.com/elevation-for-beginners/
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
long lastTime = 0; //Tracks the passing of 2000ms (2 seconds)
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Query module only every second. Doing it more often will just cause I2C traffic.
|
||||
//The module only responds when a new position is available
|
||||
if (millis() - lastTime > 1000)
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
long altitudeMSL = myGNSS.getAltitudeMSL();
|
||||
Serial.print(F(" AltMSL: "));
|
||||
Serial.print(altitudeMSL);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
Send command to reset module over I2C
|
||||
By: Nathan Seidle
|
||||
Date: January 29rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to reset the U-Blox module to factory defaults over I2C.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
while (Serial.available()) Serial.read(); //Trash any incoming chars
|
||||
Serial.println("Press a key to reset module to factory defaults");
|
||||
while (Serial.available() == false) ; //Wait for user to send character
|
||||
|
||||
myGNSS.factoryReset(); //Reset everything: baud rate, I2C address, update rate, everything.
|
||||
|
||||
delay(5000); // Wait while the module restarts
|
||||
|
||||
while (myGNSS.begin() == false) //Attempt to re-connect
|
||||
{
|
||||
delay(1000);
|
||||
Serial.println(F("Attempting to re-connect to u-blox GNSS..."));
|
||||
}
|
||||
|
||||
Serial.println("Unit has now been factory reset. Freezing...");
|
||||
while(1); // Do nothing more
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
Test baud rate changes on serial, factory reset, and hard reset.
|
||||
By: Thorsten von Eicken
|
||||
Date: January 29rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to reset the U-Blox module to factory defaults over serial.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Connect the U-Blox serial port to Serial1
|
||||
If you're using a Uno or don't have a 2nd serial port (Serial1), use SoftwareSerial instead (see below)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
//#define mySerial Serial1 // Uncomment this line to connect via Serial1
|
||||
// - or -
|
||||
SoftwareSerial mySerial(10, 11); // Uncomment this line to connect via SoftwareSerial(RX, TX). Connect pin 10 to GNSS TX pin.
|
||||
|
||||
#define defaultRate 9600 // Uncomment this line if you are using an M8 - which defaults to 9600 Baud on UART1
|
||||
// - or -
|
||||
//#define defaultRate 38400 // Uncomment this line if you are using an F9 - which defaults to 38400 Baud on UART1
|
||||
|
||||
int state = 0; // steps through auto-baud, reset, etc states
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.print("===== STATE ");
|
||||
Serial.println(state);
|
||||
switch (state) {
|
||||
case 0: // auto-baud connection, then switch to 38400 and save config
|
||||
do {
|
||||
Serial.println("GNSS: trying 38400 baud");
|
||||
mySerial.begin(38400);
|
||||
if (myGNSS.begin(mySerial)) break;
|
||||
|
||||
delay(100);
|
||||
Serial.println("GNSS: trying 9600 baud");
|
||||
mySerial.begin(9600);
|
||||
if (myGNSS.begin(mySerial)) {
|
||||
Serial.println("GNSS: connected at 9600 baud, switching to 38400");
|
||||
myGNSS.setSerialRate(38400);
|
||||
delay(100);
|
||||
} else {
|
||||
delay(2000); //Wait a bit before trying again to limit the Serial output flood
|
||||
}
|
||||
} while(1);
|
||||
myGNSS.setUART1Output(COM_TYPE_UBX); //Set the UART port to output UBX only
|
||||
myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
|
||||
Serial.println("GNSS serial connected, saved config");
|
||||
state++;
|
||||
break;
|
||||
case 1: // hardReset, expect to see GNSS back at 38400 baud
|
||||
Serial.println("Issuing hardReset (cold start)");
|
||||
myGNSS.hardReset();
|
||||
delay(2000);
|
||||
mySerial.begin(38400);
|
||||
if (myGNSS.begin(mySerial)) {
|
||||
Serial.println("Success.");
|
||||
state++;
|
||||
} else {
|
||||
Serial.println("*** GNSS did not respond at 38400 baud, starting over.");
|
||||
state = 0;
|
||||
}
|
||||
break;
|
||||
case 2: // factoryReset, expect to see GNSS back at defaultRate baud
|
||||
Serial.println("Issuing factoryReset");
|
||||
myGNSS.factoryReset();
|
||||
delay(5000); // takes more than one second... a loop to resync would be best
|
||||
mySerial.begin(defaultRate);
|
||||
if (myGNSS.begin(mySerial)) {
|
||||
Serial.println("Success.");
|
||||
state++;
|
||||
} else {
|
||||
Serial.println("*** GNSS did not come back at defaultRate baud, starting over.");
|
||||
state = 0;
|
||||
}
|
||||
break;
|
||||
case 3: // print version info
|
||||
// Note: this may fail on boards like the UNO (ATmega328P) with modules like the ZED-F9P
|
||||
// because getProtocolVersion returns a lot of data - more than the UNO's serial buffer can hold
|
||||
Serial.print("GNSS protocol version: ");
|
||||
Serial.print(myGNSS.getProtocolVersionHigh());
|
||||
Serial.print('.');
|
||||
Serial.println(myGNSS.getProtocolVersionLow());
|
||||
Serial.println("All finished! Freezing...");
|
||||
while(1);
|
||||
}
|
||||
delay(1000);
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
Reading lat and long via UBX binary commands using UART @38400 baud - free from I2C
|
||||
By: Nathan Seidle, Adapted from Example3_GetPosition by Thorsten von Eicken
|
||||
SparkFun Electronics
|
||||
Date: January 28rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the library and U-Blox for serial port use as well as
|
||||
switching the module from the default 9600 baud to 38400.
|
||||
|
||||
Note: Long/lat are large numbers because they are * 10^7. To convert lat/long
|
||||
to something google maps understands simply divide the numbers by 10,000,000. We
|
||||
do this so that we don't have to use floating point numbers.
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Connect the U-Blox serial TX pin to Uno pin 10
|
||||
Connect the U-Blox serial RX pin to Uno pin 11
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial mySerial(10, 11); // RX, TX. Pin 10 on Uno goes to TX pin on GNSS module.
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount of I2C traffic to u-blox module.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
//Assume that the U-Blox GNSS is running at 9600 baud (the default) or at 38400 baud.
|
||||
//Loop until we're in sync and then ensure it's at 38400 baud.
|
||||
do {
|
||||
Serial.println("GNSS: trying 38400 baud");
|
||||
mySerial.begin(38400);
|
||||
if (myGNSS.begin(mySerial) == true) break;
|
||||
|
||||
delay(100);
|
||||
Serial.println("GNSS: trying 9600 baud");
|
||||
mySerial.begin(9600);
|
||||
if (myGNSS.begin(mySerial) == true) {
|
||||
Serial.println("GNSS: connected at 9600 baud, switching to 38400");
|
||||
myGNSS.setSerialRate(38400);
|
||||
delay(100);
|
||||
} else {
|
||||
//myGNSS.factoryReset();
|
||||
delay(2000); //Wait a bit before trying again to limit the Serial output
|
||||
}
|
||||
} while(1);
|
||||
Serial.println("GNSS serial connected");
|
||||
|
||||
myGNSS.setUART1Output(COM_TYPE_UBX); //Set the UART port to output UBX only
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Query module only every second. Doing it more often will just cause I2C traffic.
|
||||
//The module only responds when a new position is available
|
||||
if (millis() - lastTime > 1000)
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send position reports over I2C
|
||||
By: Nathan Seidle and Thorsten von Eicken
|
||||
SparkFun Electronics
|
||||
Date: January 3rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the U-Blox GNSS the send navigation reports automatically
|
||||
and retrieving the latest one via getPVT. This eliminates the blocking in getPVT while the GNSS
|
||||
produces a fresh navigation solution at the expense of returning a slighly old solution.
|
||||
|
||||
This can be used over serial or over I2C, this example shows the I2C use. With serial the GNSS
|
||||
simply outputs the UBX_NAV_PVT packet. With I2C it queues it into its internal I2C buffer (4KB in
|
||||
size?) where it can be retrieved in the next I2C poll.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.setNavigationFrequency(2); //Produce two solutions per second
|
||||
myGNSS.setAutoPVT(true); //Tell the GNSS to "send" each solution
|
||||
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Calling getPVT returns true if there actually is a fresh navigation solution available.
|
||||
// Start the reading only when valid LLH is available
|
||||
if (myGNSS.getPVT() && (myGNSS.getInvalidLlh() == false))
|
||||
{
|
||||
Serial.println();
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
int PDOP = myGNSS.getPDOP();
|
||||
Serial.print(F(" PDOP: "));
|
||||
Serial.print(PDOP);
|
||||
Serial.print(F(" (10^-2)"));
|
||||
|
||||
int nedNorthVel = myGNSS.getNedNorthVel();
|
||||
Serial.print(F(" VelN: "));
|
||||
Serial.print(nedNorthVel);
|
||||
Serial.print(F(" (mm/s)"));
|
||||
|
||||
int nedEastVel = myGNSS.getNedEastVel();
|
||||
Serial.print(F(" VelE: "));
|
||||
Serial.print(nedEastVel);
|
||||
Serial.print(F(" (mm/s)"));
|
||||
|
||||
int nedDownVel = myGNSS.getNedDownVel();
|
||||
Serial.print(F(" VelD: "));
|
||||
Serial.print(nedDownVel);
|
||||
Serial.print(F(" (mm/s)"));
|
||||
|
||||
int verticalAccEst = myGNSS.getVerticalAccEst();
|
||||
Serial.print(F(" VAccEst: "));
|
||||
Serial.print(verticalAccEst);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
int horizontalAccEst = myGNSS.getHorizontalAccEst();
|
||||
Serial.print(F(" HAccEst: "));
|
||||
Serial.print(horizontalAccEst);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
int speedAccEst = myGNSS.getSpeedAccEst();
|
||||
Serial.print(F(" SpeedAccEst: "));
|
||||
Serial.print(speedAccEst);
|
||||
Serial.print(F(" (mm/s)"));
|
||||
|
||||
int headAccEst = myGNSS.getHeadingAccEst();
|
||||
Serial.print(F(" HeadAccEst: "));
|
||||
Serial.print(headAccEst);
|
||||
Serial.print(F(" (degrees * 10^-5)"));
|
||||
|
||||
if (myGNSS.getHeadVehValid() == true) {
|
||||
int headVeh = myGNSS.getHeadVeh();
|
||||
Serial.print(F(" HeadVeh: "));
|
||||
Serial.print(headVeh);
|
||||
Serial.print(F(" (degrees * 10^-5)"));
|
||||
|
||||
int magDec = myGNSS.getMagDec();
|
||||
Serial.print(F(" MagDec: "));
|
||||
Serial.print(magDec);
|
||||
Serial.print(F(" (degrees * 10^-2)"));
|
||||
|
||||
int magAcc = myGNSS.getMagAcc();
|
||||
Serial.print(F(" MagAcc: "));
|
||||
Serial.print(magAcc);
|
||||
Serial.print(F(" (degrees * 10^-2)"));
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
} else {
|
||||
Serial.print(".");
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send position reports over I2C, with explicit data parsing calls
|
||||
By: Nathan Seidle Thorsten von Eicken and Felix Jirka
|
||||
SparkFun Electronics
|
||||
Date: July 1st, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the U-Blox GNSS the send navigation reports automatically
|
||||
and retrieving the latest one via checkUblox when available.
|
||||
This eliminates the implicit update in getPVT when accessing data fields twice.
|
||||
Also this reduces the memory overhead of a separate buffer while introducing a slight error by inconsistencies because of the unsynchronized updates (on a multi core system).
|
||||
|
||||
This can be used over serial or over I2C, this example shows the I2C use. With serial the GNSS
|
||||
simply outputs the UBX_NAV_PVT packet. With I2C it queues it into its internal I2C buffer (4KB in
|
||||
size?) where it can be retrieved in the next I2C poll.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial)
|
||||
; //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.setNavigationFrequency(2); //Produce two solutions per second
|
||||
myGNSS.setAutoPVT(true, false); //Tell the GNSS to "send" each solution and the lib not to update stale data implicitly
|
||||
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
|
||||
}
|
||||
|
||||
/*
|
||||
Calling getPVT would return false now (compare to previous example where it would return true), so we just use the data provided
|
||||
If you are using a threaded OS eg. FreeRTOS on an ESP32, the explicit mode of autoPVT allows you to use the data provided on both cores and inside multiple threads
|
||||
The data update in background creates an inconsistent state, but that should not cause issues for most applications as they usually won't change the GNSS location significantly within a 2Hz - 5Hz update rate.
|
||||
Also you could oversample (10Hz - 20Hz) the data to smooth out such issues...
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
static uint16_t counter = 0;
|
||||
|
||||
if (counter % 10 == 0)
|
||||
{
|
||||
// update your AHRS filter here for a ~100Hz update rate
|
||||
// GNSS data will be quasi static but data from your IMU will be changing
|
||||
}
|
||||
// debug output each half second
|
||||
if (counter % 500 == 0)
|
||||
{
|
||||
Serial.println();
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
// call checkUblox all 50ms to capture the GNSS data
|
||||
if (counter % 50 == 0)
|
||||
{
|
||||
myGNSS.checkUblox();
|
||||
}
|
||||
delay(1);
|
||||
counter++;
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send position reports over Serial
|
||||
By: Nathan Seidle, Adapted from Example11 by Felix Jirka
|
||||
SparkFun Electronics
|
||||
Date: July 2nd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the U-Blox GNSS the send navigation reports automatically
|
||||
and retrieving the latest one via getPVT. This eliminates the blocking in getPVT while the GNSS
|
||||
produces a fresh navigation solution at the expense of returning a slighly old solution.
|
||||
|
||||
This can be used over serial or over I2C, this example shows the Serial use. With serial the GNSS
|
||||
simply outputs the UBX_NAV_PVT packet. With I2C it queues it into its internal I2C buffer (4KB in
|
||||
size?) where it can be retrieved in the next I2C poll.
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
//#define mySerial Serial2 // Uncomment this line to connect via Serial2
|
||||
// - or -
|
||||
SoftwareSerial mySerial(10, 11); // Uncomment this line to connect via SoftwareSerial(RX, TX). Connect pin 10 to GNSS TX pin.
|
||||
|
||||
//#define baudRate 9600 // Uncomment this line to select 9600 Baud for the M8
|
||||
// - or -
|
||||
#define baudRate 38400 // Uncomment this line to select 38400 Baud for the F9
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
mySerial.begin(baudRate); // Start the Serial port
|
||||
|
||||
if (myGNSS.begin(mySerial) == false) //Connect to the u-blox module using Serial
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setUART1Output(COM_TYPE_UBX); //Set the UART1 port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.setNavigationFrequency(2); //Produce two solutions per second
|
||||
myGNSS.setAutoPVT(true); //Tell the GNSS to "send" each solution
|
||||
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// getPVT will return true if there actually is a fresh navigation solution available.
|
||||
// Important note: the PVT message is 100 bytes long. We need to call getPVT often enough
|
||||
// to prevent serial buffer overflows on boards like the original RedBoard / UNO.
|
||||
// At 38400 Baud, the 100 PVT bytes will arrive in 26ms.
|
||||
// On the RedBoard, we need to call getPVT every 5ms to keep up.
|
||||
if (myGNSS.getPVT())
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
else
|
||||
{
|
||||
delay(5); // Delay for 5ms only
|
||||
|
||||
static int counter = 0; // Print a dot every 50ms
|
||||
counter++;
|
||||
if (counter > 10)
|
||||
{
|
||||
Serial.print(".");
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
Reading lat and long via UBX binary commands using an RX-only UART
|
||||
By: Nathan Seidle, Adapted from Example11 by Felix Jirka
|
||||
SparkFun Electronics
|
||||
Date: July 2nd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the library for serial port use with a single wire connection using the assumeAutoPVT method.
|
||||
Saving your pins for other stuff :-)
|
||||
|
||||
This example only works correctly if the module has already been configured is sending PVT messages via its UART1 TX pin.
|
||||
Run the previous example to enable the auto PVT messages if you need to.
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Preconditions:
|
||||
U-Blox module is configured to send cyclical PVT message
|
||||
|
||||
Hardware Connections:
|
||||
Connect the U-Blox serial TX pin to Rx of Serial2 (default: GPIO16) on your ESP32
|
||||
Or, switch to SoftwareSerial
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
//#define mySerial Serial2 // Uncomment this line to connect via Serial2
|
||||
// - or -
|
||||
SoftwareSerial mySerial(10, 11); // Uncomment this line to connect via SoftwareSerial(RX, TX). Connect pin 10 to GNSS TX pin.
|
||||
|
||||
//#define baudRate 9600 // Uncomment this line to select 9600 Baud for the M8
|
||||
// - or -
|
||||
#define baudRate 38400 // Uncomment this line to select 38400 Baud for the F9
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
//Use any Serial port with at least a RX Pin connected or a receive only version of SoftwareSerial here
|
||||
//Assume that the U-Blox GNSS is running at baudRate baud
|
||||
mySerial.begin(baudRate);
|
||||
// No need to check return value as internal call to isConnected() will not succeed
|
||||
myGNSS.begin(mySerial);
|
||||
|
||||
// Tell the library we are expecting the module to send PVT messages by itself to our Rx pin.
|
||||
// You can set second parameter to "false" if you want to control the parsing and eviction of the data (need to call checkUblox cyclically)
|
||||
myGNSS.assumeAutoPVT(true, true);
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// If implicit updates are enabled, calling getPVT will trigger parsing of the incoming messages
|
||||
// and return true once a PVT message has been parsed.
|
||||
// In case you want to use explicit updates, wrap this in a timer and call checkUblox()
|
||||
// as often as needed, not to overflow your UART buffers.
|
||||
//
|
||||
// Important note: the PVT message is 100 bytes long. We need to call getPVT often enough
|
||||
// to prevent serial buffer overflows on boards like the original RedBoard / UNO.
|
||||
// At 38400 Baud, the 100 PVT bytes will arrive in 26ms.
|
||||
// On the RedBoard, we need to call getPVT every 5ms to keep up.
|
||||
if (myGNSS.getPVT())
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
else
|
||||
{
|
||||
delay(5); // Delay for 5ms only
|
||||
|
||||
static int counter = 0; // Print a dot every 50ms
|
||||
counter++;
|
||||
if (counter > 10)
|
||||
{
|
||||
Serial.print(".");
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
Debug Output
|
||||
By: Nathan Seidle, Adapted from Example3_GetPosition by Thorsten von Eicken
|
||||
SparkFun Electronics
|
||||
Date: January 28rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the debug output from the library.
|
||||
Debug shows various packet and status outputs. These prints can be directed
|
||||
towards Serial (as in Serial.print) or any other port (Serial1, SerialUSB, etc).
|
||||
|
||||
You can also limit the debug messages to the "critical" ones by adding an extra argument.
|
||||
|
||||
The debug messages can be disabled again by calling disableDebugging()
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
unsigned long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
int counter = 0; // Disable the debug messages when counter reaches 20
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
|
||||
|
||||
myGNSS.enableDebugging(); //Enable all the debug messages over Serial (default)
|
||||
|
||||
//myGNSS.enableDebugging(SerialUSB); //Enable debug messages over Serial USB
|
||||
|
||||
//myGNSS.enableDebugging(Serial, true); //Enable only the critical debug messages over Serial
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Query module only every second. Doing it more often will just cause I2C traffic.
|
||||
//The module only responds when a new position is available
|
||||
if (millis() - lastTime > 1000)
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
Serial.print(F(" "));
|
||||
Serial.print(myGNSS.getYear());
|
||||
Serial.print(F("-"));
|
||||
Serial.print(myGNSS.getMonth());
|
||||
Serial.print(F("-"));
|
||||
Serial.print(myGNSS.getDay());
|
||||
Serial.print(F(" "));
|
||||
Serial.print(myGNSS.getHour());
|
||||
Serial.print(F(":"));
|
||||
Serial.print(myGNSS.getMinute());
|
||||
Serial.print(F(":"));
|
||||
Serial.println(myGNSS.getSecond());
|
||||
|
||||
Serial.println();
|
||||
|
||||
counter++; // Increment counter
|
||||
if (counter == 20)
|
||||
{
|
||||
myGNSS.disableDebugging(); // Disable the debug messages when counter reaches 20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
Getting time and date using u-blox commands
|
||||
By: davidallenmann
|
||||
SparkFun Electronics
|
||||
Date: April 16th, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to query a u-blox module for the current time and date. We also
|
||||
turn off the NMEA output on the I2C port. This decreases the amount of I2C traffic
|
||||
dramatically.
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial)
|
||||
; //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Query module only every second. Doing it more often will just cause I2C traffic.
|
||||
//The module only responds when a new position is available
|
||||
if (millis() - lastTime > 1000)
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
Serial.println();
|
||||
Serial.print(myGNSS.getYear());
|
||||
Serial.print("-");
|
||||
Serial.print(myGNSS.getMonth());
|
||||
Serial.print("-");
|
||||
Serial.print(myGNSS.getDay());
|
||||
Serial.print(" ");
|
||||
Serial.print(myGNSS.getHour());
|
||||
Serial.print(":");
|
||||
Serial.print(myGNSS.getMinute());
|
||||
Serial.print(":");
|
||||
Serial.print(myGNSS.getSecond());
|
||||
|
||||
Serial.print(" Time is ");
|
||||
if (myGNSS.getTimeValid() == false)
|
||||
{
|
||||
Serial.print("not ");
|
||||
}
|
||||
Serial.print("valid Date is ");
|
||||
if (myGNSS.getDateValid() == false)
|
||||
{
|
||||
Serial.print("not ");
|
||||
}
|
||||
Serial.print("valid");
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
Getting time and date using u-blox commands
|
||||
By: davidallenmann
|
||||
SparkFun Electronics
|
||||
Date: April 16th, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to query a u-blox module for the current time and date. We also
|
||||
turn off the NMEA output on the I2C port. This decreases the amount of I2C traffic
|
||||
dramatically.
|
||||
|
||||
Note: you will need to set your Serial Monitor to 500000 Baud to see the output
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(500000); //Increase serial speed to maximize
|
||||
while (!Serial)
|
||||
; //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
Wire.setClock(400000); // Increase I2C clock speed to 400kHz
|
||||
|
||||
//myGNSS.enableDebugging(); //Uncomment this line to enable debug messages over Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(5); //Set output to 5 times a second
|
||||
|
||||
byte rate = myGNSS.getNavigationFrequency(); //Get the update rate of this module
|
||||
Serial.print("Current update rate: ");
|
||||
Serial.println(rate);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Calling getPVT returns true if there actually is a fresh navigation solution available.
|
||||
if (myGNSS.getPVT())
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
Serial.print(" ");
|
||||
Serial.print(myGNSS.getYear());
|
||||
Serial.print("-");
|
||||
Serial.print(myGNSS.getMonth());
|
||||
Serial.print("-");
|
||||
Serial.print(myGNSS.getDay());
|
||||
Serial.print(" ");
|
||||
Serial.print(myGNSS.getHour());
|
||||
Serial.print(":");
|
||||
Serial.print(myGNSS.getMinute());
|
||||
Serial.print(":");
|
||||
Serial.print(myGNSS.getSecond());
|
||||
Serial.print(" nanoseconds: ");
|
||||
Serial.print(myGNSS.getNanosecond()); // Nanoseconds can be negative
|
||||
|
||||
myGNSS.flushPVT();
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
Getting time and date using u-blox commands
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: April 16th, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to use the Millisecond and Nanosecond output as well as increase the
|
||||
I2C speed (100 to 400kHz), and serial output (115200 to 500kbps).
|
||||
|
||||
Note: you will need to set your Serial Monitor to 500000 Baud to see the output
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(500000); //Increase serial speed to maximize
|
||||
while (!Serial)
|
||||
; //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
Wire.setClock(400000); // Increase I2C clock speed to 400kHz
|
||||
|
||||
//myGNSS.enableDebugging(); //Uncomment this line to enable debug messages over Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
|
||||
// Note: not all u-blox modules can output solutions at 10Hz - or not while tracking all satellite constellations
|
||||
// If the rate drops back to 1Hz, you're asking too much of your module
|
||||
myGNSS.setNavigationFrequency(10); //Set output to 10 times a second
|
||||
|
||||
byte rate = myGNSS.getNavigationFrequency(); //Get the update rate of this module
|
||||
Serial.print("Current update rate:");
|
||||
Serial.println(rate);
|
||||
|
||||
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Calling getPVT returns true if there actually is a fresh navigation solution available.
|
||||
if (myGNSS.getPVT())
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
Serial.print(" ");
|
||||
Serial.print(myGNSS.getYear());
|
||||
Serial.print("-");
|
||||
Serial.print(myGNSS.getMonth());
|
||||
Serial.print("-");
|
||||
Serial.print(myGNSS.getDay());
|
||||
Serial.print(" ");
|
||||
Serial.print(myGNSS.getHour());
|
||||
Serial.print(":");
|
||||
Serial.print(myGNSS.getMinute());
|
||||
Serial.print(":");
|
||||
Serial.print(myGNSS.getSecond());
|
||||
Serial.print(".");
|
||||
//Pretty print leading zeros
|
||||
int mseconds = myGNSS.getMillisecond();
|
||||
if (mseconds < 100)
|
||||
Serial.print("0");
|
||||
if (mseconds < 10)
|
||||
Serial.print("0");
|
||||
Serial.print(mseconds);
|
||||
|
||||
Serial.print(" nanoseconds: ");
|
||||
Serial.print(myGNSS.getNanosecond());
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
u-blox M8 geofence example
|
||||
|
||||
Written by Paul Clark (PaulZC)
|
||||
10th December 2019
|
||||
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example demonstrates how to use the addGeofence and getGeofenceState functions
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15210
|
||||
ZOE-M8Q: https://www.sparkfun.com/products/15193
|
||||
|
||||
This example powers up the GNSS and reads the fix.
|
||||
Once a valid 3D fix has been found, the code reads the latitude and longitude.
|
||||
The code then sets four geofences around that position with a radii of 5m, 10m, 15m and 20m with 95% confidence.
|
||||
The code then monitors the geofence status.
|
||||
The LED will be illuminated if you are inside the _combined_ geofence (i.e. within the 20m radius).
|
||||
|
||||
This code has been tested on the ZOE-M8Q.
|
||||
*/
|
||||
|
||||
#define LED LED_BUILTIN // Change this if your LED is on a different pin
|
||||
|
||||
#include <Wire.h> // Needed for I2C
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED, OUTPUT);
|
||||
|
||||
// Set up the I2C pins
|
||||
Wire.begin();
|
||||
|
||||
// Start the console serial port
|
||||
Serial.begin(115200);
|
||||
while (!Serial); // Wait for the user to open the serial monitor
|
||||
delay(100);
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println(F("u-blox M8 geofence example"));
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
delay(1000); // Let the GNSS power up
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
//myGNSS.enableDebugging(); // Enable debug messages
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); // Limit I2C output to UBX (disable the NMEA noise)
|
||||
|
||||
Serial.println(F("Waiting for a 3D fix..."));
|
||||
|
||||
byte fixType = 0;
|
||||
|
||||
while (fixType < 3)
|
||||
{
|
||||
fixType = myGNSS.getFixType(); // Get the fix type
|
||||
Serial.print(F("Fix: ")); // Print it
|
||||
Serial.print(fixType);
|
||||
if(fixType == 0) Serial.print(F(" = No fix"));
|
||||
else if(fixType == 1) Serial.print(F(" = Dead reckoning"));
|
||||
else if(fixType == 2) Serial.print(F(" = 2D"));
|
||||
else if(fixType == 3) Serial.print(F(" = 3D"));
|
||||
else if(fixType == 4) Serial.print(F(" = GNSS + Dead reckoning"));
|
||||
else if(fixType == 5) Serial.print(F(" = Time only"));
|
||||
Serial.println();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.println(F("3D fix found!"));
|
||||
|
||||
long latitude = myGNSS.getLatitude(); // Get the latitude in degrees * 10^-7
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude(); // Get the longitude in degrees * 10^-7
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.println(longitude);
|
||||
|
||||
uint32_t radius = 500; // Set the radius to 5m (radius is in m * 10^-2 i.e. cm)
|
||||
|
||||
byte confidence = 2; // Set the confidence level: 0=none, 1=68%, 2=95%, 3=99.7%, 4=99.99%
|
||||
|
||||
// Call clearGeofences() to clear all existing geofences.
|
||||
Serial.print(F("Clearing any existing geofences. clearGeofences returned: "));
|
||||
Serial.println(myGNSS.clearGeofences());
|
||||
|
||||
// It is possible to define up to four geofences.
|
||||
// Call addGeofence up to four times to define them.
|
||||
Serial.println(F("Setting the geofences:"));
|
||||
|
||||
Serial.print(F("addGeofence for geofence 1 returned: "));
|
||||
Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence));
|
||||
|
||||
radius = 1000; // 10m
|
||||
Serial.print(F("addGeofence for geofence 2 returned: "));
|
||||
Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence));
|
||||
|
||||
radius = 1500; // 15m
|
||||
Serial.print(F("addGeofence for geofence 3 returned: "));
|
||||
Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence));
|
||||
|
||||
radius = 2000; // 20m
|
||||
Serial.print(F("addGeofence for geofence 4 returned: "));
|
||||
Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
geofenceState currentGeofenceState; // Create storage for the geofence state
|
||||
|
||||
bool result = myGNSS.getGeofenceState(currentGeofenceState);
|
||||
|
||||
Serial.print(F("getGeofenceState returned: ")); // Print the combined state
|
||||
Serial.print(result); // Get the geofence state
|
||||
|
||||
if (!result) // If getGeofenceState did not return true
|
||||
{
|
||||
Serial.println(F(".")); // Tidy up
|
||||
return; // and go round the loop again
|
||||
}
|
||||
|
||||
Serial.print(F(". status is: ")); // Print the status
|
||||
Serial.print(currentGeofenceState.status);
|
||||
|
||||
Serial.print(F(". numFences is: ")); // Print the numFences
|
||||
Serial.print(currentGeofenceState.numFences);
|
||||
|
||||
Serial.print(F(". combState is: ")); // Print the combined state
|
||||
Serial.print(currentGeofenceState.combState);
|
||||
|
||||
if (currentGeofenceState.combState == 0)
|
||||
{
|
||||
Serial.print(F(" = Unknown"));
|
||||
digitalWrite(LED, LOW);
|
||||
}
|
||||
if (currentGeofenceState.combState == 1)
|
||||
{
|
||||
Serial.print(F(" = Inside"));
|
||||
digitalWrite(LED, HIGH);
|
||||
}
|
||||
else if (currentGeofenceState.combState == 2)
|
||||
{
|
||||
Serial.print(F(" = Outside"));
|
||||
digitalWrite(LED, LOW);
|
||||
}
|
||||
|
||||
Serial.print(F(". The individual states are: ")); // Print the state of each geofence
|
||||
for(int i = 0; i < currentGeofenceState.numFences; i++)
|
||||
{
|
||||
if (i > 0) Serial.print(F(","));
|
||||
Serial.print(currentGeofenceState.states[i]);
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
Power Save Mode
|
||||
By: Paul Clark (PaulZC)
|
||||
Date: April 22nd, 2020
|
||||
|
||||
Based extensively on Example3_GetPosition
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: January 3rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to put the u-blox module into power save mode and then
|
||||
query its lat/long/altitude. We also turn off the NMEA output on the I2C port.
|
||||
This decreases the amount of I2C traffic dramatically.
|
||||
|
||||
** When it is able to ** the module will reduce its current draw.
|
||||
For the ZOE-M8Q with a passive antenna, you should see the current drop
|
||||
from (approx.) 25-28mA to (approx.) 9mA when power save mode kicks in.
|
||||
|
||||
Note: this will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported
|
||||
|
||||
Note: Long/lat are large numbers because they are * 10^7. To convert lat/long
|
||||
to something google maps understands simply divide the numbers by 10,000,000. We
|
||||
do this so that we don't have to use floating point numbers.
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial)
|
||||
; //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
//myGNSS.saveConfiguration(); //Optional: Uncomment this line to save the current settings to flash and BBR
|
||||
|
||||
Serial.println("Power save example.");
|
||||
Serial.println("1) Enable power saving");
|
||||
Serial.println("2) Disable power saving");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (Serial.available())
|
||||
{
|
||||
byte incoming = Serial.read();
|
||||
|
||||
if (incoming == '1')
|
||||
{
|
||||
// Put the GNSS into power save mode
|
||||
// (If you want to disable power save mode, call myGNSS.powerSaveMode(false) instead)
|
||||
// This will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported
|
||||
if (myGNSS.powerSaveMode()) // Defaults to true
|
||||
Serial.println(F("Power Save Mode enabled."));
|
||||
else
|
||||
Serial.println(F("*** Power Save Mode FAILED ***"));
|
||||
}
|
||||
else if (incoming == '2')
|
||||
{
|
||||
//Go to normal power mode (not power saving mode)
|
||||
if (myGNSS.powerSaveMode(false))
|
||||
Serial.println(F("Power Save Mode disabled."));
|
||||
else
|
||||
Serial.println(F("*** Power Save Disable FAILED ***"));
|
||||
}
|
||||
|
||||
// Read and print the new low power mode
|
||||
uint8_t lowPowerMode = myGNSS.getPowerSaveMode();
|
||||
if (lowPowerMode == 255)
|
||||
{
|
||||
Serial.println(F("*** getPowerSaveMode FAILED ***"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F("The low power mode is: "));
|
||||
Serial.print(lowPowerMode);
|
||||
if (lowPowerMode == 0)
|
||||
{
|
||||
Serial.println(F(" (Continuous)"));
|
||||
}
|
||||
else if (lowPowerMode == 1)
|
||||
{
|
||||
Serial.println(F(" (Power Save)"));
|
||||
}
|
||||
else if (lowPowerMode == 4)
|
||||
{
|
||||
Serial.println(F(" (Continuous)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F(" (Unknown!)"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Query module every 10 seconds so it is easier to monitor the current draw
|
||||
if (millis() - lastTime > 10000)
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
byte fixType = myGNSS.getFixType(); // Get the fix type
|
||||
Serial.print(F("Fix: "));
|
||||
Serial.print(fixType);
|
||||
if (fixType == 0)
|
||||
Serial.print(F("(No fix)"));
|
||||
else if (fixType == 1)
|
||||
Serial.print(F("(Dead reckoning)"));
|
||||
else if (fixType == 2)
|
||||
Serial.print(F("(2D)"));
|
||||
else if (fixType == 3)
|
||||
Serial.print(F("(3D)"));
|
||||
else if (fixType == 4)
|
||||
Serial.print(F("(GNSS + Dead reckoning)"));
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F(" Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
Set Dynamic Model
|
||||
By: Paul Clark (PaulZC)
|
||||
Date: April 22nd, 2020
|
||||
|
||||
Based extensively on Example3_GetPosition
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: January 3rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to change the u-blox module's dynamic platform model and then
|
||||
query its lat/long/altitude. We also turn off the NMEA output on the I2C port.
|
||||
This decreases the amount of I2C traffic dramatically.
|
||||
|
||||
Possible values for the dynamic model are: PORTABLE, STATIONARY, PEDESTRIAN, AUTOMOTIVE,
|
||||
SEA, AIRBORNE1g, AIRBORNE2g, AIRBORNE4g, WRIST, BIKE
|
||||
|
||||
Note: Long/lat are large numbers because they are * 10^7. To convert lat/long
|
||||
to something google maps understands simply divide the numbers by 10,000,000. We
|
||||
do this so that we don't have to use floating point numbers.
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial)
|
||||
; //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
|
||||
// If we are going to change the dynamic platform model, let's do it here.
|
||||
// Possible values are:
|
||||
// PORTABLE, STATIONARY, PEDESTRIAN, AUTOMOTIVE, SEA, AIRBORNE1g, AIRBORNE2g, AIRBORNE4g, WRIST, BIKE
|
||||
|
||||
if (myGNSS.setDynamicModel(DYN_MODEL_PORTABLE) == false) // Set the dynamic model to PORTABLE
|
||||
{
|
||||
Serial.println(F("*** Warning: setDynamicModel failed ***"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Dynamic platform model changed successfully!"));
|
||||
}
|
||||
|
||||
// Let's read the new dynamic model to see if it worked
|
||||
uint8_t newDynamicModel = myGNSS.getDynamicModel();
|
||||
if (newDynamicModel == DYN_MODEL_UNKNOWN)
|
||||
{
|
||||
Serial.println(F("*** Warning: getDynamicModel failed ***"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F("The new dynamic model is: "));
|
||||
Serial.println(newDynamicModel);
|
||||
}
|
||||
|
||||
//myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_NAVCONF); //Uncomment this line to save only the NAV settings to flash and BBR
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Query module only every second. Doing it more often will just cause I2C traffic.
|
||||
//The module only responds when a new position is available
|
||||
if (millis() - lastTime > 1000)
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
Read NMEA sentences over I2C using u-blox module SAM-M8Q, NEO-M8P, ZED-F9P, etc
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: August 22nd, 2018
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example reads the NMEA setences from the u-blox module over I2c and outputs
|
||||
them to the serial port
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false)
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the I2C port to output both NMEA and UBX messages
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
//This will pipe all NMEA sentences to the serial port so we can see them
|
||||
myGNSS.setNMEAOutputPort(Serial);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.
|
||||
|
||||
delay(250); //Don't pound too hard on the I2C bus
|
||||
}
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
Send Custom Command
|
||||
By: Paul Clark (PaulZC)
|
||||
Date: April 20th, 2020
|
||||
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how you can create and send a custom UBX packet
|
||||
using the SparkFun u-blox library.
|
||||
|
||||
Previously it was possible to create and send a custom packet
|
||||
through the library but it would always appear to timeout as
|
||||
some of the internal functions referred to the internal private
|
||||
struct packetCfg.
|
||||
The most recent version of the library allows sendCommand to
|
||||
use a custom packet as if it were packetCfg and so:
|
||||
- sendCommand will return a sfe_ublox_status_e enum as if
|
||||
it had been called from within the library
|
||||
- the custom packet will be updated with data returned by the module
|
||||
(previously this was not possible from outside the library)
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#define NAV_RATE 5 // The new navigation rate in Hz (measurements per second)
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200); // You may need to increase this for high navigation rates!
|
||||
while (!Serial)
|
||||
; //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
|
||||
// Let's configure the module's navigation rate as if we were using setNavigationFrequency
|
||||
|
||||
// Let's create our custom packet
|
||||
uint8_t customPayload[MAX_PAYLOAD_SIZE]; // This array holds the payload data bytes. MAX_PAYLOAD_SIZE defaults to 256. The CFG_RATE payload is only 6 bytes!
|
||||
|
||||
// setPacketCfgPayloadSize tells the library how many bytes our customPayload can hold.
|
||||
// It is more memory-efficient to call setPacketCfgPayloadSize before .begin (to avoid creating a new buffer, copying across
|
||||
// the contents of the old buffer and then deleting the old buffer). But let's call it here just to prove that we can.
|
||||
myGNSS.setPacketCfgPayloadSize(MAX_PAYLOAD_SIZE);
|
||||
|
||||
// The next line creates and initialises the packet information which wraps around the payload
|
||||
ubxPacket customCfg = {0, 0, 0, 0, 0, customPayload, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED};
|
||||
|
||||
// The structure of ubxPacket is:
|
||||
// uint8_t cls : The message Class
|
||||
// uint8_t id : The message ID
|
||||
// uint16_t len : Length of the payload. Does not include cls, id, or checksum bytes
|
||||
// uint16_t counter : Keeps track of number of overall bytes received. Some responses are larger than 255 bytes.
|
||||
// uint16_t startingSpot : The counter value needed to go past before we begin recording into payload array
|
||||
// uint8_t *payload : The payload
|
||||
// uint8_t checksumA : Given to us by the module. Checked against the rolling calculated A/B checksums.
|
||||
// uint8_t checksumB
|
||||
// sfe_ublox_packet_validity_e valid : Goes from NOT_DEFINED to VALID or NOT_VALID when checksum is checked
|
||||
// sfe_ublox_packet_validity_e classAndIDmatch : Goes from NOT_DEFINED to VALID or NOT_VALID when the Class and ID match the requestedClass and requestedID
|
||||
|
||||
// sendCommand will return:
|
||||
// SFE_UBLOX_STATUS_DATA_RECEIVED if the data we requested was read / polled successfully
|
||||
// SFE_UBLOX_STATUS_DATA_SENT if the data we sent was writted successfully (ACK'd)
|
||||
// Other values indicate errors. Please see the sfe_ublox_status_e enum for further details.
|
||||
|
||||
// Referring to the u-blox M8 Receiver Description and Protocol Specification we see that
|
||||
// the navigation rate is configured using the UBX-CFG-RATE message. So let's load our
|
||||
// custom packet with the correct information so we can read (poll / get) the current settings.
|
||||
|
||||
customCfg.cls = UBX_CLASS_CFG; // This is the message Class
|
||||
customCfg.id = UBX_CFG_RATE; // This is the message ID
|
||||
customCfg.len = 0; // Setting the len (length) to zero let's us poll the current settings
|
||||
customCfg.startingSpot = 0; // Always set the startingSpot to zero (unless you really know what you are doing)
|
||||
|
||||
// We also need to tell sendCommand how long it should wait for a reply
|
||||
uint16_t maxWait = 250; // Wait for up to 250ms (Serial may need a lot longer e.g. 1100)
|
||||
|
||||
// Now let's read the current navigation rate. The results will be loaded into customCfg.
|
||||
if (myGNSS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK
|
||||
{
|
||||
Serial.println(F("sendCommand (poll / get) failed! Freezing..."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
// Referring to the message definition for UBX-CFG-RATE we see that the measurement rate
|
||||
// is stored in payload bytes 0 and 1 as a uint16_t in LSB-first (little endian) format
|
||||
|
||||
uint16_t rate = (customPayload[1] << 8) | customPayload[0]; // Extract the current rate (ms)
|
||||
float f_rate = 1000.0 / ((float)rate); // Convert the navigation rate to Hz (measurements per second)
|
||||
|
||||
// Print the current measurement rate
|
||||
Serial.print(F("The current measurement rate is: "));
|
||||
Serial.println(f_rate, 1);
|
||||
|
||||
// Let's change it
|
||||
rate = 1000 / NAV_RATE; // Load the new value into rate
|
||||
customPayload[0] = rate & 0xFF; // Store it in the payload
|
||||
customPayload[1] = rate >> 8;
|
||||
|
||||
// Print the new measurement rate
|
||||
Serial.print(F("The new measurement rate will be: "));
|
||||
Serial.println(NAV_RATE);
|
||||
|
||||
// We don't need to update customCfg.len as it will have been set to 6
|
||||
// when sendCommand read the data
|
||||
|
||||
// Now we write the custom packet back again to change the setting
|
||||
if (myGNSS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) // This time we are only expecting an ACK
|
||||
{
|
||||
Serial.println(F("sendCommand (set) failed! Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Navigation rate updated. Here we go..."));
|
||||
}
|
||||
|
||||
myGNSS.setAutoPVT(true); // Enable AutoPVT. The module will generate measurements automatically without being polled.
|
||||
|
||||
//myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_NAVCONF); //Uncomment this line to save only the NAV settings to flash and BBR
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Query the module as fast as possible
|
||||
int32_t latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
int32_t longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Lon: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
int32_t altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
uint16_t milliseconds = myGNSS.getMillisecond();
|
||||
Serial.print(F(" Milliseconds: "));
|
||||
Serial.print(milliseconds);
|
||||
Serial.println();
|
||||
}
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
Module Info - extracts and prints the full module information from UBX_MON_VER
|
||||
using a custom command.
|
||||
By: @mayopan
|
||||
Date: May 9th, 2020
|
||||
|
||||
Based on:
|
||||
Send Custom Command
|
||||
By: Paul Clark (PaulZC)
|
||||
Date: April 20th, 2020
|
||||
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
Previously it was possible to create and send a custom packet
|
||||
through the library but it would always appear to timeout as
|
||||
some of the internal functions referred to the internal private
|
||||
struct packetCfg.
|
||||
The most recent version of the library allows sendCommand to
|
||||
use a custom packet as if it were packetCfg and so:
|
||||
- sendCommand will return a sfe_ublox_status_e enum as if
|
||||
it had been called from within the library
|
||||
- the custom packet will be updated with data returned by the module
|
||||
(previously this was not possible from outside the library)
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#define MAX_PAYLOAD_SIZE 384 // Override MAX_PAYLOAD_SIZE for getModuleInfo which can return up to 348 bytes
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
|
||||
// Extend the class for getModuleInfo
|
||||
class SFE_UBLOX_GPS_ADD : public SFE_UBLOX_GNSS
|
||||
{
|
||||
public:
|
||||
bool getModuleInfo(uint16_t maxWait = 1100); //Queries module, texts
|
||||
|
||||
struct minfoStructure // Structure to hold the module info (uses 341 bytes of RAM)
|
||||
{
|
||||
char swVersion[30];
|
||||
char hwVersion[10];
|
||||
uint8_t extensionNo = 0;
|
||||
char extension[10][30];
|
||||
} minfo;
|
||||
};
|
||||
|
||||
SFE_UBLOX_GPS_ADD myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200); // You may need to increase this for high navigation rates!
|
||||
while (!Serial)
|
||||
; //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages
|
||||
|
||||
// setPacketCfgPayloadSize tells the library how many bytes our customPayload can hold.
|
||||
// If we call it after the .begin, the library will attempt to resize the existing 256 byte payload buffer
|
||||
// by creating a new buffer, copying across the contents of the old buffer, and then delete the old buffer.
|
||||
// This uses a lot of RAM and causes the code to fail on the ATmega328P. (We are also allocating another 341 bytes for minfo.)
|
||||
// To keep the code ATmega328P compliant - don't call setPacketCfgPayloadSize after .begin. Call it here instead.
|
||||
myGNSS.setPacketCfgPayloadSize(MAX_PAYLOAD_SIZE);
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
|
||||
Serial.print(F("Polling module info"));
|
||||
if (myGNSS.getModuleInfo(1100) == false) // Try to get the module info
|
||||
{
|
||||
Serial.print(F("getModuleInfo failed! Freezing..."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println(F("Module Info : "));
|
||||
Serial.print(F("Soft version: "));
|
||||
Serial.println(myGNSS.minfo.swVersion);
|
||||
Serial.print(F("Hard version: "));
|
||||
Serial.println(myGNSS.minfo.hwVersion);
|
||||
Serial.print(F("Extensions:"));
|
||||
Serial.println(myGNSS.minfo.extensionNo);
|
||||
for (int i = 0; i < myGNSS.minfo.extensionNo; i++)
|
||||
{
|
||||
Serial.print(" ");
|
||||
Serial.println(myGNSS.minfo.extension[i]);
|
||||
}
|
||||
Serial.println();
|
||||
Serial.println(F("Done!"));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
bool SFE_UBLOX_GPS_ADD::getModuleInfo(uint16_t maxWait)
|
||||
{
|
||||
myGNSS.minfo.hwVersion[0] = 0;
|
||||
myGNSS.minfo.swVersion[0] = 0;
|
||||
for (int i = 0; i < 10; i++)
|
||||
myGNSS.minfo.extension[i][0] = 0;
|
||||
myGNSS.minfo.extensionNo = 0;
|
||||
|
||||
// Let's create our custom packet
|
||||
uint8_t customPayload[MAX_PAYLOAD_SIZE]; // This array holds the payload data bytes
|
||||
|
||||
// setPacketCfgPayloadSize tells the library how many bytes our customPayload can hold.
|
||||
// If we call it here, after the .begin, the library will attempt to resize the existing 256 byte payload buffer
|
||||
// by creating a new buffer, copying across the contents of the old buffer, and then delete the old buffer.
|
||||
// This uses a lot of RAM and causes the code to fail on the ATmega328P. (We are also allocating another 341 bytes for minfo.)
|
||||
// To keep the code ATmega328P compliant - don't call setPacketCfgPayloadSize here. Call it before .begin instead.
|
||||
//myGNSS.setPacketCfgPayloadSize(MAX_PAYLOAD_SIZE);
|
||||
|
||||
// The next line creates and initialises the packet information which wraps around the payload
|
||||
ubxPacket customCfg = {0, 0, 0, 0, 0, customPayload, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED};
|
||||
|
||||
// The structure of ubxPacket is:
|
||||
// uint8_t cls : The message Class
|
||||
// uint8_t id : The message ID
|
||||
// uint16_t len : Length of the payload. Does not include cls, id, or checksum bytes
|
||||
// uint16_t counter : Keeps track of number of overall bytes received. Some responses are larger than 255 bytes.
|
||||
// uint16_t startingSpot : The counter value needed to go past before we begin recording into payload array
|
||||
// uint8_t *payload : The payload
|
||||
// uint8_t checksumA : Given to us by the module. Checked against the rolling calculated A/B checksums.
|
||||
// uint8_t checksumB
|
||||
// sfe_ublox_packet_validity_e valid : Goes from NOT_DEFINED to VALID or NOT_VALID when checksum is checked
|
||||
// sfe_ublox_packet_validity_e classAndIDmatch : Goes from NOT_DEFINED to VALID or NOT_VALID when the Class and ID match the requestedClass and requestedID
|
||||
|
||||
// sendCommand will return:
|
||||
// SFE_UBLOX_STATUS_DATA_RECEIVED if the data we requested was read / polled successfully
|
||||
// SFE_UBLOX_STATUS_DATA_SENT if the data we sent was writted successfully (ACK'd)
|
||||
// Other values indicate errors. Please see the sfe_ublox_status_e enum for further details.
|
||||
|
||||
// Referring to the u-blox M8 Receiver Description and Protocol Specification we see that
|
||||
// the module information can be read using the UBX-MON-VER message. So let's load our
|
||||
// custom packet with the correct information so we can read (poll / get) the module information.
|
||||
|
||||
customCfg.cls = UBX_CLASS_MON; // This is the message Class
|
||||
customCfg.id = UBX_MON_VER; // This is the message ID
|
||||
customCfg.len = 0; // Setting the len (length) to zero let's us poll the current settings
|
||||
customCfg.startingSpot = 0; // Always set the startingSpot to zero (unless you really know what you are doing)
|
||||
|
||||
// Now let's send the command. The module info is returned in customPayload
|
||||
|
||||
if (sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED)
|
||||
return (false); //If command send fails then bail
|
||||
|
||||
// Now let's extract the module info from customPayload
|
||||
|
||||
uint16_t position = 0;
|
||||
for (int i = 0; i < 30; i++)
|
||||
{
|
||||
minfo.swVersion[i] = customPayload[position];
|
||||
position++;
|
||||
}
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
minfo.hwVersion[i] = customPayload[position];
|
||||
position++;
|
||||
}
|
||||
|
||||
while (customCfg.len >= position + 30)
|
||||
{
|
||||
for (int i = 0; i < 30; i++)
|
||||
{
|
||||
minfo.extension[minfo.extensionNo][i] = customPayload[position];
|
||||
position++;
|
||||
}
|
||||
minfo.extensionNo++;
|
||||
if (minfo.extensionNo > 9)
|
||||
break;
|
||||
}
|
||||
|
||||
return (true); //Success!
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
Powering off a ublox GNSS module
|
||||
By: bjorn
|
||||
unsurv.org
|
||||
Date: July 20th, 2020
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows you how to turn off the ublox module to lower the power consumption.
|
||||
There are two functions: one just specifies a duration in milliseconds the other also specifies a pin on the GNSS device to wake it up with.
|
||||
By driving a voltage from LOW to HIGH or HIGH to LOW on the chosen module pin you wake the device back up.
|
||||
Note: Doing so on the INT0 pin when using the regular powerOff(durationInMs) function will wake the device anyway. (tested on SAM-M8Q)
|
||||
Note: While powered off, you should not query the device for data or it might wake up. This can be used to wake the device but is not recommended.
|
||||
Works best when also putting your microcontroller to sleep.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard.
|
||||
To force the device to wake up you need to connect to a pin (for example INT0) seperately on the module.
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
// define a digital pin capable of driving HIGH and LOW
|
||||
#define WAKEUP_PIN 5
|
||||
|
||||
// Possible GNSS interrupt pins for powerOffWithInterrupt are:
|
||||
// VAL_RXM_PMREQ_WAKEUPSOURCE_UARTRX = uartrx
|
||||
// VAL_RXM_PMREQ_WAKEUPSOURCE_EXTINT0 = extint0 (default)
|
||||
// VAL_RXM_PMREQ_WAKEUPSOURCE_EXTINT1 = extint1
|
||||
// VAL_RXM_PMREQ_WAKEUPSOURCE_SPICS = spics
|
||||
// These values can be or'd (|) together to enable interrupts on multiple pins
|
||||
|
||||
void wakeUp() {
|
||||
|
||||
Serial.print("-- waking up module via pin " + String(WAKEUP_PIN));
|
||||
Serial.println(" on your microcontroller --");
|
||||
|
||||
digitalWrite(WAKEUP_PIN, LOW);
|
||||
delay(1000);
|
||||
digitalWrite(WAKEUP_PIN, HIGH);
|
||||
delay(1000);
|
||||
digitalWrite(WAKEUP_PIN, LOW);
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
|
||||
pinMode(WAKEUP_PIN, OUTPUT);
|
||||
digitalWrite(WAKEUP_PIN, LOW);
|
||||
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Enable debug messages
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
// Powering off for 20s, you should see the power consumption drop.
|
||||
Serial.println("-- Powering off module for 20s --");
|
||||
|
||||
myGNSS.powerOff(20000);
|
||||
//myGNSS.powerOffWithInterrupt(20000, VAL_RXM_PMREQ_WAKEUPSOURCE_EXTINT0);
|
||||
|
||||
delay(10000);
|
||||
|
||||
// After 10 seconds wake the device via the specified pin on your microcontroller and module.
|
||||
wakeUp();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
//Do nothing
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
Time Pulse Parameters - Bullet Time (https://en.wikipedia.org/wiki/Bullet_time)
|
||||
By: Paul Clark (PaulZC)
|
||||
Date: January 13th, 2021
|
||||
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to change the time pulse parameters and configure the TIMEPULSE (PPS)
|
||||
pin to produce a pulse once per second but with an adjustable delay. You could use this to
|
||||
trigger multiple cameras and replicate the "bullet time" effect.
|
||||
|
||||
The SparkFun GPS-RTK-SMA Breakout - ZED-F9P (Qwiic) (https://www.sparkfun.com/products/16481)
|
||||
has solder pads which will let you connect an SMA connector to the TIMEPULSE signal. Need an
|
||||
accurate timelapse camera shutter signal? This is the product for you!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include "SparkFun_u-blox_GNSS_Arduino_Library.h" //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial)
|
||||
; //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
|
||||
// Create storage for the time pulse parameters
|
||||
UBX_CFG_TP5_data_t timePulseParameters;
|
||||
|
||||
// Get the time pulse parameters
|
||||
if (myGNSS.getTimePulseParameters(&timePulseParameters) == false)
|
||||
{
|
||||
Serial.println(F("getTimePulseParameters failed! Freezing..."));
|
||||
while (1) ; // Do nothing more
|
||||
}
|
||||
|
||||
// Print the CFG TP5 version
|
||||
Serial.print(F("UBX_CFG_TP5 version: "));
|
||||
Serial.println(timePulseParameters.version);
|
||||
|
||||
timePulseParameters.tpIdx = 0; // Select the TIMEPULSE pin
|
||||
//timePulseParameters.tpIdx = 1; // Or we could select the TIMEPULSE2 pin instead, if the module has one
|
||||
|
||||
// We can configure the time pulse pin to produce a defined frequency or period
|
||||
// Here is how to set the period:
|
||||
|
||||
// Let's say that we want our pulse-per-second to be as accurate as possible. So, let's tell the module
|
||||
// to generate no signal while it is _locking_ to GNSS time. We want the signal to start only when the module is
|
||||
// _locked_ to GNSS time.
|
||||
timePulseParameters.freqPeriod = 0; // Set the frequency/period to zero
|
||||
timePulseParameters.pulseLenRatio = 0; // Set the pulse ratio to zero
|
||||
|
||||
// When the module is _locked_ to GNSS time, make it generate a 0.1 second pulse once per second
|
||||
timePulseParameters.freqPeriodLock = 1000000; // Set the period to 1,000,000 us
|
||||
timePulseParameters.pulseLenRatioLock = 100000; // Set the pulse length to 0.1s (100,000 us)
|
||||
timePulseParameters.flags.bits.polarity = 1; // Set the polarity to "1" (high for 0.1s, low for 0.9s, rising edge at top of second)
|
||||
|
||||
// We can use userConfigDelay to delay the pulse for each camera. The delay needs to be negative for this example.
|
||||
// We can delay the pulse by +/- 2^31 nanoseconds (+/- 2.147 seconds)
|
||||
//timePulseParameters.userConfigDelay = 0; // Camera 1: delay the pulse by 0ns
|
||||
//timePulseParameters.userConfigDelay = -100000000; // Camera 2: delay the pulse by 0.1s (100,000,000 ns)
|
||||
//timePulseParameters.userConfigDelay = -200000000; // Camera 3: delay the pulse by 0.2s (200,000,000 ns)
|
||||
timePulseParameters.userConfigDelay = -300000000; // Camera 4: delay the pulse by 0.3s (300,000,000 ns)
|
||||
//timePulseParameters.userConfigDelay = -400000000; // Camera 5: delay the pulse by 0.4s (400,000,000 ns)
|
||||
//timePulseParameters.userConfigDelay = -500000000; // Camera 6: delay the pulse by 0.5s (500,000,000 ns)
|
||||
//timePulseParameters.userConfigDelay = -600000000; // Camera 7: delay the pulse by 0.6s (600,000,000 ns)
|
||||
//timePulseParameters.userConfigDelay = -700000000; // Camera 8: delay the pulse by 0.7s (700,000,000 ns)
|
||||
//timePulseParameters.userConfigDelay = -800000000; // Camera 9: delay the pulse by 0.8s (800,000,000 ns)
|
||||
//timePulseParameters.userConfigDelay = -900000000; // Camera 10: delay the pulse by 0.9s (900,000,000 ns)
|
||||
|
||||
timePulseParameters.flags.bits.active = 1; // Make sure the active flag is set to enable the time pulse. (Set to 0 to disable.)
|
||||
timePulseParameters.flags.bits.lockedOtherSet = 1; // Tell the module to use freqPeriod while locking and freqPeriodLock when locked to GNSS time
|
||||
timePulseParameters.flags.bits.isFreq = 0; // Tell the module that we want to set the period (not the frequency)
|
||||
timePulseParameters.flags.bits.isLength = 1; // Tell the module that pulseLenRatio is a length (in us) - not a duty cycle
|
||||
|
||||
// Now set the time pulse parameters
|
||||
if (myGNSS.setTimePulseParameters(&timePulseParameters) == false)
|
||||
{
|
||||
Serial.println(F("setTimePulseParameters failed!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Success!"));
|
||||
}
|
||||
|
||||
// Finally, save the time pulse parameters in battery-backed memory so the pulse will automatically restart at power on
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_NAVCONF); // Save the configuration
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Nothing to do here
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
Time Pulse Parameters - Frequency
|
||||
By: Paul Clark (PaulZC)
|
||||
Date: January 13th, 2021
|
||||
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to change the time pulse parameters and configure the TIMEPULSE (PPS)
|
||||
pin to produce a 1kHz squarewave
|
||||
|
||||
The SparkFun GPS-RTK-SMA Breakout - ZED-F9P (Qwiic) (https://www.sparkfun.com/products/16481)
|
||||
has solder pads which will let you connect an SMA connector to the TIMEPULSE signal. Need an
|
||||
accurate frequency or clock source for your latest project? This is the product for you!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include "SparkFun_u-blox_GNSS_Arduino_Library.h" //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial)
|
||||
; //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
|
||||
// Create storage for the time pulse parameters
|
||||
UBX_CFG_TP5_data_t timePulseParameters;
|
||||
|
||||
// Get the time pulse parameters
|
||||
if (myGNSS.getTimePulseParameters(&timePulseParameters) == false)
|
||||
{
|
||||
Serial.println(F("getTimePulseParameters failed! Freezing..."));
|
||||
while (1) ; // Do nothing more
|
||||
}
|
||||
|
||||
// Print the CFG TP5 version
|
||||
Serial.print(F("UBX_CFG_TP5 version: "));
|
||||
Serial.println(timePulseParameters.version);
|
||||
|
||||
timePulseParameters.tpIdx = 0; // Select the TIMEPULSE pin
|
||||
//timePulseParameters.tpIdx = 1; // Or we could select the TIMEPULSE2 pin instead, if the module has one
|
||||
|
||||
// We can configure the time pulse pin to produce a defined frequency or period
|
||||
// Here is how to set the frequency:
|
||||
|
||||
// While the module is _locking_ to GNSS time, make it generate 2kHz
|
||||
timePulseParameters.freqPeriod = 2000; // Set the frequency/period to 2000Hz
|
||||
timePulseParameters.pulseLenRatio = 0x55555555; // Set the pulse ratio to 1/3 * 2^32 to produce 33:67 mark:space
|
||||
|
||||
// When the module is _locked_ to GNSS time, make it generate 1kHz
|
||||
timePulseParameters.freqPeriodLock = 1000; // Set the frequency/period to 1000Hz
|
||||
timePulseParameters.pulseLenRatioLock = 0x80000000; // Set the pulse ratio to 1/2 * 2^32 to produce 50:50 mark:space
|
||||
|
||||
timePulseParameters.flags.bits.active = 1; // Make sure the active flag is set to enable the time pulse. (Set to 0 to disable.)
|
||||
timePulseParameters.flags.bits.lockedOtherSet = 1; // Tell the module to use freqPeriod while locking and freqPeriodLock when locked to GNSS time
|
||||
timePulseParameters.flags.bits.isFreq = 1; // Tell the module that we want to set the frequency (not the period)
|
||||
timePulseParameters.flags.bits.isLength = 0; // Tell the module that pulseLenRatio is a ratio / duty cycle (* 2^-32) - not a length (in us)
|
||||
timePulseParameters.flags.bits.polarity = 1; // Tell the module that we want the rising edge at the top of second. (Set to 0 for falling edge.)
|
||||
|
||||
// Now set the time pulse parameters
|
||||
if (myGNSS.setTimePulseParameters(&timePulseParameters) == false)
|
||||
{
|
||||
Serial.println(F("setTimePulseParameters failed!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Success!"));
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Nothing to do here
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
Time Pulse Parameters - Period
|
||||
By: Paul Clark (PaulZC)
|
||||
Date: January 13th, 2021
|
||||
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to change the time pulse parameters and configure the TIMEPULSE (PPS)
|
||||
pin to produce a 1 second pulse every 30 seconds. What's really cool is that if you run this
|
||||
example on two GNSS boards, the pulses are precisely synchronised!
|
||||
|
||||
The SparkFun GPS-RTK-SMA Breakout - ZED-F9P (Qwiic) (https://www.sparkfun.com/products/16481)
|
||||
has solder pads which will let you connect an SMA connector to the TIMEPULSE signal. Need an
|
||||
accurate timelapse camera shutter signal? This is the product for you!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include "SparkFun_u-blox_GNSS_Arduino_Library.h" //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial)
|
||||
; //Wait for user to open terminal
|
||||
Serial.println(F("SparkFun u-blox Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
|
||||
// Create storage for the time pulse parameters
|
||||
UBX_CFG_TP5_data_t timePulseParameters;
|
||||
|
||||
// Get the time pulse parameters
|
||||
if (myGNSS.getTimePulseParameters(&timePulseParameters) == false)
|
||||
{
|
||||
Serial.println(F("getTimePulseParameters failed! Freezing..."));
|
||||
while (1) ; // Do nothing more
|
||||
}
|
||||
|
||||
// Print the CFG TP5 version
|
||||
Serial.print(F("UBX_CFG_TP5 version: "));
|
||||
Serial.println(timePulseParameters.version);
|
||||
|
||||
timePulseParameters.tpIdx = 0; // Select the TIMEPULSE pin
|
||||
//timePulseParameters.tpIdx = 1; // Or we could select the TIMEPULSE2 pin instead, if the module has one
|
||||
|
||||
// We can configure the time pulse pin to produce a defined frequency or period
|
||||
// Here is how to set the period:
|
||||
|
||||
// Let's say that we want our 1 pulse every 30 seconds to be as accurate as possible. So, let's tell the module
|
||||
// to generate no signal while it is _locking_ to GNSS time. We want the signal to start only when the module is
|
||||
// _locked_ to GNSS time.
|
||||
timePulseParameters.freqPeriod = 0; // Set the frequency/period to zero
|
||||
timePulseParameters.pulseLenRatio = 0; // Set the pulse ratio to zero
|
||||
|
||||
// When the module is _locked_ to GNSS time, make it generate a 1 second pulse every 30 seconds
|
||||
// (Although the period can be a maximum of 2^32 microseconds (over one hour), the upper limit appears to be around 33 seconds)
|
||||
timePulseParameters.freqPeriodLock = 30000000; // Set the period to 30,000,000 us
|
||||
timePulseParameters.pulseLenRatioLock = 1000000; // Set the pulse length to 1,000,000 us
|
||||
|
||||
timePulseParameters.flags.bits.active = 1; // Make sure the active flag is set to enable the time pulse. (Set to 0 to disable.)
|
||||
timePulseParameters.flags.bits.lockedOtherSet = 1; // Tell the module to use freqPeriod while locking and freqPeriodLock when locked to GNSS time
|
||||
timePulseParameters.flags.bits.isFreq = 0; // Tell the module that we want to set the period (not the frequency)
|
||||
timePulseParameters.flags.bits.isLength = 1; // Tell the module that pulseLenRatio is a length (in us) - not a duty cycle
|
||||
timePulseParameters.flags.bits.polarity = 1; // Tell the module that we want the rising edge at the top of second. (Set to 0 for falling edge.)
|
||||
|
||||
// Now set the time pulse parameters
|
||||
if (myGNSS.setTimePulseParameters(&timePulseParameters) == false)
|
||||
{
|
||||
Serial.println(F("setTimePulseParameters failed!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Success!"));
|
||||
}
|
||||
|
||||
// Finally, save the time pulse parameters in battery-backed memory so the pulse will automatically restart at power on
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_NAVCONF); // Save the configuration
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Nothing to do here
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
Getting Unix Epoch Time and micros using u-blox commands
|
||||
By: UT2UH
|
||||
Date: March 31th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to query a u-blox module for the current time and date as Unix Epoch uint32_t type to avoid time.h dependency.
|
||||
We also turn off the NMEA output on the I2C port. This decreases the amount of I2C traffic dramatically.
|
||||
|
||||
Note: this example works best on modules like the ZED_F9P. Modules like the ZOE_M8Q do not support confirmedTime.
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial)
|
||||
; //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
// Uncomment the next line if you need to completely reset your module
|
||||
//myGNSS.factoryDefault(); delay(5000); // Reset everything and wait while the module restarts
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
|
||||
|
||||
Serial.println(F("Compare Unix Epoch given with reference one from https://www.epochconverter.com/"));
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Query module only every second. Doing it more often will just cause I2C traffic.
|
||||
//The module only responds when a new position is available
|
||||
if (millis() - lastTime > 1000)
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
// getUnixEpoch marks the PVT data as stale so you will get Unix time and PVT time on alternate seconds
|
||||
|
||||
uint32_t us; //microseconds returned by getUnixEpoch()
|
||||
uint32_t epoch = myGNSS.getUnixEpoch();
|
||||
Serial.print(F("Unix Epoch rounded: "));
|
||||
Serial.print(epoch, DEC);
|
||||
epoch = myGNSS.getUnixEpoch(us);
|
||||
Serial.print(F(" Exact Unix Epoch: "));
|
||||
Serial.print(epoch, DEC);
|
||||
Serial.print(F(" micros: "));
|
||||
Serial.println(us, DEC);
|
||||
|
||||
Serial.print(myGNSS.getYear());
|
||||
Serial.print(F("-"));
|
||||
Serial.print(myGNSS.getMonth());
|
||||
Serial.print(F("-"));
|
||||
Serial.print(myGNSS.getDay());
|
||||
Serial.print(F(" "));
|
||||
Serial.print(myGNSS.getHour());
|
||||
Serial.print(F(":"));
|
||||
Serial.print(myGNSS.getMinute());
|
||||
Serial.print(F(":"));
|
||||
Serial.print(myGNSS.getSecond());
|
||||
|
||||
Serial.print(F(" Time is "));
|
||||
if (myGNSS.getTimeFullyResolved() == false)
|
||||
{
|
||||
Serial.print(F("not fully resolved but "));
|
||||
} else {
|
||||
Serial.print(F("fully resolved and "));
|
||||
}
|
||||
if (myGNSS.getTimeValid() == false)
|
||||
{
|
||||
Serial.print(F("not "));
|
||||
}
|
||||
Serial.print(F("valid "));
|
||||
if (myGNSS.getConfirmedTime() == false)
|
||||
{
|
||||
Serial.print(F("but not "));
|
||||
} else {
|
||||
Serial.print(F("and "));
|
||||
}
|
||||
Serial.print(F("confirmed"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.println(SIV);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
Demonstrate get/setMeasurementRate and get/setNavigationRate
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: March 30th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to slow down the measurement and navigation rates.
|
||||
This should run on any GNSS module but has only been tested on the ZED_F9P and ZOE_M8Q.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
unsigned long lastTime = 0; //Simple local timer. Used to calc the message interval.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
// Uncomment the next line if you need to completely reset your module
|
||||
//myGNSS.factoryDefault(); delay(5000); // Reset everything and wait while the module restarts
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
|
||||
// Begin by printing the current measurement rate and navigation rate
|
||||
|
||||
uint16_t rate = myGNSS.getMeasurementRate(); //Get the measurement rate of this module
|
||||
Serial.print("Current measurement interval (ms): ");
|
||||
Serial.println(rate);
|
||||
|
||||
rate = myGNSS.getNavigationRate(); //Get the navigation rate of this module
|
||||
Serial.print("Current navigation ratio (cycles): ");
|
||||
Serial.println(rate);
|
||||
|
||||
// The measurement rate is the elapsed time between GNSS measurements, which defines the rate
|
||||
// e.g. 100 ms => 10 Hz, 1000 ms => 1 Hz, 10000 ms => 0.1 Hz.
|
||||
// Let's set the measurement rate (interval) to 5 seconds = 5000 milliseconds
|
||||
if (myGNSS.setMeasurementRate(5000) == false)
|
||||
{
|
||||
Serial.println(F("Could not set the measurement rate. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
// setMeasurementRate will set i2cPollingWait to a quarter of the interval
|
||||
// Let's override that so we can poll the module more frequently and avoid timeouts
|
||||
myGNSS.setI2CpollingWait(25); // Set i2cPollingWait to 25ms
|
||||
|
||||
// The navigation rate is the ratio between the number of measurements and the number of navigation solutions
|
||||
// e.g. 5 means five measurements for every navigation solution. Maximum value is 127
|
||||
// Let's set the navigation rate (ratio) to 12 to produce a solution every minute
|
||||
if (myGNSS.setNavigationRate(12) == false)
|
||||
{
|
||||
Serial.println(F("Could not set the navigation rate. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
// Read and print the updated measurement rate and navigation rate
|
||||
|
||||
rate = myGNSS.getMeasurementRate(); //Get the measurement rate of this module
|
||||
Serial.print("New measurement interval (ms): ");
|
||||
Serial.println(rate);
|
||||
|
||||
rate = myGNSS.getNavigationRate(); //Get the navigation rate of this module
|
||||
Serial.print("New navigation ratio (cycles): ");
|
||||
Serial.println(rate);
|
||||
|
||||
lastTime = millis();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// i2cPollingWait will prevent us from thrashing the I2C bus
|
||||
|
||||
if (myGNSS.getPVT()) //Check for new Position, Velocity, Time data. getPVT returns true if new data is available.
|
||||
{
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
|
||||
//Calculate the interval since the last message
|
||||
Serial.print(F(" Interval: "));
|
||||
Serial.print(((float)(millis() - lastTime)) / 1000.0, 2);
|
||||
Serial.print(F("s"));
|
||||
|
||||
Serial.println();
|
||||
|
||||
lastTime = millis(); //Update lastTime
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
Demonstrating how to use "end"
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: April 1st, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to use the end function.
|
||||
End will stop all automatic message processing and free (nearly) all used RAM.
|
||||
The file buffer is deleted (if it exists).
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
|
||||
|
||||
myGNSS.end(); // Call end now just because we can - it won't do much as we haven't used any automatic messages
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Allocate 128 bytes for file storage - this checks that issue #20 has been resolved
|
||||
// Allocating only 128 bytes will let this code run on the ATmega328P
|
||||
// If your processor has plenty of RAM, you can increase this to something useful like 16KB
|
||||
myGNSS.setFileBufferSize(128);
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
Serial.print(F("The file buffer size is: "));
|
||||
Serial.println(myGNSS.getFileBufferSize());
|
||||
|
||||
// Request Position, Velocity, Time
|
||||
// RAM will be allocated for PVT message processing
|
||||
// getPVT will return true is fresh PVT data was received and processed
|
||||
if (myGNSS.getPVT())
|
||||
{
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.println(F(" (mm)"));
|
||||
}
|
||||
|
||||
// Calling end will free the RAM allocated for file storage and PVT processing
|
||||
// Calling end is optional. You can comment the next line if you want to.
|
||||
myGNSS.end();
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
Configuring the GNSS to produce multiple messages at different rates
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: April 1st, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to configure the U-Blox GNSS to output multiple messages at different rates:
|
||||
PVT is output every second;
|
||||
POSECEF is output every five seconds;
|
||||
VELNED is output every ten seconds.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.setMeasurementRate(1000); //Produce a measurement every 1000ms
|
||||
myGNSS.setNavigationRate(1); //Produce a navigation solution every measurement
|
||||
|
||||
myGNSS.setAutoPVTrate(1); //Tell the GNSS to send the PVT solution every measurement
|
||||
myGNSS.setAutoNAVPOSECEFrate(5); //Tell the GNSS to send each POSECEF solution every 5th measurement
|
||||
myGNSS.setAutoNAVVELNEDrate(10); //Tell the GNSS to send each VELNED solution every 10th measurement
|
||||
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Calling getPVT returns true if there actually is a fresh navigation solution available.
|
||||
if (myGNSS.getPVT())
|
||||
{
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.println(F(" (mm)"));
|
||||
}
|
||||
|
||||
// Calling getNAVPOSECEF returns true if there actually is a fresh position solution available.
|
||||
if (myGNSS.getNAVPOSECEF())
|
||||
{
|
||||
Serial.print(F("ecefX: "));
|
||||
Serial.print((float)myGNSS.packetUBXNAVPOSECEF->data.ecefX / 100.0, 2); // convert ecefX to m
|
||||
|
||||
Serial.print(F(" ecefY: "));
|
||||
Serial.print((float)myGNSS.packetUBXNAVPOSECEF->data.ecefY / 100.0, 2); // convert ecefY to m
|
||||
|
||||
Serial.print(F(" ecefZ: "));
|
||||
Serial.print((float)myGNSS.packetUBXNAVPOSECEF->data.ecefZ / 100.0, 2); // convert ecefY to m
|
||||
Serial.println(F(" (m)"));
|
||||
|
||||
myGNSS.flushNAVPOSECEF(); //Mark all the data as read/stale so we get fresh data next time
|
||||
}
|
||||
|
||||
// Calling getNAVVELNED returns true if there actually is fresh velocity data available.
|
||||
if (myGNSS.getNAVVELNED())
|
||||
{
|
||||
Serial.print(F("velN: "));
|
||||
Serial.print((float)myGNSS.packetUBXNAVVELNED->data.velN / 100.0, 2); // convert velN to m/s
|
||||
|
||||
Serial.print(F(" velE: "));
|
||||
Serial.print((float)myGNSS.packetUBXNAVVELNED->data.velE / 100.0, 2); // convert velE to m/s
|
||||
|
||||
Serial.print(F(" velD: "));
|
||||
Serial.print((float)myGNSS.packetUBXNAVVELNED->data.velD / 100.0, 2); // convert velD to m/s
|
||||
Serial.println(F(" (m/s)"));
|
||||
|
||||
myGNSS.flushNAVVELNED(); //Mark all the data as read/stale so we get fresh data next time
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
Getting leap second event info as SNTP Leap Indicator, time to a leap second event and the number of leap seconds since GPS epoch
|
||||
By: UT2UH
|
||||
Date: April 14th, 2021
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to query a u-blox module for the leap second event info to cast to SNTP Leap Indicator enumeration.
|
||||
We also turn off the NMEA output on the I2C port. This decreases the amount of I2C traffic dramatically.
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
typedef enum {
|
||||
LI_NO_WARNING, //Time leaping not scheduled
|
||||
LI_LAST_MINUTE_61_SEC, //Last minute has 61 seconds
|
||||
LI_LAST_MINUTE_59_SEC, //Last minute has 59 seconds
|
||||
LI_ALARM_CONDITION //The NTP server's clock not synchronized
|
||||
} ntp_LI_e;
|
||||
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial)
|
||||
; //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
// Uncomment the next line if you need to completely reset your module
|
||||
//myGNSS.factoryDefault(); delay(5000); // Reset everything and wait while the module restarts
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
|
||||
|
||||
Serial.println(F("Compare Unix Epoch given with reference one from https://www.epochconverter.com/"));
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Query module only every second. Doing it more often will just cause I2C traffic.
|
||||
//The module only responds when a new position is available
|
||||
if (millis() - lastTime > 1000)
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
// getUnixEpoch marks the PVT data as stale so you will get Unix time and PVT time on alternate seconds
|
||||
|
||||
uint32_t us; //microseconds returned by getUnixEpoch()
|
||||
uint32_t epoch = myGNSS.getUnixEpoch();
|
||||
Serial.print(F("Unix Epoch rounded: "));
|
||||
Serial.print(epoch, DEC);
|
||||
epoch = myGNSS.getUnixEpoch(us);
|
||||
Serial.print(F(" Exact Unix Epoch: "));
|
||||
Serial.print(epoch, DEC);
|
||||
Serial.print(F(" micros: "));
|
||||
Serial.println(us, DEC);
|
||||
int32_t timeToLeapSecEvent;
|
||||
ntp_LI_e leapIndicator = (ntp_LI_e)myGNSS.getLeapIndicator(timeToLeapSecEvent);
|
||||
Serial.print(F("NTP LI: "));
|
||||
Serial.print(leapIndicator, DEC);
|
||||
switch (leapIndicator){
|
||||
case LI_NO_WARNING:
|
||||
Serial.print(F(" - No event scheduled"));
|
||||
break;
|
||||
case LI_LAST_MINUTE_61_SEC:
|
||||
Serial.print(F(" - last minute will end at 23:60"));
|
||||
break;
|
||||
case LI_LAST_MINUTE_59_SEC:
|
||||
Serial.print(F(" - last minute will end at 23:58"));
|
||||
break;
|
||||
case LI_ALARM_CONDITION:
|
||||
default:
|
||||
Serial.print(F(" - Unknown (clock not synchronized)"));
|
||||
break;
|
||||
}
|
||||
if (timeToLeapSecEvent < 0)
|
||||
{
|
||||
Serial.print(F(". Time since the last leap second event: "));
|
||||
Serial.println(timeToLeapSecEvent * -1, DEC);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F(". Time to the next leap second event: "));
|
||||
Serial.println(timeToLeapSecEvent, DEC);
|
||||
}
|
||||
|
||||
sfe_ublox_ls_src_e leapSecSource;
|
||||
Serial.print(F("Leap seconds since GPS Epoch (Jan 6th, 1980): "));
|
||||
Serial.print(myGNSS.getCurrentLeapSeconds(leapSecSource), DEC);
|
||||
switch (leapSecSource){
|
||||
case SFE_UBLOX_LS_SRC_DEFAULT:
|
||||
Serial.print(F(" - hardcoded"));
|
||||
break;
|
||||
case SFE_UBLOX_LS_SRC_GLONASS:
|
||||
Serial.print(F(" - derived from GPS and GLONASS time difference"));
|
||||
break;
|
||||
case SFE_UBLOX_LS_SRC_GPS:
|
||||
Serial.print(F(" - according to GPS"));
|
||||
break;
|
||||
case SFE_UBLOX_LS_SRC_SBAS:
|
||||
Serial.print(F(" - according to SBAS"));
|
||||
break;
|
||||
case SFE_UBLOX_LS_SRC_BEIDOU:
|
||||
Serial.print(F(" - according to BeiDou"));
|
||||
break;
|
||||
case SFE_UBLOX_LS_SRC_GALILEO:
|
||||
Serial.print(F(" - according to Galileo"));
|
||||
break;
|
||||
case SFE_UBLOX_LS_SRC_AIDED:
|
||||
Serial.print(F(" - last minute will end at 23:58"));
|
||||
break;
|
||||
case SFE_UBLOX_LS_SRC_CONFIGURED:
|
||||
Serial.print(F(" - as configured)"));
|
||||
break;
|
||||
case SFE_UBLOX_LS_SRC_UNKNOWN:
|
||||
default:
|
||||
Serial.print(F(" - source unknown"));
|
||||
break;
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
Get the jamming state and indication
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: March 2nd, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to enable the jamming / interference monitor and read the
|
||||
jamming state and information.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a RedBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("SparkFun u-blox GNSS Example"));
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false)
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
// Enable the jamming / interference monitor
|
||||
UBX_CFG_ITFM_data_t jammingConfig; // Create storage for the jamming configuration
|
||||
if (myGNSS.getJammingConfiguration(&jammingConfig)) // Read the jamming configuration
|
||||
{
|
||||
Serial.print(F("The jamming / interference monitor is "));
|
||||
if (jammingConfig.config.bits.enable == 0) // Check if the monitor is already enabled
|
||||
Serial.print(F("not "));
|
||||
Serial.println(F("enabled"));
|
||||
|
||||
if (jammingConfig.config.bits.enable == 0) // Check if the monitor is already enabled
|
||||
{
|
||||
Serial.print(F("Enabling the jamming / interference monitor: "));
|
||||
(jammingConfig.config.bits.enable = 1); // Enable the monitor
|
||||
if (myGNSS.setJammingConfiguration(&jammingConfig)) // Set the jamming configuration
|
||||
Serial.println(F("success"));
|
||||
else
|
||||
Serial.println(F("failed!"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Create storage to hold the hardware status
|
||||
// See the definition of UBX_MON_HW_data_t in u-blox_structs.h for more details
|
||||
UBX_MON_HW_data_t hwStatus;
|
||||
|
||||
if (myGNSS.getHWstatus(&hwStatus)) // Read the hardware status
|
||||
{
|
||||
Serial.println(F("Hardware status (UBX_MON_HW):"));
|
||||
|
||||
Serial.print(F("Jamming state: "));
|
||||
Serial.print(hwStatus.flags.bits.jammingState);
|
||||
if (hwStatus.flags.bits.jammingState == 0)
|
||||
Serial.println(F(" = unknown / disabled"));
|
||||
else if (hwStatus.flags.bits.jammingState == 1)
|
||||
Serial.println(F(" = ok"));
|
||||
else if (hwStatus.flags.bits.jammingState == 2)
|
||||
Serial.println(F(" = warning"));
|
||||
else // if (hwStatus.flags.bits.jammingState == 3)
|
||||
Serial.println(F(" = critical!"));
|
||||
|
||||
Serial.print(F("Noise level: "));
|
||||
Serial.println(hwStatus.noisePerMS);
|
||||
|
||||
Serial.print(F("AGC monitor: "));
|
||||
Serial.println(hwStatus.agcCnt);
|
||||
|
||||
Serial.print(F("CW jamming indicator: "));
|
||||
Serial.println(hwStatus.jamInd);
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
// Create storage to hold the RF information from a ZED-F9
|
||||
// See the definition of UBX_MON_RF_data_t in u-blox_structs.h for more details
|
||||
UBX_MON_RF_data_t rfInformation;
|
||||
|
||||
// Read the RF information from the ZED-F9n. Allow 2 seconds for the data to be returned. Will time out on M8 modules
|
||||
if (myGNSS.getRFinformation(&rfInformation, 2000))
|
||||
{
|
||||
Serial.print(F("The UBX_MON_RF message contains "));
|
||||
Serial.print(rfInformation.header.nBlocks); // Print how many information blocks were returned. Should be 0, 1 or 2
|
||||
Serial.println(F(" information blocks"));
|
||||
|
||||
for (uint8_t block = 0; block < rfInformation.header.nBlocks; block++)
|
||||
{
|
||||
Serial.print(F("Block ID: "));
|
||||
Serial.print(rfInformation.blocks[block].blockId);
|
||||
if (rfInformation.blocks[block].blockId == 0)
|
||||
Serial.println(F(" = L1"));
|
||||
else // if (rfInformation.blocks[block].blockId == 1)
|
||||
Serial.println(F(" = L2 / L5"));
|
||||
|
||||
Serial.print(F("Jamming state: "));
|
||||
Serial.print(rfInformation.blocks[block].flags.bits.jammingState);
|
||||
if (rfInformation.blocks[block].flags.bits.jammingState == 0)
|
||||
Serial.println(F(" = unknown / disabled"));
|
||||
else if (rfInformation.blocks[block].flags.bits.jammingState == 1)
|
||||
Serial.println(F(" = ok"));
|
||||
else if (rfInformation.blocks[block].flags.bits.jammingState == 2)
|
||||
Serial.println(F(" = warning"));
|
||||
else // if (rfInformation.blocks[block].flags.bits.jammingState == 3)
|
||||
Serial.println(F(" = critical!"));
|
||||
|
||||
Serial.print(F("Noise level: "));
|
||||
Serial.println(rfInformation.blocks[block].noisePerMS);
|
||||
|
||||
Serial.print(F("AGC monitor: "));
|
||||
Serial.println(rfInformation.blocks[block].agcCnt);
|
||||
|
||||
Serial.print(F("CW jamming indicator: "));
|
||||
Serial.println(rfInformation.blocks[block].jamInd);
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
Read NMEA sentences over I2C using u-blox module SAM-M8Q, NEO-M8P, etc
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: August 22nd, 2018
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example reads the NMEA characters over I2C and pipes them to MicroNMEA
|
||||
This example will output your current long/lat and satellites in view
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
For more MicroNMEA info see https://github.com/stevemarple/MicroNMEA
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
Go outside! Wait ~25 seconds and you should see your lat/long
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
#include <MicroNMEA.h> //http://librarymanager/All#MicroNMEA
|
||||
char nmeaBuffer[100];
|
||||
MicroNMEA nmea(nmeaBuffer, sizeof(nmeaBuffer));
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false)
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the I2C port to output both NMEA and UBX messages
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setProcessNMEAMask(SFE_UBLOX_FILTER_NMEA_ALL); // Make sure the library is passing all NMEA messages to processNMEA
|
||||
|
||||
myGNSS.setProcessNMEAMask(SFE_UBLOX_FILTER_NMEA_GGA); // Or, we can be kind to MicroNMEA and _only_ pass the GGA messages to it
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.
|
||||
|
||||
if(nmea.isValid() == true)
|
||||
{
|
||||
long latitude_mdeg = nmea.getLatitude();
|
||||
long longitude_mdeg = nmea.getLongitude();
|
||||
|
||||
Serial.print("Latitude (deg): ");
|
||||
Serial.println(latitude_mdeg / 1000000., 6);
|
||||
Serial.print("Longitude (deg): ");
|
||||
Serial.println(longitude_mdeg / 1000000., 6);
|
||||
|
||||
nmea.clear(); // Clear the MicroNMEA storage to make sure we are getting fresh data
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Waiting for fresh data");
|
||||
}
|
||||
|
||||
delay(250); //Don't pound too hard on the I2C bus
|
||||
}
|
||||
|
||||
//This function gets called from the SparkFun u-blox Arduino Library
|
||||
//As each NMEA character comes in you can specify what to do with it
|
||||
//Useful for passing to other libraries like tinyGPS, MicroNMEA, or even
|
||||
//a buffer, radio, etc.
|
||||
void SFE_UBLOX_GNSS::processNMEA(char incoming)
|
||||
{
|
||||
//Take the incoming char from the u-blox I2C port and pass it on to the MicroNMEA lib
|
||||
//for sentence cracking
|
||||
nmea.process(incoming);
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
NEO-D9S L-Band receiver example
|
||||
By: SparkFun Electronics / Paul Clark
|
||||
Date: March 7th, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to display the NEO-D9S's received signal imbalance and magnitude, plus a summary of any received PMP data.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
|
||||
NEO-D9S Correction Data Receiver: https://www.sparkfun.com/products/19390
|
||||
|
||||
Hardware Connections:
|
||||
Use a Qwiic cable to connect the NEO-D9S L-Band corection data receiver to your board
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myLBand; // NEO-D9S
|
||||
|
||||
const uint32_t myLBandFreq = 1556290000; // Uncomment this line to use the US SPARTN 1.8 service
|
||||
//const uint32_t myLBandFreq = 1545260000; // Uncomment this line to use the EU SPARTN 1.8 service
|
||||
|
||||
#define OK(ok) (ok ? F(" -> OK") : F(" -> ERROR!")) // Convert uint8_t into OK/ERROR
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
// Callback: printRXMPMP will be called when new PMP data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_RXM_PMP_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setRXMPMPcallbackPtr
|
||||
// / _____ This _must_ be UBX_RXM_PMP_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printRXMPMP(UBX_RXM_PMP_data_t *pmpData)
|
||||
{
|
||||
Serial.println(F("New PMP data received:"));
|
||||
|
||||
Serial.print(F("PMP message version: "));
|
||||
Serial.println(pmpData->version);
|
||||
|
||||
Serial.print(F("numBytesUserData : "));
|
||||
Serial.println(pmpData->numBytesUserData);
|
||||
|
||||
Serial.print(F("serviceIdentifier: 0x"));
|
||||
Serial.println(pmpData->serviceIdentifier, HEX);
|
||||
|
||||
Serial.print(F("uniqueWordBitErrors: "));
|
||||
Serial.println(pmpData->uniqueWordBitErrors);
|
||||
|
||||
Serial.print(F("fecBits: "));
|
||||
Serial.println(pmpData->fecBits);
|
||||
|
||||
Serial.print(F("ebno (dB): "));
|
||||
Serial.println((double)pmpData->ebno / 8, 3); //Convert ebno to dB
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("NEO-D9S Example"));
|
||||
|
||||
Wire.begin(); //Start I2C
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Begin and configure the NEO-D9S L-Band receiver
|
||||
|
||||
//myLBand.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
|
||||
while (myLBand.begin(Wire, 0x43) == false) //Connect to the u-blox NEO-D9S using Wire port. The D9S default I2C address is 0x43 (not 0x42)
|
||||
{
|
||||
Serial.println(F("u-blox NEO-D9S not detected at default I2C address. Please check wiring."));
|
||||
delay(2000);
|
||||
}
|
||||
Serial.println(F("u-blox NEO-D9S connected"));
|
||||
|
||||
uint8_t ok = myLBand.setVal32(UBLOX_CFG_PMP_CENTER_FREQUENCY, myLBandFreq); // Default 1539812500 Hz
|
||||
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_SEARCH_WINDOW, 2200); // Default 2200 Hz
|
||||
if (ok) ok = myLBand.setVal8(UBLOX_CFG_PMP_USE_SERVICE_ID, 0); // Default 1
|
||||
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_SERVICE_ID, 21845); // Default 50821
|
||||
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_DATA_RATE, 2400); // Default 2400 bps
|
||||
if (ok) ok = myLBand.setVal8(UBLOX_CFG_PMP_USE_DESCRAMBLER, 1); // Default 1
|
||||
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_DESCRAMBLER_INIT, 26969); // Default 23560
|
||||
if (ok) ok = myLBand.setVal8(UBLOX_CFG_PMP_USE_PRESCRAMBLING, 0); // Default 0
|
||||
if (ok) ok = myLBand.setVal64(UBLOX_CFG_PMP_UNIQUE_WORD, 16238547128276412563ull);
|
||||
if (ok) ok = myLBand.setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_I2C, 1); // Ensure UBX-RXM-PMP is enabled on the I2C port
|
||||
if (ok) ok = myLBand.setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART1, 1); // Output UBX-RXM-PMP on UART1
|
||||
if (ok) ok = myLBand.setVal8(UBLOX_CFG_UART2OUTPROT_UBX, 1); // Enable UBX output on UART2
|
||||
if (ok) ok = myLBand.setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART2, 1); // Output UBX-RXM-PMP on UART2
|
||||
if (ok) ok = myLBand.setVal32(UBLOX_CFG_UART1_BAUDRATE, 38400); // match baudrate with ZED default
|
||||
if (ok) ok = myLBand.setVal32(UBLOX_CFG_UART2_BAUDRATE, 38400); // match baudrate with ZED default
|
||||
|
||||
Serial.print(F("L-Band: configuration "));
|
||||
Serial.println(OK(ok));
|
||||
|
||||
myLBand.softwareResetGNSSOnly(); // Do a restart
|
||||
|
||||
myLBand.setRXMPMPcallbackPtr(&printRXMPMP); // Call printRXMPMP when new PMP data arrives
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void loop()
|
||||
{
|
||||
myLBand.checkUblox(); // Check for the arrival of new PMP data and process it.
|
||||
myLBand.checkCallbacks(); // Check if any LBand callbacks are waiting to be processed.
|
||||
|
||||
UBX_MON_HW2_data_t hwStatus; // Create storage for the HW2 extended hardware status
|
||||
if (myLBand.getHW2status(&hwStatus)) // Request the extended hardware status
|
||||
{
|
||||
// Print the signal imbalance and magnitude
|
||||
Serial.print(F("Signal imbalance and magnitude: ofsI: "));
|
||||
Serial.print(hwStatus.ofsI);
|
||||
Serial.print(F(" magI: "));
|
||||
Serial.print(hwStatus.magI);
|
||||
Serial.print(F(" ofsQ: "));
|
||||
Serial.print(hwStatus.ofsQ);
|
||||
Serial.print(F(" magQ: "));
|
||||
Serial.println(hwStatus.magQ);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
Calculating the Great Circle Distance and Course to a target position
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: September 21st, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to query a u-blox module for its latitude/longitude and then
|
||||
calculate the Great Circle Distance and Course to a target location.
|
||||
|
||||
Thanks! distanceBetween and courseTo were taken from Mikal Hart's TinyGPSPlus:
|
||||
https://github.com/mikalhart/TinyGPSPlus/blob/ca29434514a5c5172bd807af0608df7f296582a2/src/TinyGPS%2B%2B.cpp#L285-L328
|
||||
|
||||
Note: Lat/Long are large numbers because they are degrees * 10^-7. To convert lat/long
|
||||
to something google maps understands simply divide the numbers by 10,000,000. We
|
||||
do this so that we don't have to use floating point numbers.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
|
||||
//#include <math.h> //Uncomment if required. May be needed for sqrt, atan2, etc..
|
||||
|
||||
double distanceBetween(long lat1_l, long long1_l, long lat2_l, long long2_l)
|
||||
{
|
||||
// returns distance in meters between two positions, both specified
|
||||
// as signed decimal-degrees latitude and longitude. Uses great-circle
|
||||
// distance computation for hypothetical sphere of radius 6372795 meters.
|
||||
// Because Earth is no exact sphere, rounding errors may be up to 0.5%.
|
||||
// Courtesy of Maarten Lamers
|
||||
double lat1 = (double)lat1_l / 10000000.0; // Convert lat and long to degrees
|
||||
double long1 = (double)long1_l / 10000000.0;
|
||||
double lat2 = (double)lat2_l / 10000000.0;
|
||||
double long2 = (double)long2_l / 10000000.0;
|
||||
double delta = radians(long1-long2);
|
||||
double sdlong = sin(delta);
|
||||
double cdlong = cos(delta);
|
||||
lat1 = radians(lat1);
|
||||
lat2 = radians(lat2);
|
||||
double slat1 = sin(lat1);
|
||||
double clat1 = cos(lat1);
|
||||
double slat2 = sin(lat2);
|
||||
double clat2 = cos(lat2);
|
||||
delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
|
||||
delta = sq(delta);
|
||||
delta += sq(clat2 * sdlong);
|
||||
delta = sqrt(delta);
|
||||
double denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
|
||||
delta = atan2(delta, denom);
|
||||
return delta * 6372795;
|
||||
}
|
||||
|
||||
double courseTo(long lat1_l, long long1_l, long lat2_l, long long2_l)
|
||||
{
|
||||
// returns course in degrees (North=0, West=270) from position 1 to position 2,
|
||||
// both specified as signed decimal-degrees latitude and longitude.
|
||||
// Because Earth is no exact sphere, calculated course may be off by a tiny fraction.
|
||||
// Courtesy of Maarten Lamers
|
||||
double lat1 = (double)lat1_l / 10000000.0; // Convert lat and long to degrees
|
||||
double long1 = (double)long1_l / 10000000.0;
|
||||
double lat2 = (double)lat2_l / 10000000.0;
|
||||
double long2 = (double)long2_l / 10000000.0;
|
||||
double dlon = radians(long2-long1);
|
||||
lat1 = radians(lat1);
|
||||
lat2 = radians(lat2);
|
||||
double a1 = sin(dlon) * cos(lat2);
|
||||
double a2 = sin(lat1) * cos(lat2) * cos(dlon);
|
||||
a2 = cos(lat1) * sin(lat2) - a2;
|
||||
a2 = atan2(a1, a2);
|
||||
if (a2 < 0.0)
|
||||
{
|
||||
a2 += TWO_PI;
|
||||
}
|
||||
return degrees(a2);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Query module only every second. Doing it more often will just cause I2C traffic.
|
||||
//The module only responds when a new position is available
|
||||
if (millis() - lastTime > 1000)
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.println(F(" (degrees * 10^-7)"));
|
||||
|
||||
static const long TARGET_LAT = 400909142, TARGET_LON = -1051849833; // SparkFun's location: degrees * 10^-7 (40.091 N, 105.185 W)
|
||||
|
||||
double distanceToTarget = distanceBetween(
|
||||
latitude,
|
||||
longitude,
|
||||
TARGET_LAT,
|
||||
TARGET_LON);
|
||||
|
||||
Serial.print(F("Distance to target: "));
|
||||
Serial.print(distanceToTarget, 2);
|
||||
Serial.print(F(" (m) "));
|
||||
|
||||
double courseToTarget = courseTo(
|
||||
latitude,
|
||||
longitude,
|
||||
TARGET_LAT,
|
||||
TARGET_LON);
|
||||
|
||||
Serial.print(F("Course to target: "));
|
||||
Serial.print(courseToTarget, 1);
|
||||
Serial.println(F(" (degrees)"));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
NEO-D9C QZSS-L6 receiver example
|
||||
By: SparkFun Electronics / Paul Clark
|
||||
Date: September 23rd, 2022
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to display a summary of the NEO-D9C's UBX-RXM-QZSSL6 data.
|
||||
It also enables UBX-RXM-QZSSL6 message output on both UART1 and UART2 at 38400 baud
|
||||
so you can feed the corrections directly to (e.g.) a ZED-F9P.
|
||||
|
||||
We believe the NEO-D9C's I2C address should be 0x43 (like the NEO-D9S). But, reported by users in Japan,
|
||||
the initial NEO-D9C's use address 0x42 - which is the same as the ZED-F9P.
|
||||
|
||||
If you have one of the initial NEO-D9C's, the address 0x42 should work for you.
|
||||
If you have a newer or upgraded NEO-D9C, then you may need to change to 0x43. See line 100.
|
||||
|
||||
Also, again reported by users in Japan, the initial NEO-D9C's do not support UBX-CFG-PRT.
|
||||
The library uses UBX-CFG-PRT inside .begin (.isConnected) to check if the module is connected.
|
||||
This then fails with the initial NEO-D9C's.
|
||||
The work-around is to set the .begin assumeSuccess parameter to true.
|
||||
With newer NEO-D9C's this work-around may not be necessary. Again see line 100.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
|
||||
NEO-D9S L-Band Correction Data Receiver: https://www.sparkfun.com/products/19390
|
||||
|
||||
Hardware Connections:
|
||||
Use a Qwiic cable to connect the NEO-D9C QZSS-L6 corection data receiver to your board
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myQZSS; // NEO-D9C
|
||||
|
||||
#define OK(ok) (ok ? F(" -> OK") : F(" -> ERROR!")) // Convert uint8_t into OK/ERROR
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
// Callback: printRXMQZSSL6 will be called when new QZSS-L6 data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_RXM_QZSSL6_message_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setRXMQZSSL6messageCallbackPtr
|
||||
// / _____ This _must_ be UBX_RXM_QZSSL6_message_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printRXMQZSSL6(UBX_RXM_QZSSL6_message_data_t *qzssL6Data)
|
||||
{
|
||||
Serial.println(F("New QZSS-L6 data received:"));
|
||||
|
||||
Serial.print(F("Message version: "));
|
||||
Serial.println(qzssL6Data->payload[0]);
|
||||
|
||||
Serial.print(F("Satellite Identifier: "));
|
||||
Serial.println(qzssL6Data->payload[1]);
|
||||
|
||||
Serial.print(F("Carrier / Noise: "));
|
||||
double cno = (0.00390625 * ((double)qzssL6Data->payload[2])) + ((double)qzssL6Data->payload[3]);
|
||||
Serial.println(cno, 1);
|
||||
|
||||
Serial.print(F("Bit Errors Corrected: "));
|
||||
Serial.println(qzssL6Data->payload[9]);
|
||||
|
||||
uint16_t chInfo = (((uint16_t)qzssL6Data->payload[11]) << 8) | qzssL6Data->payload[10];
|
||||
uint16_t errStatus = ((chInfo >> 12) & 0x3);
|
||||
Serial.print(F("Receiver Channel: "));
|
||||
Serial.println((chInfo >> 8) & 0x3);
|
||||
Serial.print(F("Message Name: L6"));
|
||||
Serial.println(((chInfo >> 10) & 0x1) == 0 ? F("D") : F("E"));
|
||||
Serial.print(F("Error Status: "));
|
||||
if (errStatus == 1)
|
||||
Serial.println("error-free");
|
||||
else if (errStatus == 2)
|
||||
Serial.println("erroneous");
|
||||
else
|
||||
Serial.println("unknown");
|
||||
Serial.print(F("Channel Name: "));
|
||||
Serial.println(((chInfo >> 14) & 0x3) == 0 ? F("A") : F("B"));
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(F("NEO-D9C Example"));
|
||||
|
||||
Wire.begin(); //Start I2C
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Begin and configure the NEO-D9C QZSS-L6 receiver
|
||||
|
||||
//myQZSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
|
||||
// For the initial NEO-D9C's: connect using address 0x42; set the assumeSuccess parameter to true
|
||||
while (myQZSS.begin(Wire, 0x42, 1100, true) == false)
|
||||
// For newer NEO-D9C's: use address 0x43; leave assumeSuccess set to false (default)
|
||||
//while (myQZSS.begin(Wire, 0x43) == false)
|
||||
{
|
||||
Serial.println(F("u-blox NEO-D9C not detected at selected I2C address. Please check wiring and I2C address."));
|
||||
delay(2000);
|
||||
}
|
||||
Serial.println(F("u-blox NEO-D9C connected"));
|
||||
|
||||
uint8_t ok = myQZSS.setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_I2C, 1); // Output QZSS-L6 message on the I2C port
|
||||
|
||||
Serial.print(F("QZSS-L6: I2C configuration "));
|
||||
Serial.println(OK(ok));
|
||||
|
||||
if (ok) ok = myQZSS.setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_UART1, 1); // Output QZSS-L6 message on UART1
|
||||
if (ok) ok = myQZSS.setVal32(UBLOX_CFG_UART1_BAUDRATE, 38400); // Match UART1 baudrate with ZED
|
||||
|
||||
Serial.print(F("QZSS-L6: UART1 configuration "));
|
||||
Serial.println(OK(ok));
|
||||
|
||||
if (ok) ok = myQZSS.setVal8(UBLOX_CFG_UART2OUTPROT_UBX, 1); // Enable UBX output on UART2
|
||||
if (ok) ok = myQZSS.setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_UART2, 1); // Output QZSS-L6 message on UART2
|
||||
if (ok) ok = myQZSS.setVal32(UBLOX_CFG_UART2_BAUDRATE, 38400); // Match UART2 baudrate with ZED
|
||||
|
||||
Serial.print(F("QZSS-L6: UART2 configuration "));
|
||||
Serial.println(OK(ok));
|
||||
|
||||
myQZSS.setRXMQZSSL6messageCallbackPtr(&printRXMQZSSL6); // Call printRXMQZSSL6 when new QZSS-L6 data arrives
|
||||
}
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
void loop()
|
||||
{
|
||||
myQZSS.checkUblox(); // Check for the arrival of new QZSS-L6 data and process it.
|
||||
myQZSS.checkCallbacks(); // Check if any QZSS-L6 callbacks are waiting to be processed.
|
||||
}
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
Configure Time & Frequency Sync manager (UBX-CFG-SMGR)
|
||||
By: Danylo Ulianych
|
||||
SparkFun Electronics
|
||||
Date: March 6th, 2024
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example reads / sets UBX-CFG-SMGR configuration and prints UBX-TIM-SMEAS messages.
|
||||
Works only with Time & Frequency Sync products like LEA-M8F, etc.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
|
||||
// Callback: printTIMSMEASdata will be called when new TIM SMEA data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_TIM_SMEAS_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoTIMTM2callback
|
||||
// / _____ This _must_ be UBX_TIM_SMEAS_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printTIMSMEASdata(UBX_TIM_SMEAS_data_t smea)
|
||||
{
|
||||
Serial.print("UBX-TIM-SMEAS:");
|
||||
Serial.printf("\n version: %u", smea.version);
|
||||
Serial.printf("\n numMeas: %u", smea.numMeas);
|
||||
Serial.printf("\n iTOW: %lu", smea.iTOW);
|
||||
for (int i = 0; i < smea.numMeas; i++) {
|
||||
Serial.printf("\n sourceId %u:", smea.data[i].sourceId);
|
||||
Serial.printf("\n flags:");
|
||||
Serial.printf("\n freqValid %u", smea.data[i].flags.bits.freqValid);
|
||||
Serial.printf("\n phaseValid %u", smea.data[i].flags.bits.phaseValid);
|
||||
Serial.printf("\n phaseOffsetFrac %d", smea.data[i].phaseOffsetFrac);
|
||||
Serial.printf("\n phaseUncFrac %u", smea.data[i].phaseUncFrac);
|
||||
Serial.printf("\n phaseOffset %ld", smea.data[i].phaseOffset);
|
||||
Serial.printf("\n phaseUnc %lu", smea.data[i].phaseUnc);
|
||||
Serial.printf("\n freqOffset %ld", smea.data[i].freqOffset);
|
||||
Serial.printf("\n freqUnc %lu", smea.data[i].freqUnc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UBX_CFG_SMGR_data_t convertRawBufToCfgSmgr(const ubxPacket* msg) {
|
||||
UBX_CFG_SMGR_data_t smgr;
|
||||
if (msg->len < sizeof(UBX_CFG_SMGR_data_t)) {
|
||||
Serial.printf("Payload message size (%zu) is too small to be converted to UBX_CFG_SMGR_data_t\n", msg->len);
|
||||
return smgr;
|
||||
}
|
||||
|
||||
smgr.version = SFE_UBLOX_GNSS::extractByte(msg, 0);
|
||||
smgr.minGNSSFix = SFE_UBLOX_GNSS::extractByte(msg, 1);
|
||||
smgr.maxFreqChangeRate = SFE_UBLOX_GNSS::extractInt(msg, 2);
|
||||
smgr.maxPhaseCorrRate = SFE_UBLOX_GNSS::extractInt(msg, 4);
|
||||
smgr.freqTolerance = SFE_UBLOX_GNSS::extractInt(msg, 8);
|
||||
smgr.timeTolerance = SFE_UBLOX_GNSS::extractInt(msg, 10);
|
||||
smgr.messageCfg.all = SFE_UBLOX_GNSS::extractInt(msg, 12);
|
||||
smgr.maxSlewRate = SFE_UBLOX_GNSS::extractInt(msg, 14);
|
||||
smgr.flags.all = SFE_UBLOX_GNSS::extractLong(msg, 16);
|
||||
|
||||
return smgr;
|
||||
}
|
||||
|
||||
|
||||
void printUbxCfgSmgr(const UBX_CFG_SMGR_data_t& smgr) {
|
||||
Serial.printf("\nUBX-CFG-SMGR:");
|
||||
Serial.printf("\n version %u (0x%02x)", smgr.version, smgr.version);
|
||||
Serial.printf("\n minGNSSFix %u (0x%02x)", smgr.minGNSSFix, smgr.minGNSSFix);
|
||||
Serial.printf("\n maxFreqChangeRate %u (0x%02x)", smgr.maxFreqChangeRate, smgr.maxFreqChangeRate);
|
||||
Serial.printf("\n maxPhaseCorrRate %u (0x%02x)", smgr.maxPhaseCorrRate, smgr.maxPhaseCorrRate);
|
||||
Serial.printf("\n freqTolerance %u (0x%02x)", smgr.freqTolerance, smgr.freqTolerance);
|
||||
Serial.printf("\n timeTolerance %u (0x%02x)", smgr.timeTolerance, smgr.timeTolerance);
|
||||
Serial.printf("\n messageCfg:");
|
||||
Serial.printf("\n measInternal: %u", smgr.messageCfg.bits.measInternal);
|
||||
Serial.printf("\n measGNSS: %u", smgr.messageCfg.bits.measGNSS);
|
||||
Serial.printf("\n measEXTINT0: %u", smgr.messageCfg.bits.measEXTINT0);
|
||||
Serial.printf("\n measEXTINT1: %u", smgr.messageCfg.bits.measEXTINT1);
|
||||
Serial.printf("\n maxSlewRate %u (0x%02x)", smgr.maxSlewRate, smgr.maxSlewRate);
|
||||
Serial.printf("\n flags:");
|
||||
Serial.printf("\n disableInternal: %u", smgr.flags.bits.disableInternal);
|
||||
Serial.printf("\n disableExternal: %u", smgr.flags.bits.disableExternal);
|
||||
Serial.printf("\n preferenceMode: %u", smgr.flags.bits.preferenceMode);
|
||||
Serial.printf("\n enableGNSS: %u", smgr.flags.bits.enableGNSS);
|
||||
Serial.printf("\n enableEXTINT0: %u", smgr.flags.bits.enableEXTINT0);
|
||||
Serial.printf("\n enableEXTINT1: %u", smgr.flags.bits.enableEXTINT1);
|
||||
Serial.printf("\n enableHostMeasInt: %u", smgr.flags.bits.enableHostMeasInt);
|
||||
Serial.printf("\n enableHostMeasExt: %u", smgr.flags.bits.enableHostMeasExt);
|
||||
Serial.printf("\n useAnyFix: %u", smgr.flags.bits.useAnyFix);
|
||||
Serial.printf("\n disableMaxSlewRate: %u", smgr.flags.bits.disableMaxSlewRate);
|
||||
Serial.printf("\n issueFreqWarn: %u", smgr.flags.bits.issueFreqWarn);
|
||||
Serial.printf("\n issueTimeWarn: %u", smgr.flags.bits.issueTimeWarn);
|
||||
Serial.printf("\n TPCoherent: %u", smgr.flags.bits.TPCoherent);
|
||||
Serial.printf("\n disableOffset: %u", smgr.flags.bits.disableOffset);
|
||||
Serial.println("\n");
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); // wait for Serial ready
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false)
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); // ignore NMEA messages
|
||||
|
||||
// setPacketCfgPayloadSize tells the library how many bytes our customPayload can hold.
|
||||
// It is more memory-efficient to call setPacketCfgPayloadSize before .begin (to avoid creating a new buffer, copying across
|
||||
// the contents of the old buffer and then deleting the old buffer). But let's call it here just to prove that we can.
|
||||
myGNSS.setPacketCfgPayloadSize(MAX_PAYLOAD_SIZE);
|
||||
|
||||
uint8_t customPayload[MAX_PAYLOAD_SIZE]; // This array holds the payload data bytes. MAX_PAYLOAD_SIZE defaults to 256. The CFG_RATE payload is only 6 bytes!
|
||||
|
||||
// The next line creates and initialises the packet information which wraps around the payload
|
||||
ubxPacket customCfg = {0, 0, 0, 0, 0, customPayload, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED};
|
||||
|
||||
// The structure of ubxPacket is:
|
||||
// uint8_t cls : The message Class
|
||||
// uint8_t id : The message ID
|
||||
// uint16_t len : Length of the payload. Does not include cls, id, or checksum bytes
|
||||
// uint16_t counter : Keeps track of number of overall bytes received. Some responses are larger than 255 bytes.
|
||||
// uint16_t startingSpot : The counter value needed to go past before we begin recording into payload array
|
||||
// uint8_t *payload : The payload
|
||||
// uint8_t checksumA : Given to us by the module. Checked against the rolling calculated A/B checksums.
|
||||
// uint8_t checksumB
|
||||
// sfe_ublox_packet_validity_e valid : Goes from NOT_DEFINED to VALID or NOT_VALID when checksum is checked
|
||||
// sfe_ublox_packet_validity_e classAndIDmatch : Goes from NOT_DEFINED to VALID or NOT_VALID when the Class and ID match the requestedClass and requestedID
|
||||
|
||||
// sendCommand will return:
|
||||
// SFE_UBLOX_STATUS_DATA_RECEIVED if the data we requested was read / polled successfully
|
||||
// SFE_UBLOX_STATUS_DATA_SENT if the data we sent was writted successfully (ACK'd)
|
||||
// Other values indicate errors. Please see the sfe_ublox_status_e enum for further details.
|
||||
|
||||
// Referring to the u-blox M8 Receiver Description and Protocol Specification we see that
|
||||
// the navigation rate is configured using the UBX-CFG-RATE message. So let's load our
|
||||
// custom packet with the correct information so we can read (poll / get) the current settings.
|
||||
|
||||
customCfg.cls = UBX_CLASS_CFG; // This is the message Class
|
||||
customCfg.id = UBX_CFG_SMGR; // This is the message ID
|
||||
customCfg.len = 0; // Setting the len (length) to zero let's us poll the current settings
|
||||
customCfg.startingSpot = 0; // Always set the startingSpot to zero (unless you really know what you are doing)
|
||||
|
||||
// We also need to tell sendCommand how long it should wait for a reply
|
||||
uint16_t maxWait = 250; // Wait for up to 250ms (Serial may need a lot longer e.g. 1100)
|
||||
|
||||
// Now let's read the current UBX-CFG-SMGR settings. The results will be loaded into customCfg.
|
||||
if (myGNSS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK
|
||||
{
|
||||
Serial.println(F("sendCommand (poll / get) failed! Freezing..."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
UBX_CFG_SMGR_data_t cfgSmgrPayload = convertRawBufToCfgSmgr(&customCfg);
|
||||
|
||||
printUbxCfgSmgr(cfgSmgrPayload);
|
||||
|
||||
cfgSmgrPayload.minGNSSFix = 5; // update the min no. of GNSS fixes to start freq/phase sync
|
||||
cfgSmgrPayload.flags.bits.useAnyFix = 1; // use any fix
|
||||
|
||||
// update the raw payload buffer
|
||||
memmove(customPayload, &cfgSmgrPayload, sizeof(UBX_CFG_SMGR_data_t));
|
||||
|
||||
// Now let's set the updated settings.
|
||||
if (myGNSS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) // We are expecting data and an ACK
|
||||
{
|
||||
Serial.println(F("sendCommand set failed! Freezing..."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
Serial.println("UBX-CFG-SMGR successfully updated");
|
||||
|
||||
myGNSS.setAutoTIMSMEAcallback(&printTIMSMEASdata);
|
||||
|
||||
// Enable info/warns messages
|
||||
// myGNSS.setVal8(UBLOX_CFG_INFMSG_UBX_I2C, 1);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); //See if new UBX data is available. Process bytes as they come in.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
delay(250); //Don't pound too hard on the I2C bus
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
Reading lat and long via UBX binary commands - no more NMEA parsing!
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: January 3rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to query a u-blox module for its lat/long/altitude. We also
|
||||
turn off the NMEA output on the I2C port. This decreases the amount of I2C traffic
|
||||
dramatically.
|
||||
|
||||
Note: Long/lat are large numbers because they are * 10^7. To convert lat/long
|
||||
to something google maps understands simply divide the numbers by 10,000,000. We
|
||||
do this so that we don't have to use floating point numbers.
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Query module only every second. Doing it more often will just cause I2C traffic.
|
||||
//The module only responds when a new position is available
|
||||
if (millis() - lastTime > 1000)
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
Serial.print(F(" (mm)"));
|
||||
|
||||
byte SIV = myGNSS.getSIV();
|
||||
Serial.print(F(" SIV: "));
|
||||
Serial.print(SIV);
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
Get fix type and RTK fix type if available
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: January 3rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to query a u-blox module for fix type and RTK fix type.
|
||||
The fix type is as follows:
|
||||
0 = no fix
|
||||
1 = dead reckoning (requires external sensors)
|
||||
2 = 2D (not quite enough satellites in view)
|
||||
3 = 3D (the standard fix)
|
||||
4 = GNSS + dead reckoning (requires external sensors)
|
||||
5 = Time fix only
|
||||
|
||||
Additionally, if we are doing RTK, we can figure out if we have a floating
|
||||
RTK solution or if we have been able to resolve a fixec solution (better precision).
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
//Wire.setClock(400000); //Optional. Increase I2C clock speed to 400kHz.
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Query module only every second. Doing it more often will just cause I2C traffic.
|
||||
if (millis() - lastTime > 1000)
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
|
||||
long altitude = myGNSS.getAltitude();
|
||||
Serial.print(F(" Alt: "));
|
||||
Serial.print(altitude);
|
||||
|
||||
byte fixType = myGNSS.getFixType();
|
||||
Serial.print(F(" Fix: "));
|
||||
if(fixType == 0) Serial.print(F("No fix"));
|
||||
else if(fixType == 1) Serial.print(F("Dead reckoning"));
|
||||
else if(fixType == 2) Serial.print(F("2D"));
|
||||
else if(fixType == 3) Serial.print(F("3D"));
|
||||
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
|
||||
else if(fixType == 5) Serial.print(F("Time only"));
|
||||
|
||||
byte RTK = myGNSS.getCarrierSolutionType();
|
||||
Serial.print(" RTK: ");
|
||||
Serial.print(RTK);
|
||||
if (RTK == 0) Serial.print(F(" (No solution)"));
|
||||
else if (RTK == 1) Serial.print(F(" (High precision floating fix)"));
|
||||
else if (RTK == 2) Serial.print(F(" (High precision fix)"));
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
Get Speed/Heading and dilution of precision via UBX binary commands - no more NMEA parsing!
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: January 3rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to query a u-blox module for its lat/long/altitude.
|
||||
|
||||
Note: Long/lat are large numbers because they are * 10^7. To convert lat/long
|
||||
to something google maps understands simply divide the numbers by 1,000,000. We
|
||||
do this so that we don't have to use floating point numbers.
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Query module only every second. Doing it more often will just cause I2C traffic.
|
||||
//The module only responds when a new position is available
|
||||
if (millis() - lastTime > 1000)
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
|
||||
long speed = myGNSS.getGroundSpeed();
|
||||
Serial.print(F(" Speed: "));
|
||||
Serial.print(speed);
|
||||
Serial.print(F(" (mm/s)"));
|
||||
|
||||
long heading = myGNSS.getHeading();
|
||||
Serial.print(F(" Heading: "));
|
||||
Serial.print(heading);
|
||||
Serial.print(F(" (degrees * 10^-5)"));
|
||||
|
||||
int pDOP = myGNSS.getPDOP();
|
||||
Serial.print(F(" pDOP: "));
|
||||
Serial.print(pDOP / 100.0, 2); // Convert pDOP scaling from 0.01 to 1
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
Turn on/off various NMEA sentences.
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: January 3rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to turn on/off the NMEA sentences being output
|
||||
over UART1. We use the I2C interface on the u-blox module for configuration
|
||||
but you won't see any output from this sketch. You'll need to hook up
|
||||
a Serial Basic or other USB to Serial device to UART1 on your u-blox module
|
||||
to see the output.
|
||||
|
||||
This example turns off all sentences except for the GPGGA and GPVTG sentences.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a RedBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
Hookup a Serial Basic (https://www.sparkfun.com/products/15096) to UART1 on the u-blox module. Open a terminal at 57600bps
|
||||
and see GPGGA and GPVTG sentences.
|
||||
*/
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
unsigned long lastGNSSsend = 0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200); // Serial debug output over USB visible from Arduino IDE
|
||||
Serial.println("Example showing how to enable/disable certain NMEA sentences");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false)
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
//Disable or enable various NMEA sentences over the UART1 interface
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_UART1); //Several of these are on by default on ublox board so let's disable them
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_UART1);
|
||||
myGNSS.disableNMEAMessage(UBX_NMEA_RMC, COM_PORT_UART1);
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_UART1); //Only leaving GGA & VTG enabled at current navigation rate
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_VTG, COM_PORT_UART1);
|
||||
|
||||
//Here's the advanced configure method
|
||||
//Some of the other examples in this library enable the PVT message so let's disable it
|
||||
myGNSS.configureMessage(UBX_CLASS_NAV, UBX_NAV_PVT, COM_PORT_UART1, 0); //Message Class, ID, and port we want to configure, sendRate of 0 (disable).
|
||||
|
||||
myGNSS.setUART1Output(COM_TYPE_NMEA); //Turn off UBX and RTCM sentences on the UART1 interface
|
||||
|
||||
myGNSS.setSerialRate(57600); //Set UART1 to 57600bps.
|
||||
|
||||
//myGNSS.saveConfiguration(); //Optional: Save these settings to NVM
|
||||
|
||||
Serial.println(F("Messages configured. NMEA now being output over the UART1 port on the u-blox module at 57600bps."));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (millis() - lastGNSSsend > 200)
|
||||
{
|
||||
myGNSS.checkUblox(); //See if new data is available, but we don't want to get NMEA here. Go check UART1.
|
||||
lastGNSSsend = millis();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
Set update rate to 10Hz
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: January 3rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to increase the output of the module from 1Hz to 4Hz.
|
||||
The max output rate various from model to model. RTFM! But you cannot do harm
|
||||
to the module.
|
||||
|
||||
We also disable NMEA output on the I2C bus and use only UBX. This dramatically
|
||||
decreases the amount of data that needs to be transmitted.
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
unsigned long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
unsigned long startTime = 0; //Used to calc the actual update rate.
|
||||
unsigned long updateCount = 0; //Used to calc the actual update rate.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
// Increase I2C clock speed to 400kHz to cope with the high navigation rate
|
||||
// (We normally recommend running the bus at 100kHz)
|
||||
Wire.setClock(400000);
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.setNavigationFrequency(5); //Set output to 5 times a second
|
||||
|
||||
uint8_t rate = myGNSS.getNavigationFrequency(); //Get the update rate of this module
|
||||
Serial.print("Current update rate: ");
|
||||
Serial.println(rate);
|
||||
|
||||
startTime = millis();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Query module every 25 ms. Doing it more often will just cause I2C traffic.
|
||||
//The module only responds when a new position is available. This is defined
|
||||
//by the update freq.
|
||||
if (millis() - lastTime > 25)
|
||||
{
|
||||
lastTime = millis(); //Update the timer
|
||||
|
||||
long latitude = myGNSS.getLatitude();
|
||||
Serial.print(F("Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = myGNSS.getLongitude();
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
|
||||
updateCount++;
|
||||
|
||||
//Calculate the actual update rate based on the sketch start time and the
|
||||
//number of updates we've received.
|
||||
Serial.print(F(" Rate: "));
|
||||
Serial.print( updateCount / ((millis() - startTime) / 1000.0), 2);
|
||||
Serial.print(F("Hz"));
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Reading the protocol version of a u-blox module
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: January 3rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to query a u-blox module for its protocol version.
|
||||
|
||||
Various modules have various protocol version. We've seen v18 up to v27. Depending
|
||||
on the protocol version there are different commands available. This is a handy
|
||||
way to predict which commands will or won't work.
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
Serial.print(F("Version: "));
|
||||
byte versionHigh = myGNSS.getProtocolVersionHigh();
|
||||
Serial.print(versionHigh);
|
||||
Serial.print(".");
|
||||
byte versionLow = myGNSS.getProtocolVersionLow();
|
||||
Serial.print(versionLow);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
Reading the protocol version of a u-blox module
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: January 3rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to query a u-blox module for its protocol version.
|
||||
|
||||
Note: this may fail on boards like the UNO (ATmega328P) with modules like the ZED-F9P
|
||||
because getProtocolVersion returns a lot of data - more than the UNO's serial buffer can hold
|
||||
|
||||
Various modules have various protocol version. We've seen v18 up to v27. Depending
|
||||
on the protocol version there are different commands available. This is a handy
|
||||
way to predict which commands will or won't work.
|
||||
|
||||
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
#define mySerial Serial1 // Uncomment this line to connect via Serial1
|
||||
// - or -
|
||||
//SoftwareSerial mySerial(10, 11); // Uncomment this line to connect via SoftwareSerial(RX, TX). Connect pin 10 to GNSS TX pin.
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Serial.println("Trying 38400 baud");
|
||||
mySerial.begin(38400);
|
||||
if (myGNSS.begin(mySerial))
|
||||
{
|
||||
Serial.println("GNSS connected at 38400 baud");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Trying 9600 baud");
|
||||
mySerial.begin(9600);
|
||||
if (myGNSS.begin(mySerial))
|
||||
{
|
||||
Serial.println("GNSS connected at 9600 baud");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Could not connect to GNSS. Freezing...");
|
||||
while(1); // Do nothing more
|
||||
}
|
||||
}
|
||||
|
||||
Serial.print(F("Version: "));
|
||||
byte versionHigh = myGNSS.getProtocolVersionHigh();
|
||||
Serial.print(versionHigh);
|
||||
Serial.print(".");
|
||||
byte versionLow = myGNSS.getProtocolVersionLow();
|
||||
Serial.print(versionLow);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
Change the I2C address of a u-blox module using I2C
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: January 3rd, 2019
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example shows how to change the I2C address of a u-blox module
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
long lastTime = 0; //Tracks the passing of 2000ms (2 seconds)
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin();
|
||||
|
||||
byte oldAddress = 0x42; //The default address for u-blox modules is 0x42
|
||||
byte newAddress = 0x3F; //Address you want to change to. Valid is 0x08 to 0x77.
|
||||
|
||||
while (Serial.available()) Serial.read(); //Trash any incoming chars
|
||||
Serial.print("Press a key to change address to 0x");
|
||||
Serial.println(newAddress, HEX);
|
||||
while (Serial.available() == false) ; //Wait for user to send character
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
|
||||
|
||||
if (myGNSS.begin(Wire, oldAddress) == true) //Connect to the u-blox module using Wire port and the old address
|
||||
{
|
||||
Serial.print("GNSS found at address 0x");
|
||||
Serial.println(oldAddress, HEX);
|
||||
|
||||
myGNSS.setI2CAddress(newAddress); //Change I2C address of this device
|
||||
//Device's I2C address is stored to memory and loaded on each power-on
|
||||
|
||||
delay(2000); // Allow time for the change to take
|
||||
|
||||
if (myGNSS.begin(Wire, newAddress) == true)
|
||||
{
|
||||
myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
|
||||
|
||||
Serial.print("Address successfully changed to 0x");
|
||||
Serial.println(newAddress, HEX);
|
||||
Serial.print("Now load another example sketch using .begin(Wire, 0x");
|
||||
Serial.print(newAddress, HEX);
|
||||
Serial.println(") to use this GPS module");
|
||||
Serial.println("Freezing...");
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
|
||||
//Something went wrong, begin looking for the I2C device
|
||||
Serial.println("Address change probably failed. Beginning an I2C scan.");
|
||||
|
||||
Wire.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
byte address;
|
||||
int nDevices;
|
||||
|
||||
Serial.println("Scanning...");
|
||||
|
||||
nDevices = 0;
|
||||
for (address = 1; address < 127; address++ )
|
||||
{
|
||||
Wire.beginTransmission(address);
|
||||
byte error = Wire.endTransmission();
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
Serial.print("I2C device found at address 0x");
|
||||
if (address < 16)
|
||||
Serial.print("0");
|
||||
Serial.print(address, HEX);
|
||||
Serial.println(" !");
|
||||
|
||||
nDevices++;
|
||||
}
|
||||
// else if (error == 4)
|
||||
// {
|
||||
// Serial.print("Unknown error at address 0x");
|
||||
// if (address < 16)
|
||||
// Serial.print("0");
|
||||
// Serial.println(address, HEX);
|
||||
// }
|
||||
}
|
||||
|
||||
if (nDevices == 0)
|
||||
Serial.println("No I2C devices found\n");
|
||||
else
|
||||
Serial.println("done\n");
|
||||
|
||||
delay(5000); // wait 5 seconds for next scan
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
Send UBX binary commands to enable RTCM sentences on u-blox NEO-M8P module
|
||||
By: Nathan Seidle
|
||||
SparkFun Electronics
|
||||
Date: September 7th, 2018
|
||||
License: MIT. See license file for more information but you can
|
||||
basically do whatever you want with this code.
|
||||
|
||||
This example sends the command to enable the four RTCM messages needed for RTK. This
|
||||
is the first part of a larger tutorial and example to setup an RTK base station.
|
||||
These commands are only accepted by the NEO-M8P module.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
SAM-M8Q: https://www.sparkfun.com/products/15106
|
||||
|
||||
Hardware Connections:
|
||||
Plug a Qwiic cable into the GNSS and a BlackBoard
|
||||
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
|
||||
Open the serial monitor at 115200 baud to see the output
|
||||
*/
|
||||
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GNSS myGNSS;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while(!Serial); //Wait for user to open terminal
|
||||
Serial.println(F("u-blox RTCM Enable Example"));
|
||||
|
||||
Wire.begin();
|
||||
Wire.setClock(400000); //Increase I2C clock speed to 400kHz
|
||||
|
||||
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
while(Serial.available()) Serial.read(); //Clear any latent chars in serial buffer
|
||||
Serial.println(F("Press any key to send commands to enable RTCM 3.x"));
|
||||
while(Serial.available() == 0) ; //Wait for user to press a key
|
||||
|
||||
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_RTCM3); // Ensure RTCM3 is enabled
|
||||
myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
|
||||
|
||||
bool response = true;
|
||||
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1005, COM_PORT_I2C, 1); //Enable message 1005 to output through I2C port, message every second
|
||||
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1077, COM_PORT_I2C, 1);
|
||||
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1087, COM_PORT_I2C, 1);
|
||||
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1230, COM_PORT_I2C, 10); //Enable message every 10 seconds
|
||||
|
||||
if (response == true)
|
||||
{
|
||||
Serial.println(F("RTCM messages enabled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("RTCM failed to enable. Are you sure you have an NEO-M8P?"));
|
||||
while(1); //Freeze
|
||||
}
|
||||
|
||||
//RTCM is now enabled but we haven't done a 'survey-in'
|
||||
//See example 4 for the full Base RTK setup
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.
|
||||
|
||||
delay(250); //Don't pound too hard on the I2C bus
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue