Implement sim devices for ADXL345, ADXL362, ADXRS450, Ultrasonic

This makes the halsim_adx_gyro_accelerometer simulation plugin and
the accelerometer part of lowfi_simulation obsolete.
This commit is contained in:
Peter Johnson
2019-09-29 00:57:16 -07:00
parent aa90645865
commit a9f0e46680
42 changed files with 371 additions and 1337 deletions

View File

@@ -24,7 +24,6 @@ include 'wpilibjIntegrationTests'
include 'wpilibj'
include 'simulation:halsim_print'
include 'simulation:halsim_lowfi'
include 'simulation:halsim_adx_gyro_accelerometer'
include 'simulation:halsim_ds_nt'
include 'simulation:gz_msgs'
include 'simulation:frc_gazebo_plugins'

View File

@@ -1,199 +0,0 @@
apply plugin: 'cpp'
apply plugin: 'google-test-test-suite'
apply plugin: 'visual-studio'
apply plugin: 'edu.wpi.first.NativeUtils'
apply plugin: SingleNativeBuild
apply plugin: ExtraTasks
ext {
nativeName = 'halsim_adx_gyro_accelerometer'
}
apply from: "${rootDir}/shared/config.gradle"
if (!project.hasProperty('onlylinuxathena')) {
ext.skiplinuxathena = true
ext {
sharedCvConfigs = [halsim_adx_gyro_accelerometerTest: []]
staticCvConfigs = [:]
useJava = false
useCpp = true
}
apply from: "${rootDir}/shared/opencv.gradle"
ext {
staticGtestConfigs = [:]
}
staticGtestConfigs["${nativeName}Test"] = []
apply from: "${rootDir}/shared/googletest.gradle"
project(':').libraryBuild.dependsOn build
ext {
chipObjectComponents = ["$nativeName".toString(), "${nativeName}Base".toString(), "${nativeName}Dev".toString(), "${nativeName}Test".toString()]
netCommComponents = ["$nativeName".toString(), "${nativeName}Base".toString(), "${nativeName}Dev".toString(), "${nativeName}Test".toString()]
useNiJava = false
}
apply from: "${rootDir}/shared/nilibraries.gradle"
nativeUtils.exportsConfigs {
halsim_adx_gyro_accelerometer {
x86ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
'_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
'_TI5?AVfailure', '_CT??_R0?AVout_of_range', '_CTA3?AVout_of_range',
'_TI3?AVout_of_range', '_CT??_R0?AVbad_cast']
x64ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
'_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
'_TI5?AVfailure', '_CT??_R0?AVout_of_range', '_CTA3?AVout_of_range',
'_TI3?AVout_of_range', '_CT??_R0?AVbad_cast']
}
}
model {
components {
"${nativeName}Base"(NativeLibrarySpec) {
sources {
cpp {
source {
srcDirs = ['src/main/native/cpp']
include '**/*.cpp'
}
exportedHeaders {
srcDirs 'src/main/native/include'
}
}
}
binaries.all {
if (it instanceof SharedLibraryBinarySpec) {
it.buildable = false
return
}
if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
it.buildable = false
return
}
project(':hal').addHalDependency(it, 'shared')
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
}
}
"${nativeName}"(NativeLibrarySpec) {
sources {
cpp {
source {
srcDirs "${rootDir}/shared/singlelib"
include '**/*.cpp'
}
exportedHeaders {
srcDirs 'src/main/native/include'
}
}
}
binaries.all {
if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
it.buildable = false
return
}
project(':hal').addHalDependency(it, 'shared')
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
}
}
// By default, a development executable will be generated. This is to help the case of
// testing specific functionality of the library.
"${nativeName}Dev"(NativeExecutableSpec) {
targetBuildTypes 'debug'
sources {
cpp {
source {
srcDirs 'src/dev/native/cpp'
include '**/*.cpp'
lib library: "${nativeName}"
}
exportedHeaders {
srcDirs 'src/dev/native/include'
}
}
}
binaries.all {
if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
it.buildable = false
return
}
project(':hal').addHalDependency(it, 'shared')
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
lib library: nativeName, linkage: 'shared'
}
}
}
binaries {
withType(GoogleTestTestSuiteBinarySpec) {
if (!project.hasProperty('onlylinuxathena') && !project.hasProperty('onlylinuxraspbian') && !project.hasProperty('onlylinuxaarch64bionic')) {
lib project: ':ntcore', library: 'ntcore', linkage: 'shared'
lib project: ':cscore', library: 'cscore', linkage: 'shared'
project(':hal').addHalDependency(it, 'shared')
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
lib project: ':cameraserver', library: 'cameraserver', linkage: 'shared'
lib project: ':wpilibc', library: 'wpilibc', linkage: 'shared'
lib library: nativeName, linkage: 'shared'
} else {
it.buildable = false
}
}
}
}
apply from: "publish.gradle"
}
model {
testSuites {
if (!project.hasProperty('onlylinuxathena') && !project.hasProperty('onlylinuxraspbian') && !project.hasProperty('onlylinuxaarch64bionic')) {
"${nativeName}Test"(GoogleTestTestSuiteSpec) {
for(NativeComponentSpec c : $.components) {
if (c.name == nativeName) {
testing c
break
}
}
sources {
cpp {
source {
srcDirs 'src/test/native/cpp'
include '**/*.cpp'
}
exportedHeaders {
srcDirs 'src/test/native/include', 'src/main/native/cpp'
}
}
}
}
}
}
tasks {
def c = $.components
project.tasks.create('runCpp', Exec) {
def found = false
c.each {
if (it in NativeExecutableSpec && it.name == "${nativeName}Dev") {
it.binaries.each {
if (!found) {
def arch = it.targetPlatform.architecture.name
if (arch == 'x86-64' || arch == 'x86') {
dependsOn it.tasks.install
commandLine it.tasks.install.runScriptFile.get().asFile.toString()
found = true
}
}
}
}
}
}
}
}
tasks.withType(RunTestExecutable) {
args "--gtest_output=xml:test_detail.xml"
outputs.dir outputDir
}

View File

@@ -1,63 +0,0 @@
apply plugin: 'maven-publish'
def baseArtifactId = nativeName
def artifactGroupId = 'edu.wpi.first.halsim'
def zipBaseName = "_GROUP_edu_wpi_first_halsim_ID_${nativeName}_CLS"
def outputsFolder = file("$project.buildDir/outputs")
task cppSourcesZip(type: Zip) {
destinationDir = outputsFolder
baseName = zipBaseName
classifier = "sources"
from(licenseFile) {
into '/'
}
from('src/main/native/cpp') {
into '/'
}
}
task cppHeadersZip(type: Zip) {
destinationDir = outputsFolder
baseName = zipBaseName
classifier = "headers"
from(licenseFile) {
into '/'
}
from('src/main/native/include') {
into '/'
}
}
build.dependsOn cppSourcesZip
build.dependsOn cppHeadersZip
addTaskToCopyAllOutputs(cppSourcesZip)
addTaskToCopyAllOutputs(cppHeadersZip)
model {
publishing {
def halsim_adx_gyro_accelerometerTaskList = createComponentZipTasks($.components, [nativeName], zipBaseName, Zip, project, includeStandardZipFormat)
publications {
cpp(MavenPublication) {
halsim_adx_gyro_accelerometerTaskList.each {
artifact it
}
artifact cppHeadersZip
artifact cppSourcesZip
artifactId = baseArtifactId
groupId artifactGroupId
version wpilibVersioning.version.get()
}
}
}
}

View File

@@ -1,8 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
int main() {}

View File

@@ -1,73 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "ADXL345_I2CAccelerometerData.h"
#include <cstring>
#include <mockdata/I2CData.h>
using namespace hal;
const double ADXL345_I2CData::LSB = 1 / 0.00390625;
static void ADXL345I2C_ReadBufferCallback(const char* name, void* param,
uint8_t* buffer, uint32_t count) {
ADXL345_I2CData* sim = static_cast<ADXL345_I2CData*>(param);
sim->HandleRead(buffer, count);
}
static void ADXL345I2C_WriteBufferCallback(const char* name, void* param,
const uint8_t* buffer,
uint32_t count) {
ADXL345_I2CData* sim = static_cast<ADXL345_I2CData*>(param);
sim->HandleWrite(buffer, count);
}
ADXL345_I2CData::ADXL345_I2CData(int port) : m_port(port) {
m_readCallbackId =
HALSIM_RegisterI2CReadCallback(port, ADXL345I2C_ReadBufferCallback, this);
m_writeCallbackId = HALSIM_RegisterI2CWriteCallback(
port, ADXL345I2C_WriteBufferCallback, this);
}
ADXL345_I2CData::~ADXL345_I2CData() {
HALSIM_CancelI2CReadCallback(m_port, m_readCallbackId);
HALSIM_CancelI2CWriteCallback(m_port, m_writeCallbackId);
}
bool ADXL345_I2CData::GetInitialized() const {
return HALSIM_GetI2CInitialized(m_port);
}
void ADXL345_I2CData::ADXL345_I2CData::HandleWrite(const uint8_t* buffer,
uint32_t count) {
m_lastWriteAddress = buffer[0];
}
void ADXL345_I2CData::HandleRead(uint8_t* buffer, uint32_t count) {
bool writeAll = count == 6;
int byteIndex = 0;
if (writeAll || m_lastWriteAddress == 0x32) {
int16_t val = static_cast<int16_t>(GetX() * LSB);
std::memcpy(&buffer[byteIndex], &val, sizeof(val));
byteIndex += sizeof(val);
}
if (writeAll || m_lastWriteAddress == 0x34) {
int16_t val = static_cast<int16_t>(GetY() * LSB);
std::memcpy(&buffer[byteIndex], &val, sizeof(val));
byteIndex += sizeof(val);
}
if (writeAll || m_lastWriteAddress == 0x36) {
int16_t val = static_cast<int16_t>(GetZ() * LSB);
std::memcpy(&buffer[byteIndex], &val, sizeof(val));
byteIndex += sizeof(val);
}
}

