Using the NavX3
StudicaLib​
NavX3 Libraries ship with the StudicaLib vendordep. Install the vendordep through the WPILib Vendor Dependencies plugin. The WPILib documentation has a great guide that walks through the process.
info
Always use the latest version.
Adding to WPILib Projects​
Adding NavX3 to a project takes only a few steps.
Import Declaration and Include Directive​
- Java
- C++
import com.studica.frc.Navx;
#include "studica/Navx.h"
Object Declaration​
- Java
- C++
private Navx navx;
studica::Navx navx{0, 100};
tip
For C++ declare and initialize the object at the same time. The NavX3 here is defined with a CAN ID of 0 and an update rate of 100 Hz.
Create the instance​
- Java
- C++
navx = new Navx(0, 100);
NavX3 Object initialized with CAN ID of 0 and an update rate of 100 Hz.
No separate constructor call is needed in C++ because the object was constructed at the point of declaration using direct initialization.
Full example using Default Project​
- Java
- C++
Robot.java
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package frc.robot;
import edu.wpi.first.wpilibj.TimedRobot;
import edu.wpi.first.wpilibj.simulation.SimDeviceSim;
import edu.wpi.first.wpilibj.smartdashboard.SendableChooser;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import edu.wpi.first.math.geometry.Quaternion;
import edu.wpi.first.units.measure.AngularVelocity;
import edu.wpi.first.units.measure.LinearAcceleration;
import static edu.wpi.first.units.Units.Celsius;
import static edu.wpi.first.units.Units.Degrees;
import static edu.wpi.first.units.Units.DegreesPerSecond;
import static edu.wpi.first.units.Units.MetersPerSecondPerSecond;
import com.studica.frc.Navx;
/**
* The methods in this class are called automatically corresponding to each mode, as described in
* the TimedRobot documentation. If you change the name of this class or the package after creating
* this project, you must also update the Main.java file in the project.
*/
public class Robot extends TimedRobot {
private static final String kDefaultAuto = "Default";
private static final String kCustomAuto = "My Auto";
private String m_autoSelected;
private final SendableChooser<String> m_chooser = new SendableChooser<>();
private Navx navx;
private SimDeviceSim device;
/**
* This function is run when the robot is first started up and should be used for any
* initialization code.
*/
public Robot() {
m_chooser.setDefaultOption("Default Auto", kDefaultAuto);
m_chooser.addOption("My Auto", kCustomAuto);
SmartDashboard.putData("Auto choices", m_chooser);
// Create NavX Object
navx = new Navx(0, 100); // CAN
// navx = new Navx(Navx.Port.kUSB1); // USB
// Create Sim Object
device = new SimDeviceSim("NavX3", 0);
// You can enable which messages the navx sends to prevent bus saturation
navx.enableOptionalMessages(true,
true,
true,
true,
true,
true,
true,
true,
true,
true);
// UUID of the navx if thats something you want
int[] uuids = new int[3];
navx.getSensorUUID(uuids);
SmartDashboard.putNumber("uuid0", uuids[0]);
SmartDashboard.putNumber("uuid1", uuids[1]);
SmartDashboard.putNumber("uuid2", uuids[2]);
// Add reset yaw btn to dashboard
SmartDashboard.putBoolean("Reset Yaw", false);
}
/**
* This function is called every 20 ms, no matter the mode. Use this for items like diagnostics
* that you want ran during disabled, autonomous, teleoperated and test.
*
* <p>This runs after the mode specific periodic functions, but before LiveWindow and
* SmartDashboard integrated updating.
*/
@Override
public void robotPeriodic()
{
// Yaw, Pitch, Roll, Angle
SmartDashboard.putNumber("Yaw:", navx.getYaw().in(Degrees));
SmartDashboard.putNumber("Pitch:", navx.getPitch().in(Degrees));
SmartDashboard.putNumber("Roll:", navx.getRoll().in(Degrees));
SmartDashboard.putNumber("Angle:", navx.getAngle().in(Degrees));
// 6-axis quaternion
Quaternion quat = navx.getQuat6D();
SmartDashboard.putNumber("q6_w:", quat.getW());
SmartDashboard.putNumber("q6_x:", quat.getX());
SmartDashboard.putNumber("q6_y:", quat.getY());
SmartDashboard.putNumber("q6_z:", quat.getZ());
// Angular Velocity
AngularVelocity[] omega = navx.getAngularVel();
SmartDashboard.putNumber("w_x:", omega[0].in(DegreesPerSecond));
SmartDashboard.putNumber("w_y:", omega[1].in(DegreesPerSecond));
SmartDashboard.putNumber("w_z:", omega[2].in(DegreesPerSecond));
// 9-axis quaternion
Quaternion quat9 = navx.getQuat9D();
SmartDashboard.putNumber("q9_w:", quat9.getW());
SmartDashboard.putNumber("q9_x:", quat9.getX());
SmartDashboard.putNumber("q9_y:", quat9.getY());
SmartDashboard.putNumber("q9_z:", quat9.getZ());
// Linear Acceleration
LinearAcceleration[] accel = navx.getLinearAccel();
SmartDashboard.putNumber("v_x:", accel[0].in(MetersPerSecondPerSecond));
SmartDashboard.putNumber("v_y:", accel[1].in(MetersPerSecondPerSecond));
SmartDashboard.putNumber("v_z:", accel[2].in(MetersPerSecondPerSecond));
// Get Compass reading from Mag
float[] mag = new float[4];
int error = navx.getCompass(mag);
SmartDashboard.putNumber("mag_1:", mag[0]);
SmartDashboard.putNumber("mag_2:", mag[1]);
SmartDashboard.putNumber("mag_3:", mag[2]);
SmartDashboard.putNumber("mag_4:", mag[3]);
// Temperature reported by IMU
SmartDashboard.putNumber("temp:", navx.getTemperature().in(Celsius));
if (SmartDashboard.getBoolean("Reset Yaw", false))
{
navx.resetYaw();
SmartDashboard.putBoolean("Reset Yaw", false);
}
}
/**
* This autonomous (along with the chooser code above) shows how to select between different
* autonomous modes using the dashboard. The sendable chooser code works with the Java
* SmartDashboard. If you prefer the LabVIEW Dashboard, remove all of the chooser code and
* uncomment the getString line to get the auto name from the text box below the Gyro
*
* <p>You can add additional auto modes by adding additional comparisons to the switch structure
* below with additional strings. If using the SendableChooser make sure to add them to the
* chooser code above as well.
*/
@Override
public void autonomousInit() {
m_autoSelected = m_chooser.getSelected();
// m_autoSelected = SmartDashboard.getString("Auto Selector", kDefaultAuto);
System.out.println("Auto selected: " + m_autoSelected);
}
/** This function is called periodically during autonomous. */
@Override
public void autonomousPeriodic() {
switch (m_autoSelected) {
case kCustomAuto:
// Put custom auto code here
break;
case kDefaultAuto:
default:
// Put default auto code here
break;
}
}
/** This function is called once when teleop is enabled. */
@Override
public void teleopInit() {}
/** This function is called periodically during operator control. */
@Override
public void teleopPeriodic() {}
/** This function is called once when the robot is disabled. */
@Override
public void disabledInit() {}
/** This function is called periodically when disabled. */
@Override
public void disabledPeriodic() {}
/** This function is called once when test mode is enabled. */
@Override
public void testInit() {}
/** This function is called periodically during test mode. */
@Override
public void testPeriodic() {}
/** This function is called once when the robot is first started up. */
@Override
public void simulationInit() {}
/** This function is called periodically whilst in simulation. */
@Override
public void simulationPeriodic() {}
}
- C++ Header
- C++ Source
Robot.h
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <string>
#include <frc/TimedRobot.h>
#include <frc/smartdashboard/SendableChooser.h>
#include "studica/Navx.h"
#include "frc/simulation/SimDeviceSim.h"
class Robot : public frc::TimedRobot {
public:
Robot();
void RobotPeriodic() override;
void AutonomousInit() override;
void AutonomousPeriodic() override;
void TeleopInit() override;
void TeleopPeriodic() override;
void DisabledInit() override;
void DisabledPeriodic() override;
void TestInit() override;
void TestPeriodic() override;
void SimulationInit() override;
void SimulationPeriodic() override;
private:
frc::SendableChooser<std::string> m_chooser;
const std::string kAutoNameDefault = "Default";
const std::string kAutoNameCustom = "My Auto";
std::string m_autoSelected;
studica::Navx navx{0, 100}; // CAN bus
// studica::Navx navx{studica::Navx::Port::kUSB1, 100}; // USB
frc::sim::SimDeviceSim device{"NavX3", 0};
};
Robot.cpp
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "Robot.h"
#include <frc/smartdashboard/SmartDashboard.h>
#include <wpi/print.h>
Robot::Robot() {
m_chooser.SetDefaultOption(kAutoNameDefault, kAutoNameDefault);
m_chooser.AddOption(kAutoNameCustom, kAutoNameCustom);
frc::SmartDashboard::PutData("Auto Modes", &m_chooser);
// You can enable which messages the navx sends to prevent bus saturation
navx.EnableOptionalMessages(true, true, true, true, true, true, true, true, true);
// UUID of the navx if thats something you want
int uuids[3] = {0};
navx.GetSensorUUID(uuids);
frc::SmartDashboard::PutNumber("uuid0", uuids[0]);
frc::SmartDashboard::PutNumber("uuid1", uuids[1]);
frc::SmartDashboard::PutNumber("uuid2", uuids[2]);
// Zero Yaw Btn
frc::SmartDashboard::PutBoolean("Reset Yaw", false);
}
/**
* This function is called every 20 ms, no matter the mode. Use
* this for items like diagnostics that you want ran during disabled,
* autonomous, teleoperated and test.
*
* <p> This runs after the mode specific periodic functions, but before
* LiveWindow and SmartDashboard integrated updating.
*/
void Robot::RobotPeriodic()
{
int error;
// Yaw, Pitch, Roll, Angle
frc::SmartDashboard::PutNumber("Yaw:", navx.GetYaw().value());
frc::SmartDashboard::PutNumber("Pitch:", navx.GetPitch().value());
frc::SmartDashboard::PutNumber("Roll:", navx.GetRoll().value());
frc::SmartDashboard::PutNumber("Angle:", navx.GetAngle().value());
// 6-axis quaternion
frc::Quaternion quat6{};
error = navx.GetQuat6D(quat6);
frc::SmartDashboard::PutNumber("q6_w:", quat6.W());
frc::SmartDashboard::PutNumber("q6_x:", quat6.X());
frc::SmartDashboard::PutNumber("q6_y:", quat6.Y());
frc::SmartDashboard::PutNumber("q6_z:", quat6.Z());
// Angular Velocity
units::degrees_per_second_t wx{0}, wy{0}, wz{0};
error = navx.GetAngularVel(wx, wy, wz);
frc::SmartDashboard::PutNumber("w_x:", wx.value());
frc::SmartDashboard::PutNumber("w_y:", wy.value());
frc::SmartDashboard::PutNumber("w_z:", wz.value());
// 9-axis quaternion
frc::Quaternion quat9{};
error = navx.GetQuat9D(quat9);
frc::SmartDashboard::PutNumber("q9_w:", quat6.W());
frc::SmartDashboard::PutNumber("q9_x:", quat6.X());
frc::SmartDashboard::PutNumber("q9_y:", quat6.Y());
frc::SmartDashboard::PutNumber("q9_z:", quat6.Z());
// Linear Acceleration
units::meters_per_second_squared_t ax{0}, ay{0}, az{0};
error = navx.GetLinearAccel(ax, ay, az);
frc::SmartDashboard::PutNumber("a_x:", ax.value());
frc::SmartDashboard::PutNumber("a_y:", ay.value());
frc::SmartDashboard::PutNumber("a_z:", az.value());
// Get Compass reading from Mag
units::tesla_t mx{0}, my{0}, mz{0}, mnorm{0};
error = navx.GetCompass(mx, my, mz, mnorm);
frc::SmartDashboard::PutNumber("mag_x_ut:", mx.value() * 1e-6);
frc::SmartDashboard::PutNumber("mag_y_ut:", my.value() * 1e-6);
frc::SmartDashboard::PutNumber("mag_z_ut:", mz.value() * 1e-6);
frc::SmartDashboard::PutNumber("mag_norm_ut:", mnorm.value() * 1e-6);
// Temperature reported by IMU
frc::SmartDashboard::PutNumber("temp:", navx.GetTemperature().value());
// Zero Yaw if btn pushed
if (frc::SmartDashboard::GetBoolean("Reset Yaw", false))
{
navx.ResetYaw();
frc::SmartDashboard::PutBoolean("Reset Yaw", false);
}
}
/**
* This autonomous (along with the chooser code above) shows how to select
* between different autonomous modes using the dashboard. The sendable chooser
* code works with the Java SmartDashboard. If you prefer the LabVIEW Dashboard,
* remove all of the chooser code and uncomment the GetString line to get the
* auto name from the text box below the Gyro.
*
* You can add additional auto modes by adding additional comparisons to the
* if-else structure below with additional strings. If using the SendableChooser
* make sure to add them to the chooser code above as well.
*/
void Robot::AutonomousInit() {
m_autoSelected = m_chooser.GetSelected();
// m_autoSelected = SmartDashboard::GetString("Auto Selector",
// kAutoNameDefault);
wpi::print("Auto selected: {}\n", m_autoSelected);
if (m_autoSelected == kAutoNameCustom) {
// Custom Auto goes here
} else {
// Default Auto goes here
}
}
void Robot::AutonomousPeriodic() {
if (m_autoSelected == kAutoNameCustom) {
// Custom Auto goes here
} else {
// Default Auto goes here
}
}
void Robot::TeleopInit() {}
void Robot::TeleopPeriodic() {}
void Robot::DisabledInit() {}
void Robot::DisabledPeriodic() {}
void Robot::TestInit() {}
void Robot::TestPeriodic() {}
void Robot::SimulationInit() {}
void Robot::SimulationPeriodic() {}
#ifndef RUNNING_FRC_TESTS
int main() {
return frc::StartRobot<Robot>();
}
#endif