Artemis Global Tracker Hookup Guide
Artemis Global Tracker Arduino Examples
The AGT ships with a comprehensive Global Tracker example pre-loaded on the board for users to get started quickly with the Artemis Global Tracker Configuration Tool so if you want to skip ahead and use the Configuration Tool, jump ahead to the next section.
Arduino Examples
We've written twenty examples for users to familiarize themselves with all of the hardware present on the Artemis Global Tracker using the Arduino IDE. The examples build on each other to quickly test functionality of different circuits on the AGT and demonstrate how to use the PHT sensor, ZOE-M8Q and 9603N individually with some highlighting features of these components as well as three examples showing how to create a tracking device using the AGT. Download the examples either from the GitHub repository or you can download a ZIP of the GitHub repo by clicking the button below:
Open the examples either from the folder they downloaded to or you can put them in your "Arduino Sketchbook" folder to open them in the Arduino IDE. If you're not certain where your Sketchbook folder is, open the "Preferences" menu in Arduino and look for the filepath under the selection titled "Sketchbook location".
Required Arduino Libraries
The Artemis Global Tracker examples use three SparkFun libraries users need to install prior to working with them:
Install the libraries through the Arduino Library Manager tool by searching for "IridiumSBDi2c", "SparkFun u-blox GNSS Arduino Library" and "SparkFun PHT MS8607 Arduino Library". Users who prefer to manually install the libraries can download the ZIP of each library repository by clicking the buttons below:
Arduino Examples
With the Artemis Arduino Core and necessary libraries installed we can move on to using the examples. This tutorial covers six of the Arduino examples we find most helpful to demonstrate how to use the major components on the AGT and then how to use them all in conjunction to create a global tracking device.
Users looking to write their own code for the AGT should take note of the following pin definitions and functions:
language:c
// D4 can be used as an SPI chip select or as a general purpose IO pin
#define spiCS1 4
// Input for the ZOE-M8Qs PIO14 (geofence) pin
#define geofencePin 10
// Bus voltage divided by 3 (Analog in)
#define busVoltagePin 13
// Iridium 9603N ON/OFF (sleep) pin: pull high to enable the 9603N
#define iridiumSleep 17
// Input for the Iridium 9603N Network Available
#define iridiumNA 18
// White LED
#define LED 19
// ADM4210 ON: pull high to enable power for the Iridium 9603N
#define iridiumPwrEN 22
// GNSS Enable: pull low to enable power for the GNSS (via Q2)
#define gnssEN 26
// LTC3225 super capacitor charger: pull high to enable the super capacitor charger
#define superCapChgEN 27
// Input for the LTC3225 super capacitor charger PGOOD signal
#define superCapPGOOD 28
// Bus voltage monitor enable: pull high to enable bus voltage monitoring (via Q4 and Q3)
#define busVoltageMonEN 34
// D35 can be used as an SPI chip select or as a general purpose IO pin
#define spiCS2 35
// Input for the Iridium 9603N Ring Indicator
#define iridiumRI 41
void gnssON(void) // Enable power for the GNSS
{
am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
pin_config(PinName(gnssEN), pinCfg);
delay(1);
digitalWrite(gnssEN, LOW); // Enable GNSS power (HIGH = disable; LOW = enable)
}
void gnssOFF(void) // Disable power for the GNSS
{
am_hal_gpio_pincfg_t pinCfg = g_AM_HAL_GPIO_OUTPUT; // Begin by making the gnssEN pin an open-drain output
pinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
pin_config(PinName(gnssEN), pinCfg);
delay(1);
digitalWrite(gnssEN, HIGH); // Disable GNSS power (HIGH = disable; LOW = enable)
}
void setup()
{
// Configure the I/O pins
pinMode(LED, OUTPUT);
pinMode(iridiumPwrEN, OUTPUT); // Configure the Iridium Power Pin (connected to the ADM4210 ON pin)
digitalWrite(iridiumPwrEN, LOW); // Disable Iridium Power
pinMode(superCapChgEN, OUTPUT); // Configure the super capacitor charger enable pin (connected to LTC3225 !SHDN)
digitalWrite(superCapChgEN, LOW); // Disable the super capacitor charger
gnssOFF(); // Disable power for the GNSS
pinMode(busVoltageMonEN, OUTPUT); // Make the Bus Voltage Monitor Enable an output
digitalWrite(busVoltageMonEN, HIGH); // Set it high to enable the measurement
//digitalWrite(busVoltageMonEN, LOW); // Set it low to disable the measurement (busV should be ~zero)
analogReadResolution(14); //Set resolution to 14 bit
Example 3 - PHT
The first example we'll take a look at is Example 3 - PHT. This example demonstrates how to interact with the MS8607 PHT Sensor to retrieve pressure, humidity and temperature data from the sensor. The code performs all of the AGT pin definitions and custom functions listed above and initializes the MS8607 on the I2C bus:
language:c
if (barometricSensor.begin(agtWire) == false)
{
Serial.println("MS8607 sensor did not respond. Trying again...");
if (barometricSensor.begin(agtWire) == false)
{
Serial.println("MS8607 sensor did not respond. Please check wiring.");
while(1)
;
}
}
After initializing the sensor, the code polls for temperature (in °C), pressure (in hPa or mbar) and humidity (in %RH) data from the sensor and prints it out over serial every 500ms. Open the serial monitor with the baud set to 115200 to watch the environmental data print out.
Users who prefer to use an external PHT sensor should refer to Example 4 - External PHT for a demonstration of that application.
Example 5 - GNSS
Example 5 shows how to use the ZOE-M8Q to get GNSS positioning data. Upload the example and open the serial terminal with the baud set to 115200 and input set to Newline. The setup initializes the Wire port and sets the clock speed to 100kHz for optimal performance:
language:c
agtWire.begin();
agtWire.setClock(100000);
Before initializing the ZOE-M8Q, the code waits for a user input to confirm the serial monitor settings are correct. After user input, the code turns the ZOE-M8Q on, waits one second for the module to power up, initializes it on the I2C bus, and sets it to output only UBX data:
language:c
Serial.println(F("Please check that the Serial Monitor is set to 115200 Baud"));
Serial.println(F("and that the line ending is set to Newline."));
Serial.println(F("Then click Send to start the example."));
Serial.println();
while(Serial.available() == 0)
;
gnssON(); // Enable power for the GNSS
delay(1000); // Let the ZOE power up
if (myGNSS.begin(agtWire) == false) //Connect to the u-blox module using pads 8 & 9
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
//myGNSS.factoryDefault(); delay(5000); // Uncomment this line to reset the ZOE-M8Q to the factory defaults
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
myGNSS.setI2COutput(COM_TYPE_UBX);
The main loop checks for the GNSS fix and prints out what type of fix the module has (Dead Reckoning, 2D, 3D or GNSS+Dead Reckoning). Once the ZOE-M8Q has a GNSS fix the code pulls and prints out latitude, longitude and altitude data from the module.
The two commented out lines allow the user to reset the ZOE-M8Q to factory defaults and enable serial debugging. Sending the factory default command can help recover the ZOE-M8Q in case it gets stuck in an unresponsive state. Enabling serial debugging tells the ZOE-M8Q to send all debug data over serial for troubleshooting.
Example 6 - Geofence
Example 6 builds on the previous example to set up four geofence areas for the ZOE-M8Q to monitor. The code sets everything up just like the previous GNSS example. When the module finds a 3D fix, the code prints the longitude and latitude, creates settings for the four geofence areas, clears any existing geofences stored and then sets four geofence areas of 5m, 10m, 15m and 20m:
language:c
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%
byte pinPolarity = 0; // Set the PIO pin polarity: 0 = low means inside, 1 = low means outside (or unknown)
byte pin = 14; // ZOE-M8Q PIO14 is connected to the geofencePin
Serial.print(F("Clearing any existing geofences. clearGeofences returned: "));
Serial.println(myGNSS.clearGeofences());
Serial.print(F("addGeofence for geofence 1 returned: "));
Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence, pinPolarity, pin));
radius = 1000; // 10m
Serial.print(F("addGeofence for geofence 2 returned: "));
Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence, pinPolarity, pin));
radius = 1500; // 15m
Serial.print(F("addGeofence for geofence 3 returned: "));
Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence, pinPolarity, pin));
radius = 2000; // 20m
Serial.print(F("addGeofence for geofence 4 returned: "));
Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence, pinPolarity, pin));
The main loop monitors the state of the four geofences and prints out both the combined and individual status of the geofences every second:
language:c
geofenceState currentGeofenceState; // Create storage for the geofence state
boolean 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
}
// Print the Geofencing status
// 0 - Geofencing not available or not reliable; 1 - Geofencing active
Serial.print(F(". status is: "));
Serial.print(currentGeofenceState.status);
// Print the numFences
Serial.print(F(". numFences is: "));
Serial.print(currentGeofenceState.numFences);
// Print the combined state
// Combined (logical OR) state of all geofences: 0 - Unknown; 1 - Inside; 2 - Outside
Serial.print(F(". combState is: "));
Serial.print(currentGeofenceState.combState);
// Print the state of each geofence
// 0 - Unknown; 1 - Inside; 2 - Outside
Serial.print(F(". The individual states are: "));
for(int i = 0; i < currentGeofenceState.numFences; i++)
{
if (i > 0) Serial.print(F(","));
Serial.print(currentGeofenceState.states[i]);
}
byte fenceStatus = digitalRead(geofencePin); // Read the geofence pin
digitalWrite(LED, !fenceStatus); // Set the LED (inverted)
Serial.print(F(". Geofence pin (PIO14) is: ")); // Print the pin state
Serial.print(fenceStatus);
Serial.println(F("."));
delay(1000);
The on-board LED is configured to illuminate when the AGT is inside the combined geofence areas and will go out when the AGT is outside them to provide a visual indicator for quickly identifying the geofence area limits.
Example 10 - Basic Send
Example 10 demonstrates how to perform a basic data transmission using the 9603N to send the classic "Hello, world!" over the Iridium satellite network. The code declares the IridiumSBD
object with the sleep (ON/OFF) and RI (Ring Indicator) pins and creates two functions to set up and control Artemis Serial1 to communicate with the 9603N modem:
language:c
IridiumSBD modem(Serial1, iridiumSleep, iridiumRI);
void IridiumSBD::beginSerialPort() // Start the serial port connected to the satellite modem
{
diagprint(F("custom IridiumSBD::beginSerialPort\r\n"));
// Configure the standard ATP pins for UART1 TX and RX - endSerialPort may have disabled the RX pin
am_hal_gpio_pincfg_t pinConfigTx = g_AM_BSP_GPIO_COM_UART_TX;
pinConfigTx.uFuncSel = AM_HAL_PIN_24_UART1TX;
pin_config(D24, pinConfigTx);
am_hal_gpio_pincfg_t pinConfigRx = g_AM_BSP_GPIO_COM_UART_RX;
pinConfigRx.uFuncSel = AM_HAL_PIN_25_UART1RX;
pinConfigRx.ePullup = AM_HAL_GPIO_PIN_PULLUP_WEAK; // Put a weak pull-up on the Rx pin
pin_config(D25, pinConfigRx);
Serial1.begin(19200);
}
void IridiumSBD::endSerialPort()
{
diagprint(F("custom IridiumSBD::endSerialPort\r\n"));
// Disable the Serial1 RX pin to avoid the code hang
am_hal_gpio_pinconfig(PinName(D25), g_AM_HAL_GPIO_DISABLE);
}
After uploading the code, open the serial monitor with the baud set to 115200. The code waits for the user to open the serial monitor and press send before continuing with the rest of the sketch. After the input, the code enables the supercapacitor charger, begins the charge cycle and then attempts to initialize the 9603N once the charge cycle is complete. Serial prints accompany all these functions for users to follow along with.
Assuming the 9603N initialized correctly, the code checks the signal quality, prints out a value between 0 and 5 (5 being the strongest signal quality) and then attempts to send a text message of "Hello, world!" over the network. This may take several minutes, if the message was sent successfully, the code prints "Hey, it worked!" otherwise, the code prints "Try again with a better view of the sky.".
Regardless of success or failure of sending the text message, the code finishes by clearing the Mobile Originated message buffer, puts the 9603N to sleep and then disables power to the 9603N and supercapacitor charge circuit. Note, this code is not a loop and if it fails, you'll need to reset the AGT before attempting again.
Example 16 - Global Tracker
The last example this tutorial combines everything together to provide a comprehensive global tracker capable of receiving a host of settings updates either via USB-C or wirelessly using Iridium SBD messages. This means users can monitor and configure the device depending on the application's needs while the AGT is in the field.
The example gets a 3D fix from the ZOE-M8Q, environmental readings from the MS8607, measures the bus voltage, and transmits the data at a set interval via Iridium SBD messages. The code also stores many settings in EEPROM (Flash) to be configured either via the USB port or an Iridium binary message sent from Rock7 Operations.
On top of all that, the example includes the capability for users to add up to eight custom functions for additional sensor or other devices in use with the AGT. For those curious about the message format, please review this page in the GitHub repository.
The code defaults to send a text message every five minutes of the following data fields:
- DATETIME: GNSS date and time in YYYYMMDDHHMMSS format
- LAT: GNSS latitude in degrees
- LON: GNSS longitude in degrees
- ALT: GNSS altitude above mean sea level in meters
This example works in tandem with the Artemis Global Tracker Configuration Tool we cover in the next section.