View File

@@ -1,73 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "ADXL345_SpiAccelerometerData.h"
#include <cstring>
#include <mockdata/SPIData.h>
using namespace hal;
const double ADXL345_SpiAccelerometer::LSB = 1 / 0.00390625;
static void ADXL345SPI_ReadBufferCallback(const char* name, void* param,
uint8_t* buffer, uint32_t count) {
ADXL345_SpiAccelerometer* sim = static_cast<ADXL345_SpiAccelerometer*>(param);
sim->HandleRead(buffer, count);
}
static void ADXL345SPI_WriteBufferCallback(const char* name, void* param,
const uint8_t* buffer,
uint32_t count) {
ADXL345_SpiAccelerometer* sim = static_cast<ADXL345_SpiAccelerometer*>(param);
sim->HandleWrite(buffer, count);
}
ADXL345_SpiAccelerometer::ADXL345_SpiAccelerometer(int port) : m_port(port) {
m_readCallbackId =
HALSIM_RegisterSPIReadCallback(port, ADXL345SPI_ReadBufferCallback, this);
m_writeCallbackId = HALSIM_RegisterSPIWriteCallback(
port, ADXL345SPI_WriteBufferCallback, this);
}
ADXL345_SpiAccelerometer::~ADXL345_SpiAccelerometer() {
HALSIM_CancelSPIReadCallback(m_port, m_readCallbackId);
HALSIM_CancelSPIWriteCallback(m_port, m_writeCallbackId);
}
bool ADXL345_SpiAccelerometer::GetInitialized() const {
return HALSIM_GetSPIInitialized(m_port);
}
void ADXL345_SpiAccelerometer::HandleWrite(const uint8_t* buffer,
uint32_t count) {
m_lastWriteAddress = buffer[0] & 0xF;
}
void ADXL345_SpiAccelerometer::HandleRead(uint8_t* buffer, uint32_t count) {
bool writeAll = count == 7;
int byteIndex = 1;
if (writeAll || m_lastWriteAddress == 0x02) {
int16_t val = static_cast<int16_t>(GetX() * LSB);
std::memcpy(&buffer[byteIndex], &val, sizeof(val));
byteIndex += sizeof(val);
}
if (writeAll || m_lastWriteAddress == 0x04) {
int16_t val = static_cast<int16_t>(GetY() * LSB);
std::memcpy(&buffer[byteIndex], &val, sizeof(val));
byteIndex += sizeof(val);
}
if (writeAll || m_lastWriteAddress == 0x06) {
int16_t val = static_cast<int16_t>(GetZ() * LSB);
std::memcpy(&buffer[byteIndex], &val, sizeof(val));
byteIndex += sizeof(val);
}
}

View File

@@ -1,79 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "ADXL362_SpiAccelerometerData.h"
#include <cstring>
#include <mockdata/SPIData.h>
using namespace hal;
const double ADXL362_SpiAccelerometer::LSB = 1 / 0.001;
static void ADXL362SPI_ReadBufferCallback(const char* name, void* param,
uint8_t* buffer, uint32_t count) {
ADXL362_SpiAccelerometer* sim = static_cast<ADXL362_SpiAccelerometer*>(param);
sim->HandleRead(buffer, count);
}
static void ADXL362SPI_WriteBufferCallback(const char* name, void* param,
const uint8_t* buffer,
uint32_t count) {
ADXL362_SpiAccelerometer* sim = static_cast<ADXL362_SpiAccelerometer*>(param);
sim->HandleWrite(buffer, count);
}
ADXL362_SpiAccelerometer::ADXL362_SpiAccelerometer(int port) : m_port(port) {
m_readCallbackId =
HALSIM_RegisterSPIReadCallback(port, ADXL362SPI_ReadBufferCallback, this);
m_writeCallbackId = HALSIM_RegisterSPIWriteCallback(
port, ADXL362SPI_WriteBufferCallback, this);
}
ADXL362_SpiAccelerometer::~ADXL362_SpiAccelerometer() {
HALSIM_CancelSPIReadCallback(m_port, m_readCallbackId);
HALSIM_CancelSPIWriteCallback(m_port, m_writeCallbackId);
}
bool ADXL362_SpiAccelerometer::GetInitialized() const {
return HALSIM_GetSPIInitialized(m_port);
}
void ADXL362_SpiAccelerometer::HandleWrite(const uint8_t* buffer,
uint32_t count) {
m_lastWriteAddress = buffer[1];
}
void ADXL362_SpiAccelerometer::HandleRead(uint8_t* buffer, uint32_t count) {
// Init check
if (m_lastWriteAddress == 0x02) {
uint32_t numToPut = 0xF20000;
std::memcpy(&buffer[0], &numToPut, sizeof(numToPut));
} else {
// Get Accelerations
bool writeAll = count == 8;
int byteIndex = 2;
if (writeAll || m_lastWriteAddress == 0x0E) {
int16_t val = static_cast<int16_t>(GetX() * LSB);
std::memcpy(&buffer[byteIndex], &val, sizeof(val));
byteIndex += sizeof(val);
}
if (writeAll || m_lastWriteAddress == 0x10) {
int16_t val = static_cast<int16_t>(GetY() * LSB);
std::memcpy(&buffer[byteIndex], &val, sizeof(val));
byteIndex += sizeof(val);
}
if (writeAll || m_lastWriteAddress == 0x12) {
int16_t val = static_cast<int16_t>(GetZ() * LSB);
std::memcpy(&buffer[byteIndex], &val, sizeof(val));
byteIndex += sizeof(val);
}
}
}

View File

@@ -1,132 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "ADXRS450_SpiGyroWrapperData.h"
#include <algorithm>
#include <cmath>
#include <cstring>
#include <hal/HALBase.h>
#include <mockdata/SPIData.h>
#ifdef _WIN32
#include "Winsock2.h"
#pragma comment(lib, "ws2_32.lib")
#else
#include <arpa/inet.h>
#endif
using namespace hal;
static constexpr double kSamplePeriod = 0.0005;
const double ADXRS450_SpiGyroWrapper::kAngleLsb = 1 / 0.0125 / kSamplePeriod;
const double ADXRS450_SpiGyroWrapper::kMaxAngleDeltaPerMessage = 0.1875;
const int ADXRS450_SpiGyroWrapper::kPacketSize = 4 + 1; // +1 for timestamp
template <class T>
constexpr const T& clamp(const T& value, const T& low, const T& high) {
return (std::max)(low, (std::min)(value, high));
}
static void ADXRS450SPI_ReadBufferCallback(const char* name, void* param,
uint8_t* buffer, uint32_t count) {
auto sim = static_cast<ADXRS450_SpiGyroWrapper*>(param);
sim->HandleRead(buffer, count);
}
static void ADXRS450SPI_ReadAutoReceivedData(const char* name, void* param,
uint32_t* buffer,
int32_t numToRead,
int32_t* outputCount) {
auto sim = static_cast<ADXRS450_SpiGyroWrapper*>(param);
sim->HandleAutoReceiveData(buffer, numToRead, *outputCount);
}
ADXRS450_SpiGyroWrapper::ADXRS450_SpiGyroWrapper(int port) : m_port(port) {
m_readCallbackId = HALSIM_RegisterSPIReadCallback(
port, ADXRS450SPI_ReadBufferCallback, this);
m_autoReceiveReadCallbackId = HALSIM_RegisterSPIReadAutoReceivedDataCallback(
port, ADXRS450SPI_ReadAutoReceivedData, this);
}
ADXRS450_SpiGyroWrapper::~ADXRS450_SpiGyroWrapper() {
HALSIM_CancelSPIReadCallback(m_port, m_readCallbackId);
HALSIM_CancelSPIReadAutoReceivedDataCallback(m_port,
m_autoReceiveReadCallbackId);
}
bool ADXRS450_SpiGyroWrapper::GetInitialized() const {
return HALSIM_GetSPIInitialized(m_port);
}
void ADXRS450_SpiGyroWrapper::ResetData() {
std::scoped_lock lock(m_angle.GetMutex());
m_angle.Reset(0.0);
m_angleDiff = 0;
}
void ADXRS450_SpiGyroWrapper::HandleRead(uint8_t* buffer, uint32_t count) {
int returnCode = 0x00400AE0;
std::memcpy(&buffer[0], &returnCode, sizeof(returnCode));
}
void ADXRS450_SpiGyroWrapper::HandleAutoReceiveData(uint32_t* buffer,
int32_t numToRead,
int32_t& outputCount) {
std::scoped_lock lock(m_angle.GetMutex());
int32_t messagesToSend =
1 + std::abs(m_angleDiff > 0
? std::ceil(m_angleDiff / kMaxAngleDeltaPerMessage)
: std::floor(m_angleDiff / kMaxAngleDeltaPerMessage));
// Zero gets passed in during the "How much data do I need to read" step.
// Else it is actually reading the accumulator
if (numToRead == 0) {
outputCount = messagesToSend * kPacketSize;
return;
}
int valuesToRead = numToRead / kPacketSize;
std::memset(&buffer[0], 0, numToRead * sizeof(uint32_t));
int32_t status = 0;
uint32_t timestamp = HAL_GetFPGATime(&status);
for (int msgCtr = 0; msgCtr < valuesToRead; ++msgCtr) {
// force the first message to be a rate of 0 to init the timestamp
double cappedDiff = (msgCtr == 0)
? 0
: clamp(m_angleDiff, -kMaxAngleDeltaPerMessage,
kMaxAngleDeltaPerMessage);
// first word is timestamp
buffer[msgCtr * kPacketSize] = timestamp;
int32_t valueToSend =
((static_cast<int32_t>(cappedDiff * kAngleLsb) << 10) & (~0x0C00000E)) |
0x04000000;
// following words have byte in LSB, in big endian order
for (int i = 4; i >= 1; --i) {
buffer[msgCtr * kPacketSize + i] =
static_cast<uint32_t>(valueToSend) & 0xffu;
valueToSend >>= 8;
}
m_angleDiff -= cappedDiff;
timestamp += kSamplePeriod * 1e6; // fpga time is in us
}
}
void ADXRS450_SpiGyroWrapper::SetAngle(double angle) {
std::scoped_lock lock(m_angle.GetMutex());
if (m_angle != angle) {
m_angleDiff += angle - m_angle;
m_angle = angle;
}
}

View File

@@ -1,19 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "ThreeAxisAccelerometerData.h"
using namespace hal;
ThreeAxisAccelerometerData::ThreeAxisAccelerometerData() {}
ThreeAxisAccelerometerData::~ThreeAxisAccelerometerData() {}
void ThreeAxisAccelerometerData::ResetData() {
x.Reset(0.0);
y.Reset(0.0);
z.Reset(0.0);
}

View File

@@ -1,32 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "ThreeAxisAccelerometerData.h"
namespace hal {
class ADXL345_I2CData : public ThreeAxisAccelerometerData {
public:
explicit ADXL345_I2CData(int port);
virtual ~ADXL345_I2CData();
bool GetInitialized() const override;
void HandleWrite(const uint8_t* buffer, uint32_t count);
void HandleRead(uint8_t* buffer, uint32_t count);
private:
int m_port;
int m_writeCallbackId;
int m_readCallbackId;
int m_lastWriteAddress;
static const double LSB;
};
} // namespace hal

View File

@@ -1,32 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "ThreeAxisAccelerometerData.h"
namespace hal {
class ADXL345_SpiAccelerometer : public ThreeAxisAccelerometerData {
public:
explicit ADXL345_SpiAccelerometer(int port);
virtual ~ADXL345_SpiAccelerometer();
bool GetInitialized() const override;
void HandleWrite(const uint8_t* buffer, uint32_t count);
void HandleRead(uint8_t* buffer, uint32_t count);
private:
int m_port;
int m_writeCallbackId;
int m_readCallbackId;
int m_lastWriteAddress;
static const double LSB;
};
} // namespace hal

View File

@@ -1,32 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "ThreeAxisAccelerometerData.h"
namespace hal {
class ADXL362_SpiAccelerometer : public ThreeAxisAccelerometerData {
public:
explicit ADXL362_SpiAccelerometer(int port);
virtual ~ADXL362_SpiAccelerometer();
bool GetInitialized() const override;
void HandleWrite(const uint8_t* buffer, uint32_t count);
void HandleRead(uint8_t* buffer, uint32_t count);
private:
int m_port;
int m_writeCallbackId;
int m_readCallbackId;
int m_lastWriteAddress;
static const double LSB;
};
} // namespace hal

View File

@@ -1,50 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <mockdata/SimDataValue.h>
namespace hal {
class ADXRS450_SpiGyroWrapper {
public:
explicit ADXRS450_SpiGyroWrapper(int port);
virtual ~ADXRS450_SpiGyroWrapper();
bool GetInitialized() const;
void HandleRead(uint8_t* buffer, uint32_t count);
void HandleAutoReceiveData(uint32_t* buffer, int32_t numToRead,
int32_t& outputCount);
int32_t RegisterAngleCallback(HAL_NotifyCallback callback, void* param,
HAL_Bool initialNotify) {
return m_angle.RegisterCallback(callback, param, initialNotify);
}
void CancelAngleCallback(int32_t uid) { m_angle.CancelCallback(uid); }
double GetAngle() { return m_angle; }
void SetAngle(double angle);
virtual void ResetData();
private:
int m_port;
int m_readCallbackId;
int m_autoReceiveReadCallbackId;
HAL_SIMDATAVALUE_DEFINE_NAME(Angle)
SimDataValue<double, HAL_MakeDouble, GetAngleName> m_angle{0.0};
double m_angleDiff = 0.0;
static const double kAngleLsb;
// The maximum difference that can fit inside of the shifted and masked data
// field, per transaction
static const double kMaxAngleDeltaPerMessage;
static const int kPacketSize;
};
} // namespace hal

View File

@@ -1,39 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <mockdata/SimDataValue.h>
namespace hal {
class ThreeAxisAccelerometerData {
HAL_SIMDATAVALUE_DEFINE_NAME(X);
HAL_SIMDATAVALUE_DEFINE_NAME(Y);
HAL_SIMDATAVALUE_DEFINE_NAME(Z);
public:
ThreeAxisAccelerometerData();
virtual ~ThreeAxisAccelerometerData();
virtual bool GetInitialized() const = 0;
double GetX() { return x; }
void SetX(double x_) { x = x_; }
double GetY() { return y; }
void SetY(double y_) { y = y_; }
double GetZ() { return z; }
void SetZ(double z_) { z = z_; }
SimDataValue<double, HAL_MakeDouble, GetXName> x{0.0};
SimDataValue<double, HAL_MakeDouble, GetYName> y{0.0};
SimDataValue<double, HAL_MakeDouble, GetZName> z{0.0};
virtual void ResetData();
};
} // namespace hal

View File

@@ -1,46 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "ADXL345_I2CAccelerometerData.h"
#include "frc/ADXL345_I2C.h"
#include "gtest/gtest.h"
class ADXL345_I2CAccelerometerTest
: public ::testing::TestWithParam<frc::I2C::Port> {};
TEST_P(ADXL345_I2CAccelerometerTest, TestAccelerometer) {
const double EPSILON = 1 / 256.0;
frc::I2C::Port port = GetParam();
hal::ADXL345_I2CData sim{port};
frc::ADXL345_I2C accel{port};
EXPECT_NEAR(0, sim.GetX(), EPSILON);
EXPECT_NEAR(0, sim.GetY(), EPSILON);
EXPECT_NEAR(0, sim.GetZ(), EPSILON);
EXPECT_NEAR(0, accel.GetX(), EPSILON);
EXPECT_NEAR(0, accel.GetY(), EPSILON);
EXPECT_NEAR(0, accel.GetZ(), EPSILON);
sim.SetX(1.56);
sim.SetY(-.653);
sim.SetZ(0.11);
EXPECT_NEAR(1.56, sim.GetX(), EPSILON);
EXPECT_NEAR(-.653, sim.GetY(), EPSILON);
EXPECT_NEAR(0.11, sim.GetZ(), EPSILON);
EXPECT_NEAR(1.56, accel.GetX(), EPSILON);
EXPECT_NEAR(-.653, accel.GetY(), EPSILON);
EXPECT_NEAR(0.11, accel.GetZ(), EPSILON);
}
INSTANTIATE_TEST_SUITE_P(ADXL345_I2CAccelerometerTest,
ADXL345_I2CAccelerometerTest,
::testing::Values(frc::I2C::kOnboard, frc::I2C::kMXP));

View File

@@ -1,48 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "ADXL345_SpiAccelerometerData.h"
#include "frc/ADXL345_SPI.h"
#include "gtest/gtest.h"
class ADXL345_SpiAccelerometerTest
: public ::testing::TestWithParam<frc::SPI::Port> {};
TEST_P(ADXL345_SpiAccelerometerTest, TestAccelerometer) {
const double EPSILON = 1 / 256.0;
frc::SPI::Port port = GetParam();
hal::ADXL345_SpiAccelerometer sim{port};
frc::ADXL345_SPI accel{port};
EXPECT_NEAR(0, sim.GetX(), EPSILON);
EXPECT_NEAR(0, sim.GetY(), EPSILON);
EXPECT_NEAR(0, sim.GetZ(), EPSILON);
EXPECT_NEAR(0, accel.GetX(), EPSILON);
EXPECT_NEAR(0, accel.GetY(), EPSILON);
EXPECT_NEAR(0, accel.GetZ(), EPSILON);
sim.SetX(1.56);
sim.SetY(-.653);
sim.SetZ(0.11);
EXPECT_NEAR(1.56, sim.GetX(), EPSILON);
EXPECT_NEAR(-.653, sim.GetY(), EPSILON);
EXPECT_NEAR(0.11, sim.GetZ(), EPSILON);
EXPECT_NEAR(1.56, accel.GetX(), EPSILON);
EXPECT_NEAR(-.653, accel.GetY(), EPSILON);
EXPECT_NEAR(0.11, accel.GetZ(), EPSILON);
}
INSTANTIATE_TEST_SUITE_P(
ADXL345_SpiAccelerometerTest, ADXL345_SpiAccelerometerTest,
::testing::Values(frc::SPI::kOnboardCS0, frc::SPI::kOnboardCS1,
frc::SPI::kOnboardCS2, frc::SPI::kOnboardCS3,
frc::SPI::kMXP));

View File

@@ -1,48 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "ADXL362_SpiAccelerometerData.h"
#include "frc/ADXL362.h"
#include "gtest/gtest.h"
class ADXL362_SpiAccelerometerTest
: public ::testing::TestWithParam<frc::SPI::Port> {};
TEST_P(ADXL362_SpiAccelerometerTest, TestAccelerometer) {
const double EPSILON = 1 / 256.0;
frc::SPI::Port port = GetParam();
hal::ADXL362_SpiAccelerometer sim{port};
frc::ADXL362 accel{port};
EXPECT_NEAR(0, sim.GetX(), EPSILON);
EXPECT_NEAR(0, sim.GetY(), EPSILON);
EXPECT_NEAR(0, sim.GetZ(), EPSILON);
EXPECT_NEAR(0, accel.GetX(), EPSILON);
EXPECT_NEAR(0, accel.GetY(), EPSILON);
EXPECT_NEAR(0, accel.GetZ(), EPSILON);
sim.SetX(1.56);
sim.SetY(-.653);
sim.SetZ(0.11);
EXPECT_NEAR(1.56, sim.GetX(), EPSILON);
EXPECT_NEAR(-.653, sim.GetY(), EPSILON);
EXPECT_NEAR(0.11, sim.GetZ(), EPSILON);
EXPECT_NEAR(1.56, accel.GetX(), EPSILON);
EXPECT_NEAR(-.653, accel.GetY(), EPSILON);
EXPECT_NEAR(0.11, accel.GetZ(), EPSILON);
}
INSTANTIATE_TEST_SUITE_P(
ADXL362_SpiAccelerometerTest, ADXL362_SpiAccelerometerTest,
::testing::Values(frc::SPI::kOnboardCS0, frc::SPI::kOnboardCS1,
frc::SPI::kOnboardCS2, frc::SPI::kOnboardCS3,
frc::SPI::kMXP));

View File

@@ -1,41 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "ADXRS450_SpiGyroWrapperData.h"
#include "frc/ADXRS450_Gyro.h"
#include "gtest/gtest.h"
class ADXRS450_SpiGyroWrapperTest
: public ::testing::TestWithParam<frc::SPI::Port> {};
TEST_P(ADXRS450_SpiGyroWrapperTest, TestAccelerometer) {
#ifdef __APPLE__
// Disable test on mac, because of unknown failures
// TODO: Finally figure out the isse.
return;
#else
const double EPSILON = .000001;
frc::SPI::Port port = GetParam();
hal::ADXRS450_SpiGyroWrapper sim{port};
frc::ADXRS450_Gyro gyro{port};
EXPECT_NEAR(0, sim.GetAngle(), EPSILON);
EXPECT_NEAR(0, gyro.GetAngle(), EPSILON);
sim.SetAngle(32.56);
EXPECT_NEAR(32.56, sim.GetAngle(), EPSILON);
EXPECT_NEAR(32.56, gyro.GetAngle(), EPSILON);
#endif
}
INSTANTIATE_TEST_SUITE_P(
ADXRS450_SpiGyroWrapperTest, ADXRS450_SpiGyroWrapperTest,
::testing::Values(frc::SPI::kOnboardCS0, frc::SPI::kOnboardCS1,
frc::SPI::kOnboardCS2, frc::SPI::kOnboardCS3,
frc::SPI::kMXP));

View File

@@ -1,17 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include <hal/HAL.h>
#include "gtest/gtest.h"
int main(int argc, char** argv) {
HAL_Initialize(500, 0);
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
return ret;
}

View File

@@ -78,7 +78,6 @@ if (!project.hasProperty('onlylinuxathena')) {
}
project(':hal').addHalDependency(it, 'shared')
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
lib project: ':simulation:halsim_adx_gyro_accelerometer', library: 'halsim_adx_gyro_accelerometer', linkage: 'shared'
}
}
"${nativeName}"(NativeLibrarySpec) {
@@ -100,7 +99,6 @@ if (!project.hasProperty('onlylinuxathena')) {
}
project(':hal').addHalDependency(it, 'shared')
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
lib project: ':simulation:halsim_adx_gyro_accelerometer', library: 'halsim_adx_gyro_accelerometer', linkage: 'shared'
}
}
// By default, a development executable will be generated. This is to help the case of
@@ -126,7 +124,6 @@ if (!project.hasProperty('onlylinuxathena')) {
}
project(':hal').addHalDependency(it, 'shared')
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
lib project: ':simulation:halsim_adx_gyro_accelerometer', library: 'halsim_adx_gyro_accelerometer', linkage: 'shared'
lib library: nativeName, linkage: 'shared'
}
}
@@ -139,7 +136,6 @@ if (!project.hasProperty('onlylinuxathena')) {
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
lib project: ':cameraserver', library: 'cameraserver', linkage: 'shared'
lib project: ':wpilibc', library: 'wpilibc', linkage: 'shared'
lib project: ':simulation:halsim_adx_gyro_accelerometer', library: 'halsim_adx_gyro_accelerometer', linkage: 'shared'
lib library: nativeName, linkage: 'shared'
}
}

View File

@@ -1,46 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "lowfisim/wpisimulators/ADXLThreeAxisAccelerometerSim.h"
namespace frc {
namespace sim {
namespace lowfi {
ADXLThreeAxisAccelerometerSim::ADXLThreeAxisAccelerometerSim(
hal::ThreeAxisAccelerometerData& accelerometerWrapper)
: m_accelerometerWrapper(accelerometerWrapper),
m_xWrapper(
[data = &m_accelerometerWrapper] { return data->GetInitialized(); },
[data = &m_accelerometerWrapper](double x) { data->x = x; },
[data = &m_accelerometerWrapper] { return data->GetX(); }),
m_yWrapper(
[data = &m_accelerometerWrapper] { return data->GetInitialized(); },
[data = &m_accelerometerWrapper](double y) { data->y = y; },
[data = &m_accelerometerWrapper] { return data->GetY(); }),
m_zWrapper(
[data = &m_accelerometerWrapper] { return data->GetInitialized(); },
[data = &m_accelerometerWrapper](double z) { data->z = z; },
[data = &m_accelerometerWrapper] { return data->GetZ(); }) {}
AccelerometerSim& ADXLThreeAxisAccelerometerSim::GetXWrapper() {
return m_xWrapper;
}
AccelerometerSim& ADXLThreeAxisAccelerometerSim::GetYWrapper() {
return m_yWrapper;
}
AccelerometerSim& ADXLThreeAxisAccelerometerSim::GetZWrapper() {
return m_zWrapper;
}
} // namespace lowfi
} // namespace sim
} // namespace frc

View File

@@ -1,29 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "lowfisim/wpisimulators/ADXRS450_SpiGyroSim.h"
namespace frc {
namespace sim {
namespace lowfi {
ADXRS450_SpiGyroSim::ADXRS450_SpiGyroSim(int spiPort)
: m_gyroWrapper(spiPort) {}
bool ADXRS450_SpiGyroSim::IsWrapperInitialized() const {
return m_gyroWrapper.GetInitialized();
}
void ADXRS450_SpiGyroSim::SetAngle(double angle) {
m_gyroWrapper.SetAngle(angle);
}
double ADXRS450_SpiGyroSim::GetAngle() { return m_gyroWrapper.GetAngle(); }
} // namespace lowfi
} // namespace sim
} // namespace frc

View File

@@ -1,35 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "ThreeAxisAccelerometerData.h"
#include "lowfisim/SimpleAccelerometerSim.h"
namespace frc {
namespace sim {
namespace lowfi {
class ADXLThreeAxisAccelerometerSim {
public:
ADXLThreeAxisAccelerometerSim(
hal::ThreeAxisAccelerometerData& accelerometerWrapper);
AccelerometerSim& GetXWrapper();
AccelerometerSim& GetYWrapper();
AccelerometerSim& GetZWrapper();
protected:
hal::ThreeAxisAccelerometerData& m_accelerometerWrapper;
SimpleAccelerometerSim m_xWrapper;
SimpleAccelerometerSim m_yWrapper;
SimpleAccelerometerSim m_zWrapper;
};
} // namespace lowfi
} // namespace sim
} // namespace frc

View File

@@ -1,32 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "ADXRS450_SpiGyroWrapperData.h"
#include "lowfisim/GyroSim.h"
namespace frc {
namespace sim {
namespace lowfi {
class ADXRS450_SpiGyroSim : public GyroSim {
public:
explicit ADXRS450_SpiGyroSim(int spiPort);
bool IsWrapperInitialized() const override;
void SetAngle(double angle) override;
double GetAngle() override;
protected:
hal::ADXRS450_SpiGyroWrapper m_gyroWrapper;
};
} // namespace lowfi
} // namespace sim
} // namespace frc

View File

@@ -1,58 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "ADXL345_I2CAccelerometerData.h"
#include "frc/ADXL345_I2C.h"
#include "gtest/gtest.h"
#include "lowfisim/wpisimulators/ADXLThreeAxisAccelerometerSim.h"
TEST(AccelerometerTests, TestADXL345_I2CAccelerometerWrapper) {
const double EPSILON = 1 / 256.0;
frc::I2C::Port port = frc::I2C::kOnboard;
hal::ADXL345_I2CData rawAdxSim(port);
frc::sim::lowfi::ADXLThreeAxisAccelerometerSim accelerometerSim(rawAdxSim);
frc::sim::lowfi::AccelerometerSim& xWrapper = accelerometerSim.GetXWrapper();
frc::sim::lowfi::AccelerometerSim& yWrapper = accelerometerSim.GetYWrapper();
frc::sim::lowfi::AccelerometerSim& zWrapper = accelerometerSim.GetZWrapper();
EXPECT_FALSE(xWrapper.IsWrapperInitialized());
EXPECT_FALSE(yWrapper.IsWrapperInitialized());
EXPECT_FALSE(zWrapper.IsWrapperInitialized());
frc::ADXL345_I2C accel{port};
EXPECT_NEAR(0, accel.GetX(), EPSILON);
EXPECT_NEAR(0, accel.GetY(), EPSILON);
EXPECT_NEAR(0, accel.GetZ(), EPSILON);
EXPECT_TRUE(xWrapper.IsWrapperInitialized());
EXPECT_TRUE(yWrapper.IsWrapperInitialized());
EXPECT_TRUE(zWrapper.IsWrapperInitialized());
xWrapper.SetAcceleration(1.45);
EXPECT_NEAR(1.45, accel.GetX(), EPSILON);
EXPECT_NEAR(0, accel.GetY(), EPSILON);
EXPECT_NEAR(0, accel.GetZ(), EPSILON);
EXPECT_NEAR(1.45, xWrapper.GetAcceleration(), EPSILON);
EXPECT_NEAR(0, yWrapper.GetAcceleration(), EPSILON);
EXPECT_NEAR(0, zWrapper.GetAcceleration(), EPSILON);
yWrapper.SetAcceleration(-.67);
EXPECT_NEAR(1.45, accel.GetX(), EPSILON);
EXPECT_NEAR(-.67, accel.GetY(), EPSILON);
EXPECT_NEAR(0, accel.GetZ(), EPSILON);
EXPECT_NEAR(1.45, xWrapper.GetAcceleration(), EPSILON);
EXPECT_NEAR(-.67, yWrapper.GetAcceleration(), EPSILON);
EXPECT_NEAR(0, zWrapper.GetAcceleration(), EPSILON);
zWrapper.SetAcceleration(2.42);
EXPECT_NEAR(1.45, accel.GetX(), EPSILON);
EXPECT_NEAR(-.67, accel.GetY(), EPSILON);
EXPECT_NEAR(2.42, accel.GetZ(), EPSILON);
EXPECT_NEAR(1.45, xWrapper.GetAcceleration(), EPSILON);
EXPECT_NEAR(-.67, yWrapper.GetAcceleration(), EPSILON);
EXPECT_NEAR(2.42, zWrapper.GetAcceleration(), EPSILON);
}

View File

@@ -1,47 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "ADXRS450_SpiGyroWrapperData.h"
#include "frc/ADXRS450_Gyro.h"
#include "frc/AnalogGyro.h"
#include "gtest/gtest.h"
#include "lowfisim/wpisimulators/ADXRS450_SpiGyroSim.h"
#include "lowfisim/wpisimulators/WpiAnalogGyroSim.h"
void TestGyro(frc::sim::lowfi::GyroSim& sim, frc::Gyro& gyro) {
const double EPSILON = .00001;
EXPECT_NEAR(0, gyro.GetAngle(), EPSILON);
EXPECT_NEAR(0, sim.GetAngle(), EPSILON);
sim.SetAngle(45.13);
EXPECT_NEAR(45.13, gyro.GetAngle(), EPSILON);
EXPECT_NEAR(45.13, sim.GetAngle(), EPSILON);
}
TEST(GyroSimulatorTests, TestAnalogGyro) {
int port = 1;
frc::sim::lowfi::WpiAnalogGyroSim sim{port};
EXPECT_FALSE(sim.IsWrapperInitialized());
frc::AnalogGyro gyro{port};
EXPECT_TRUE(sim.IsWrapperInitialized());
TestGyro(sim, gyro);
}
TEST(GyroSimulatorTests, TestSpiGyro) {
frc::SPI::Port port = frc::SPI::kOnboardCS0;
frc::sim::lowfi::ADXRS450_SpiGyroSim sim{port};
EXPECT_FALSE(sim.IsWrapperInitialized());
frc::ADXRS450_Gyro gyro{port};
EXPECT_TRUE(sim.IsWrapperInitialized());
TestGyro(sim, gyro);
}

View File

@@ -15,7 +15,15 @@
using namespace frc;
ADXL345_I2C::ADXL345_I2C(I2C::Port port, Range range, int deviceAddress)
: m_i2c(port, deviceAddress) {
: m_i2c(port, deviceAddress),
m_simDevice("ADXL345_I2C", port, deviceAddress) {
if (m_simDevice) {
m_simRange =
m_simDevice.CreateEnum("Range", true, {"2G", "4G", "8G", "16G"}, 0);
m_simX = m_simDevice.CreateDouble("X Accel", false, 0.0);
m_simX = m_simDevice.CreateDouble("Y Accel", false, 0.0);
m_simZ = m_simDevice.CreateDouble("Z Accel", false, 0.0);
}
// Turn on the measurements
m_i2c.Write(kPowerCtlRegister, kPowerCtl_Measure);
// Specify the data format to read
@@ -39,6 +47,9 @@ double ADXL345_I2C::GetY() { return GetAcceleration(kAxis_Y); }
double ADXL345_I2C::GetZ() { return GetAcceleration(kAxis_Z); }
double ADXL345_I2C::GetAcceleration(ADXL345_I2C::Axes axis) {
if (axis == kAxis_X && m_simX) return m_simX.Get();
if (axis == kAxis_Y && m_simY) return m_simY.Get();
if (axis == kAxis_Z && m_simZ) return m_simZ.Get();
int16_t rawAccel = 0;
m_i2c.Read(kDataRegister + static_cast<int>(axis), sizeof(rawAccel),
reinterpret_cast<uint8_t*>(&rawAccel));
@@ -46,7 +57,13 @@ double ADXL345_I2C::GetAcceleration(ADXL345_I2C::Axes axis) {
}
ADXL345_I2C::AllAxes ADXL345_I2C::GetAccelerations() {
AllAxes data = AllAxes();
AllAxes data;
if (m_simX && m_simY && m_simZ) {
data.XAxis = m_simX.Get();
data.YAxis = m_simY.Get();
data.ZAxis = m_simZ.Get();
return data;
}
int16_t rawData[3];
m_i2c.Read(kDataRegister, sizeof(rawData),
reinterpret_cast<uint8_t*>(rawData));

View File

@@ -15,7 +15,14 @@
using namespace frc;
ADXL345_SPI::ADXL345_SPI(SPI::Port port, ADXL345_SPI::Range range)
: m_spi(port) {
: m_spi(port), m_simDevice("ADXL345_SPI", port) {
if (m_simDevice) {
m_simRange =
m_simDevice.CreateEnum("Range", true, {"2G", "4G", "8G", "16G"}, 0);
m_simX = m_simDevice.CreateDouble("X Accel", false, 0.0);
m_simX = m_simDevice.CreateDouble("Y Accel", false, 0.0);
m_simZ = m_simDevice.CreateDouble("Z Accel", false, 0.0);
}
m_spi.SetClockRate(500000);
m_spi.SetMSBFirst();
m_spi.SetSampleDataOnTrailingEdge();
@@ -43,6 +50,8 @@ void ADXL345_SPI::SetRange(Range range) {
commands[0] = kDataFormatRegister;
commands[1] = kDataFormat_FullRes | static_cast<uint8_t>(range & 0x03);
m_spi.Transaction(commands, commands, 2);
if (m_simRange) m_simRange.Set(range);
}
double ADXL345_SPI::GetX() { return GetAcceleration(kAxis_X); }
@@ -52,6 +61,9 @@ double ADXL345_SPI::GetY() { return GetAcceleration(kAxis_Y); }
double ADXL345_SPI::GetZ() { return GetAcceleration(kAxis_Z); }
double ADXL345_SPI::GetAcceleration(ADXL345_SPI::Axes axis) {
if (axis == kAxis_X && m_simX) return m_simX.Get();
if (axis == kAxis_Y && m_simY) return m_simY.Get();
if (axis == kAxis_Z && m_simZ) return m_simZ.Get();
uint8_t buffer[3];
uint8_t command[3] = {0, 0, 0};
command[0] = (kAddress_Read | kAddress_MultiByte | kDataRegister) +
@@ -64,7 +76,14 @@ double ADXL345_SPI::GetAcceleration(ADXL345_SPI::Axes axis) {
}
ADXL345_SPI::AllAxes ADXL345_SPI::GetAccelerations() {
AllAxes data = AllAxes();
AllAxes data;
if (m_simX && m_simY && m_simZ) {
data.XAxis = m_simX.Get();
data.YAxis = m_simY.Get();
data.ZAxis = m_simZ.Get();
return data;
}
uint8_t dataBuffer[7] = {0, 0, 0, 0, 0, 0, 0};
int16_t rawData[3];

View File

@@ -34,23 +34,34 @@ static constexpr int kPowerCtl_Measure = 0x02;
ADXL362::ADXL362(Range range) : ADXL362(SPI::Port::kOnboardCS1, range) {}
ADXL362::ADXL362(SPI::Port port, Range range) : m_spi(port) {
ADXL362::ADXL362(SPI::Port port, Range range)
: m_spi(port), m_simDevice("ADXL362", port) {
if (m_simDevice) {
m_simRange =
m_simDevice.CreateEnum("Range", true, {"2G", "4G", "8G", "16G"}, 0);
m_simX = m_simDevice.CreateDouble("X Accel", false, 0.0);
m_simX = m_simDevice.CreateDouble("Y Accel", false, 0.0);
m_simZ = m_simDevice.CreateDouble("Z Accel", false, 0.0);
}
m_spi.SetClockRate(3000000);
m_spi.SetMSBFirst();
m_spi.SetSampleDataOnTrailingEdge();
m_spi.SetClockActiveLow();
m_spi.SetChipSelectActiveLow();
// Validate the part ID
uint8_t commands[3];
commands[0] = kRegRead;
commands[1] = kPartIdRegister;
commands[2] = 0;
m_spi.Transaction(commands, commands, 3);
if (commands[2] != 0xF2) {
DriverStation::ReportError("could not find ADXL362");
m_gsPerLSB = 0.0;
return;
if (!m_simDevice) {
// Validate the part ID
commands[0] = kRegRead;
commands[1] = kPartIdRegister;
commands[2] = 0;
m_spi.Transaction(commands, commands, 3);
if (commands[2] != 0xF2) {
DriverStation::ReportError("could not find ADXL362");
m_gsPerLSB = 0.0;
return;
}
}
SetRange(range);
@@ -90,6 +101,8 @@ void ADXL362::SetRange(Range range) {
commands[2] =
kFilterCtl_ODR_100Hz | static_cast<uint8_t>((range & 0x03) << 6);
m_spi.Write(commands, 3);
if (m_simRange) m_simRange.Set(range);
}
double ADXL362::GetX() { return GetAcceleration(kAxis_X); }
@@ -101,6 +114,10 @@ double ADXL362::GetZ() { return GetAcceleration(kAxis_Z); }
double ADXL362::GetAcceleration(ADXL362::Axes axis) {
if (m_gsPerLSB == 0.0) return 0.0;
if (axis == kAxis_X && m_simX) return m_simX.Get();
if (axis == kAxis_Y && m_simY) return m_simY.Get();
if (axis == kAxis_Z && m_simZ) return m_simZ.Get();
uint8_t buffer[4];
uint8_t command[4] = {0, 0, 0, 0};
command[0] = kRegRead;
@@ -113,11 +130,17 @@ double ADXL362::GetAcceleration(ADXL362::Axes axis) {
}
ADXL362::AllAxes ADXL362::GetAccelerations() {
AllAxes data = AllAxes();
AllAxes data;
if (m_gsPerLSB == 0.0) {
data.XAxis = data.YAxis = data.ZAxis = 0.0;
return data;
}
if (m_simX && m_simY && m_simZ) {
data.XAxis = m_simX.Get();
data.YAxis = m_simY.Get();
data.ZAxis = m_simZ.Get();
return data;
}
uint8_t dataBuffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
int16_t rawData[3];

View File

@@ -31,24 +31,32 @@ static constexpr int kSNLowRegister = 0x10;
ADXRS450_Gyro::ADXRS450_Gyro() : ADXRS450_Gyro(SPI::kOnboardCS0) {}
ADXRS450_Gyro::ADXRS450_Gyro(SPI::Port port) : m_spi(port) {
ADXRS450_Gyro::ADXRS450_Gyro(SPI::Port port)
: m_spi(port), m_simDevice("ADXRS450_Gyro", port) {
if (m_simDevice) {
m_simAngle = m_simDevice.CreateDouble("Angle", false, 0.0);
m_simRate = m_simDevice.CreateDouble("Rate", false, 0.0);
}
m_spi.SetClockRate(3000000);
m_spi.SetMSBFirst();
m_spi.SetSampleDataOnLeadingEdge();
m_spi.SetClockActiveHigh();
m_spi.SetChipSelectActiveLow();
// Validate the part ID
if ((ReadRegister(kPIDRegister) & 0xff00) != 0x5200) {
DriverStation::ReportError("could not find ADXRS450 gyro");
return;
if (!m_simDevice) {
// Validate the part ID
if ((ReadRegister(kPIDRegister) & 0xff00) != 0x5200) {
DriverStation::ReportError("could not find ADXRS450 gyro");
return;
}
m_spi.InitAccumulator(kSamplePeriod, 0x20000000u, 4, 0x0c00000eu,
0x04000000u, 10u, 16u, true, true);
Calibrate();
}
m_spi.InitAccumulator(kSamplePeriod, 0x20000000u, 4, 0x0c00000eu, 0x04000000u,
10u, 16u, true, true);
Calibrate();
HAL_Report(HALUsageReporting::kResourceType_ADXRS450, port);
SendableRegistry::GetInstance().AddLW(this, "ADXRS450_Gyro", port);
@@ -88,15 +96,21 @@ uint16_t ADXRS450_Gyro::ReadRegister(int reg) {
}
double ADXRS450_Gyro::GetAngle() const {
if (m_simAngle) return m_simAngle.Get();
return m_spi.GetAccumulatorIntegratedValue() * kDegreePerSecondPerLSB;
}
double ADXRS450_Gyro::GetRate() const {
if (m_simRate) return m_simRate.Get();
return static_cast<double>(m_spi.GetAccumulatorLastValue()) *
kDegreePerSecondPerLSB;
}
void ADXRS450_Gyro::Reset() { m_spi.ResetAccumulator(); }
void ADXRS450_Gyro::Reset() {
if (m_simAngle) m_simAngle.Set(0.0);
if (m_simRate) m_simRate.Set(0.0);
m_spi.ResetAccumulator();
}
void ADXRS450_Gyro::Calibrate() {
Wait(0.1);

View File

@@ -98,7 +98,10 @@ void Ultrasonic::Ping() {
m_pingChannel->Pulse(kPingTime);
}
bool Ultrasonic::IsRangeValid() const { return m_counter.Get() > 1; }
bool Ultrasonic::IsRangeValid() const {
if (m_simRangeValid) return m_simRangeValid.Get();
return m_counter.Get() > 1;
}
void Ultrasonic::SetAutomaticMode(bool enabling) {
if (enabling == m_automaticEnabled) return; // ignore the case of no change
@@ -135,10 +138,12 @@ void Ultrasonic::SetAutomaticMode(bool enabling) {
}
double Ultrasonic::GetRangeInches() const {
if (IsRangeValid())
if (IsRangeValid()) {
if (m_simRange) return m_simRange.Get();
return m_counter.GetPeriod() * kSpeedOfSoundInchesPerSec / 2.0;
else
} else {
return 0;
}
}
double Ultrasonic::GetRangeMM() const { return GetRangeInches() * 25.4; }
@@ -177,6 +182,14 @@ void Ultrasonic::InitSendable(SendableBuilder& builder) {
}
void Ultrasonic::Initialize() {
m_simDevice = hal::SimDevice("Ultrasonic", m_echoChannel->GetChannel());
if (m_simDevice) {
m_simRangeValid = m_simDevice.CreateBoolean("Range Valid", false, true);
m_simRange = m_simDevice.CreateDouble("Range (in)", false, 0.0);
m_pingChannel->SetSimDevice(m_simDevice);
m_echoChannel->SetSimDevice(m_simDevice);
}
bool originalMode = m_automaticEnabled;
SetAutomaticMode(false); // Kill task when adding a new sensor
// Link this instance on the list

View File

@@ -7,6 +7,8 @@
#pragma once
#include <hal/SimDevice.h>
#include "frc/ErrorBase.h"
#include "frc/I2C.h"
#include "frc/interfaces/Accelerometer.h"
@@ -78,6 +80,12 @@ class ADXL345_I2C : public ErrorBase,
protected:
I2C m_i2c;
hal::SimDevice m_simDevice;
hal::SimEnum m_simRange;
hal::SimDouble m_simX;
hal::SimDouble m_simY;
hal::SimDouble m_simZ;
static constexpr int kAddress = 0x1D;
static constexpr int kPowerCtlRegister = 0x2D;
static constexpr int kDataFormatRegister = 0x31;

View File

@@ -7,6 +7,8 @@
#pragma once
#include <hal/SimDevice.h>
#include "frc/ErrorBase.h"
#include "frc/SPI.h"
#include "frc/interfaces/Accelerometer.h"
@@ -74,6 +76,12 @@ class ADXL345_SPI : public ErrorBase,
protected:
SPI m_spi;
hal::SimDevice m_simDevice;
hal::SimEnum m_simRange;
hal::SimDouble m_simX;
hal::SimDouble m_simY;
hal::SimDouble m_simZ;
static constexpr int kPowerCtlRegister = 0x2D;
static constexpr int kDataFormatRegister = 0x31;
static constexpr int kDataRegister = 0x32;

View File

@@ -7,6 +7,8 @@
#pragma once
#include <hal/SimDevice.h>
#include "frc/ErrorBase.h"
#include "frc/SPI.h"
#include "frc/interfaces/Accelerometer.h"
@@ -81,6 +83,11 @@ class ADXL362 : public ErrorBase,
private:
SPI m_spi;
hal::SimDevice m_simDevice;
hal::SimEnum m_simRange;
hal::SimDouble m_simX;
hal::SimDouble m_simY;
hal::SimDouble m_simZ;
double m_gsPerLSB = 0.001;
};

View File

@@ -9,6 +9,8 @@
#include <stdint.h>
#include <hal/SimDevice.h>
#include "frc/GyroBase.h"
#include "frc/SPI.h"
@@ -94,6 +96,10 @@ class ADXRS450_Gyro : public GyroBase {
private:
SPI m_spi;
hal::SimDevice m_simDevice;
hal::SimDouble m_simAngle;
hal::SimDouble m_simRate;
uint16_t ReadRegister(int reg);
};

View File

@@ -12,6 +12,8 @@
#include <thread>
#include <vector>
#include <hal/SimDevice.h>
#include "frc/Counter.h"
#include "frc/ErrorBase.h"
#include "frc/PIDSource.h"
@@ -230,6 +232,10 @@ class Ultrasonic : public ErrorBase,
bool m_enabled = false;
Counter m_counter;
DistanceUnit m_units;
hal::SimDevice m_simDevice;
hal::SimBoolean m_simRangeValid;
hal::SimDouble m_simRange;
};
} // namespace frc

View File

@@ -100,7 +100,6 @@ model {
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
if (binary.targetPlatform.name != nativeUtils.wpi.platforms.roborio) {
lib project: ':simulation:halsim_lowfi', library: 'halsim_lowfi', linkage: 'shared'
lib project: ':simulation:halsim_adx_gyro_accelerometer', library: 'halsim_adx_gyro_accelerometer', linkage: 'shared'
lib project: ':simulation:halsim_print', library: 'halsim_print', linkage: 'shared'
lib project: ':simulation:halsim_ds_nt', library: 'halsim_ds_nt', linkage: 'shared'
}
@@ -150,7 +149,6 @@ model {
}
if (binary.targetPlatform.name != nativeUtils.wpi.platforms.roborio) {
lib project: ':simulation:halsim_lowfi', library: 'halsim_lowfi', linkage: 'shared'
lib project: ':simulation:halsim_adx_gyro_accelerometer', library: 'halsim_adx_gyro_accelerometer', linkage: 'shared'
lib project: ':simulation:halsim_print', library: 'halsim_print', linkage: 'shared'
lib project: ':simulation:halsim_ds_nt', library: 'halsim_ds_nt', linkage: 'shared'
}

View File

@@ -13,6 +13,9 @@ import java.nio.ByteOrder;
import edu.wpi.first.hal.FRCNetComm.tInstances;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.hal.SimEnum;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.interfaces.Accelerometer;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
@@ -64,6 +67,12 @@ public class ADXL345_I2C implements Accelerometer, Sendable, AutoCloseable {
protected I2C m_i2c;
protected SimDevice m_simDevice;
protected SimEnum m_simRange;
protected SimDouble m_simX;
protected SimDouble m_simY;
protected SimDouble m_simZ;
/**
* Constructs the ADXL345 Accelerometer with I2C address 0x1D.
*
@@ -84,6 +93,15 @@ public class ADXL345_I2C implements Accelerometer, Sendable, AutoCloseable {
public ADXL345_I2C(I2C.Port port, Range range, int deviceAddress) {
m_i2c = new I2C(port, deviceAddress);
// simulation
m_simDevice = SimDevice.create("ADXL345_I2C", port.value, deviceAddress);
if (m_simDevice != null) {
m_simRange = m_simDevice.createEnum("Range", true, new String[] {"2G", "4G", "8G", "16G"}, 0);
m_simX = m_simDevice.createDouble("X Accel", false, 0.0);
m_simX = m_simDevice.createDouble("Y Accel", false, 0.0);
m_simZ = m_simDevice.createDouble("Z Accel", false, 0.0);
}
// Turn on the measurements
m_i2c.write(kPowerCtlRegister, kPowerCtl_Measure);
@@ -95,7 +113,14 @@ public class ADXL345_I2C implements Accelerometer, Sendable, AutoCloseable {
@Override
public void close() {
m_i2c.close();
if (m_i2c != null) {
m_i2c.close();
m_i2c = null;
}
if (m_simDevice != null) {
m_simDevice.close();
m_simDevice = null;
}
}
@Override
@@ -121,6 +146,10 @@ public class ADXL345_I2C implements Accelerometer, Sendable, AutoCloseable {
// Specify the data format to read
m_i2c.write(kDataFormatRegister, kDataFormat_FullRes | value);
if (m_simRange != null) {
m_simRange.set(value);
}
}
@Override
@@ -145,6 +174,15 @@ public class ADXL345_I2C implements Accelerometer, Sendable, AutoCloseable {
* @return Acceleration of the ADXL345 in Gs.
*/
public double getAcceleration(Axes axis) {
if (axis == Axes.kX && m_simX != null) {
return m_simX.get();
}
if (axis == Axes.kY && m_simY != null) {
return m_simY.get();
}
if (axis == Axes.kZ && m_simZ != null) {
return m_simZ.get();
}
ByteBuffer rawAccel = ByteBuffer.allocate(2);
m_i2c.read(kDataRegister + axis.value, 2, rawAccel);
@@ -160,6 +198,12 @@ public class ADXL345_I2C implements Accelerometer, Sendable, AutoCloseable {
*/
public AllAxes getAccelerations() {
AllAxes data = new AllAxes();
if (m_simX != null && m_simY != null && m_simZ != null) {
data.XAxis = m_simX.get();
data.YAxis = m_simY.get();
data.ZAxis = m_simZ.get();
return data;
}
ByteBuffer rawData = ByteBuffer.allocate(6);
m_i2c.read(kDataRegister, 6, rawData);

View File

@@ -13,6 +13,9 @@ import java.nio.ByteOrder;
import edu.wpi.first.hal.FRCNetComm.tInstances;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.hal.SimEnum;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.interfaces.Accelerometer;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
@@ -67,6 +70,12 @@ public class ADXL345_SPI implements Accelerometer, Sendable, AutoCloseable {
protected SPI m_spi;
protected SimDevice m_simDevice;
protected SimEnum m_simRange;
protected SimDouble m_simX;
protected SimDouble m_simY;
protected SimDouble m_simZ;
/**
* Constructor.
*
@@ -75,13 +84,28 @@ public class ADXL345_SPI implements Accelerometer, Sendable, AutoCloseable {
*/
public ADXL345_SPI(SPI.Port port, Range range) {
m_spi = new SPI(port);
// simulation
m_simDevice = SimDevice.create("ADXL345_SPI", port.value);
if (m_simDevice != null) {
m_simRange = m_simDevice.createEnum("Range", true, new String[] {"2G", "4G", "8G", "16G"}, 0);
m_simX = m_simDevice.createDouble("X Accel", false, 0.0);
m_simX = m_simDevice.createDouble("Y Accel", false, 0.0);
m_simZ = m_simDevice.createDouble("Z Accel", false, 0.0);
}
init(range);
SendableRegistry.addLW(this, "ADXL345_SPI", port.value);
}
@Override
public void close() {
m_spi.close();
if (m_spi != null) {
m_spi.close();
m_spi = null;
}
if (m_simDevice != null) {
m_simDevice.close();
m_simDevice = null;
}
}
/**
@@ -131,6 +155,10 @@ public class ADXL345_SPI implements Accelerometer, Sendable, AutoCloseable {
// Specify the data format to read
byte[] commands = new byte[]{kDataFormatRegister, (byte) (kDataFormat_FullRes | value)};
m_spi.write(commands, commands.length);
if (m_simRange != null) {
m_simRange.set(value);
}
}
@Override
@@ -155,6 +183,15 @@ public class ADXL345_SPI implements Accelerometer, Sendable, AutoCloseable {
* @return Acceleration of the ADXL345 in Gs.
*/
public double getAcceleration(ADXL345_SPI.Axes axis) {
if (axis == Axes.kX && m_simX != null) {
return m_simX.get();
}
if (axis == Axes.kY && m_simY != null) {
return m_simY.get();
}
if (axis == Axes.kZ && m_simZ != null) {
return m_simZ.get();
}
ByteBuffer transferBuffer = ByteBuffer.allocate(3);
transferBuffer.put(0,
(byte) ((kAddress_Read | kAddress_MultiByte | kDataRegister) + axis.value));
@@ -172,6 +209,12 @@ public class ADXL345_SPI implements Accelerometer, Sendable, AutoCloseable {
*/
public ADXL345_SPI.AllAxes getAccelerations() {
ADXL345_SPI.AllAxes data = new ADXL345_SPI.AllAxes();
if (m_simX != null && m_simY != null && m_simZ != null) {
data.XAxis = m_simX.get();
data.YAxis = m_simY.get();
data.ZAxis = m_simZ.get();
return data;
}
if (m_spi != null) {
ByteBuffer dataBuffer = ByteBuffer.allocate(7);
// Select the data address.

View File

@@ -12,6 +12,9 @@ import java.nio.ByteOrder;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.hal.SimEnum;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.interfaces.Accelerometer;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
@@ -62,6 +65,13 @@ public class ADXL362 implements Accelerometer, Sendable, AutoCloseable {
}
private SPI m_spi;
private SimDevice m_simDevice;
private SimEnum m_simRange;
private SimDouble m_simX;
private SimDouble m_simY;
private SimDouble m_simZ;
private double m_gsPerLSB;
/**
@@ -82,22 +92,33 @@ public class ADXL362 implements Accelerometer, Sendable, AutoCloseable {
public ADXL362(SPI.Port port, Range range) {
m_spi = new SPI(port);
// simulation
m_simDevice = SimDevice.create("ADXL362", port.value);
if (m_simDevice != null) {
m_simRange = m_simDevice.createEnum("Range", true, new String[] {"2G", "4G", "8G", "16G"}, 0);
m_simX = m_simDevice.createDouble("X Accel", false, 0.0);
m_simX = m_simDevice.createDouble("Y Accel", false, 0.0);
m_simZ = m_simDevice.createDouble("Z Accel", false, 0.0);
}
m_spi.setClockRate(3000000);
m_spi.setMSBFirst();
m_spi.setSampleDataOnTrailingEdge();
m_spi.setClockActiveLow();
m_spi.setChipSelectActiveLow();
// Validate the part ID
ByteBuffer transferBuffer = ByteBuffer.allocate(3);
transferBuffer.put(0, kRegRead);
transferBuffer.put(1, kPartIdRegister);
m_spi.transaction(transferBuffer, transferBuffer, 3);
if (transferBuffer.get(2) != (byte) 0xF2) {
m_spi.close();
m_spi = null;
DriverStation.reportError("could not find ADXL362 on SPI port " + port.value, false);
return;
if (m_simDevice == null) {
// Validate the part ID
transferBuffer.put(0, kRegRead);
transferBuffer.put(1, kPartIdRegister);
m_spi.transaction(transferBuffer, transferBuffer, 3);
if (transferBuffer.get(2) != (byte) 0xF2) {
m_spi.close();
m_spi = null;
DriverStation.reportError("could not find ADXL362 on SPI port " + port.value, false);
return;
}
}
setRange(range);
@@ -118,6 +139,10 @@ public class ADXL362 implements Accelerometer, Sendable, AutoCloseable {
m_spi.close();
m_spi = null;
}
if (m_simDevice != null) {
m_simDevice.close();
m_simDevice = null;
}
}
@Override
@@ -150,6 +175,10 @@ public class ADXL362 implements Accelerometer, Sendable, AutoCloseable {
byte[] commands = new byte[]{kRegWrite, kFilterCtlRegister, (byte) (kFilterCtl_ODR_100Hz
| value)};
m_spi.write(commands, commands.length);
if (m_simRange != null) {
m_simRange.set(value);
}
}
@@ -175,6 +204,15 @@ public class ADXL362 implements Accelerometer, Sendable, AutoCloseable {
* @return Acceleration of the ADXL362 in Gs.
*/
public double getAcceleration(ADXL362.Axes axis) {
if (axis == Axes.kX && m_simX != null) {
return m_simX.get();
}
if (axis == Axes.kY && m_simY != null) {
return m_simY.get();
}
if (axis == Axes.kZ && m_simZ != null) {
return m_simZ.get();
}
if (m_spi == null) {
return 0.0;
}
@@ -195,6 +233,12 @@ public class ADXL362 implements Accelerometer, Sendable, AutoCloseable {
*/
public ADXL362.AllAxes getAccelerations() {
ADXL362.AllAxes data = new ADXL362.AllAxes();
if (m_simX != null && m_simY != null && m_simZ != null) {
data.XAxis = m_simX.get();
data.YAxis = m_simY.get();
data.ZAxis = m_simZ.get();
return data;
}
if (m_spi != null) {
ByteBuffer dataBuffer = ByteBuffer.allocate(8);
// Select the data address.

View File

@@ -12,6 +12,9 @@ import java.nio.ByteOrder;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimBoolean;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.wpilibj.interfaces.Gyro;
import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
@@ -42,6 +45,11 @@ public class ADXRS450_Gyro extends GyroBase implements Gyro, PIDSource, Sendable
private SPI m_spi;
private SimDevice m_simDevice;
private SimBoolean m_simConnected;
private SimDouble m_simAngle;
private SimDouble m_simRate;
/**
* Constructor. Uses the onboard CS0.
*/
@@ -57,31 +65,49 @@ public class ADXRS450_Gyro extends GyroBase implements Gyro, PIDSource, Sendable
public ADXRS450_Gyro(SPI.Port port) {
m_spi = new SPI(port);
// simulation
m_simDevice = SimDevice.create("ADXRS450_Gyro", port.value);
if (m_simDevice != null) {
m_simConnected = m_simDevice.createBoolean("Connected", false, true);
m_simAngle = m_simDevice.createDouble("Angle", false, 0.0);
m_simRate = m_simDevice.createDouble("Rate", false, 0.0);
}
m_spi.setClockRate(3000000);
m_spi.setMSBFirst();
m_spi.setSampleDataOnLeadingEdge();
m_spi.setClockActiveHigh();
m_spi.setChipSelectActiveLow();
// Validate the part ID
if ((readRegister(kPIDRegister) & 0xff00) != 0x5200) {
m_spi.close();
m_spi = null;
DriverStation.reportError("could not find ADXRS450 gyro on SPI port " + port.value,
false);
return;
if (m_simDevice == null) {
// Validate the part ID
if ((readRegister(kPIDRegister) & 0xff00) != 0x5200) {
m_spi.close();
m_spi = null;
DriverStation.reportError("could not find ADXRS450 gyro on SPI port " + port.value,
false);
return;
}
m_spi.initAccumulator(kSamplePeriod, 0x20000000, 4, 0x0c00000e, 0x04000000, 10, 16,
true, true);
calibrate();
}
m_spi.initAccumulator(kSamplePeriod, 0x20000000, 4, 0x0c00000e, 0x04000000, 10, 16,
true, true);
calibrate();
HAL.report(tResourceType.kResourceType_ADXRS450, port.value);
SendableRegistry.addLW(this, "ADXRS450_Gyro", port.value);
}
/**
* Determine if the gyro is connected.
*
* @return true if it is connected, false otherwise.
*/
public boolean isConnected() {
if (m_simConnected != null) {
return m_simConnected.get();
}
return m_spi != null;
}
@@ -133,6 +159,12 @@ public class ADXRS450_Gyro extends GyroBase implements Gyro, PIDSource, Sendable
@Override
public void reset() {
if (m_simAngle != null) {
m_simAngle.set(0.0);
}
if (m_simRate != null) {
m_simRate.set(0.0);
}
if (m_spi != null) {
m_spi.resetAccumulator();
}
@@ -147,10 +179,17 @@ public class ADXRS450_Gyro extends GyroBase implements Gyro, PIDSource, Sendable
m_spi.close();
m_spi = null;
}
if (m_simDevice != null) {
m_simDevice.close();
m_simDevice = null;
}
}
@Override
public double getAngle() {
if (m_simAngle != null) {
return m_simAngle.get();
}
if (m_spi == null) {
return 0.0;
}
@@ -159,6 +198,9 @@ public class ADXRS450_Gyro extends GyroBase implements Gyro, PIDSource, Sendable
@Override
public double getRate() {
if (m_simRate != null) {
return m_simRate.get();
}
if (m_spi == null) {
return 0.0;
}

View File

@@ -12,6 +12,9 @@ import java.util.List;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimBoolean;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
@@ -59,6 +62,10 @@ public class Ultrasonic implements PIDSource, Sendable, AutoCloseable {
private static int m_instances;
protected PIDSourceType m_pidSource = PIDSourceType.kDisplacement;
private SimDevice m_simDevice;
private SimBoolean m_simRangeValid;
private SimDouble m_simRange;
/**
* Background task that goes through the list of ultrasonic sensors and pings each one in turn.
* The counter is configured to read the timing of the returned echo pulse.
@@ -94,6 +101,13 @@ public class Ultrasonic implements PIDSource, Sendable, AutoCloseable {
* then automatic mode is restored.
*/
private synchronized void initialize() {
m_simDevice = SimDevice.create("Ultrasonic", m_echoChannel.getChannel());
if (m_simDevice != null) {
m_simRangeValid = m_simDevice.createBoolean("Range Valid", false, true);
m_simRange = m_simDevice.createDouble("Range (in)", false, 0.0);
m_pingChannel.setSimDevice(m_simDevice);
m_echoChannel.setSimDevice(m_simDevice);
}
if (m_task == null) {
m_task = new UltrasonicChecker();
}
@@ -216,6 +230,11 @@ public class Ultrasonic implements PIDSource, Sendable, AutoCloseable {
if (!m_sensors.isEmpty() && wasAutomaticMode) {
setAutomaticMode(true);
}
if (m_simDevice != null) {
m_simDevice.close();
m_simDevice = null;
}
}
/**
@@ -285,6 +304,9 @@ public class Ultrasonic implements PIDSource, Sendable, AutoCloseable {
* @return true if the range is valid
*/
public boolean isRangeValid() {
if (m_simRangeValid != null) {
return m_simRangeValid.get();
}
return m_counter.get() > 1;
}
@@ -296,6 +318,9 @@ public class Ultrasonic implements PIDSource, Sendable, AutoCloseable {
*/
public double getRangeInches() {
if (isRangeValid()) {
if (m_simRange != null) {
return m_simRange.get();
}
return m_counter.getPeriod() * kSpeedOfSoundInchesPerSec / 2.0;
} else {
return 0;