diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..b3a020c5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "3rdParty/yaml-cpp"] + path = 3rdParty/yaml-cpp + url = https://github.com/jbeder/yaml-cpp.git diff --git a/3rdParty/build.gradle b/3rdParty/build.gradle new file mode 100644 index 00000000..ae2f82a9 --- /dev/null +++ b/3rdParty/build.gradle @@ -0,0 +1,26 @@ +apply plugin: "cpp" +apply plugin: 'visual-studio' +apply plugin: 'edu.wpi.first.NativeUtils' + +apply from: "${rootDir}/common/config.gradle" + + +model { + components { + yamlcpp(NativeLibrarySpec) { + sources { + cpp { + source { + srcDirs = ['yaml-cpp/src'] + includes = ['**/*.cpp'] + } + exportedHeaders { + srcDirs = ["yaml-cpp/include"] + } + } + } + } + + } + +} \ No newline at end of file diff --git a/3rdParty/yaml-cpp b/3rdParty/yaml-cpp new file mode 160000 index 00000000..562aefc1 --- /dev/null +++ b/3rdParty/yaml-cpp @@ -0,0 +1 @@ +Subproject commit 562aefc114938e388457e6a531ed7b54d9dc1b62 diff --git a/appveyor.yml b/appveyor.yml index 61f8ee41..816cfd46 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,6 +5,16 @@ platform: - x86 - x64 +clone_script: +- cmd: >- + git clone -q --branch=%APPVEYOR_REPO_BRANCH% https://github.com/%APPVEYOR_REPO_NAME%.git %APPVEYOR_BUILD_FOLDER% + + cd %APPVEYOR_BUILD_FOLDER% + + git checkout -qf %APPVEYOR_REPO_COMMIT% + + git submodule update --init --recursive + build_script: - ps: >- mkdir build diff --git a/common/gtest.gradle b/common/gtest.gradle new file mode 100644 index 00000000..736d886e --- /dev/null +++ b/common/gtest.gradle @@ -0,0 +1,13 @@ +model { + dependencyConfigs { + googletest(DependencyConfig) { + groupId = 'edu.wpi.first.thirdparty.frc2019' + artifactId = 'googletest' + headerClassifier = 'headers' + ext = 'zip' + version = '1.8.0-4-4e4df22' + sharedConfigs = [:] + staticConfigs = project.staticGtestConfigs + } + } +} diff --git a/settings.gradle b/settings.gradle index f6ec52ab..97a1398d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,6 +17,7 @@ include 'snobot_sim_utilities' include 'snobot_sim_gui' include 'snobot_sim_joysticks' include 'snobot_sim_example_robot' +include '3rdParty' rootProject.name = 'CppSimulator' diff --git a/snobot_sim/src/main/native/cpp/SnobotSim/Config/V1/SimulatorConfigReaderV1.cpp b/snobot_sim/src/main/native/cpp/SnobotSim/Config/V1/SimulatorConfigReaderV1.cpp new file mode 100644 index 00000000..450119e1 --- /dev/null +++ b/snobot_sim/src/main/native/cpp/SnobotSim/Config/V1/SimulatorConfigReaderV1.cpp @@ -0,0 +1,292 @@ + +#include "SnobotSim/Config/SimulatorConfigReaderV1.h" + +#include + +#include + +#include "SnobotSim/Config/SimulatorConfigV1.h" +#include "SnobotSim/GetSensorActuatorHelper.h" +#include "SnobotSim/Logging/SnobotLogger.h" +#include "SnobotSim/ModuleWrapper/Factories/FactoryContainer.h" +#include "SnobotSim/MotorSim/GravityLoadDcMotorSim.h" +#include "SnobotSim/MotorSim/RotationalLoadDcMotorSim.h" +#include "SnobotSim/MotorSim/SimpleMotorSimulator.h" +#include "SnobotSim/MotorSim/StaticLoadDcMotorSim.h" +#include "SnobotSim/SensorActuatorRegistry.h" +#include "yaml-cpp/yaml.h" + +void ParseMap(const YAML::Node& aNode, std::map& aMap) +{ + for (YAML::const_iterator it = aNode.begin(); it != aNode.end(); ++it) + { + aMap[it->first.as()] = it->second.as(); + } +} + +template +void ParseVector(const YAML::Node& aNode, std::vector& aVector) +{ + for (YAML::const_iterator it = aNode.begin(); it != aNode.end(); ++it) + { + T value; + (*it) >> value; + aVector.push_back(value); + } +} + +void LoadBasicConfig(const YAML::Node& aNode, BasicModuleConfig& aOutput) +{ + aOutput.mHandle = aNode["mHandle"].as(); + aOutput.mName = aNode["mName"].as(); + aOutput.mType = aNode["mType"].as(); +} + +const YAML::Node& operator>>(const YAML::Node& aNode, EncoderConfig& aOutput) +{ + LoadBasicConfig(aNode, aOutput); + aOutput.mConnectedSpeedControllerHandle = aNode["mConnectedSpeedControllerHandle"].as(); + return aNode; +} + +const YAML::Node& operator>>(const YAML::Node& aNode, PwmConfig& aOutput) +{ + LoadBasicConfig(aNode, aOutput); + + if (aNode["mMotorSimConfig"]) + { + const YAML::Node& motorSimConfig = aNode["mMotorSimConfig"]; + const std::string& motorSimConfigTag = motorSimConfig.Tag(); + + if (motorSimConfigTag == "tag:yaml.org,2002:com.snobot.simulator.motor_sim.SimpleMotorSimulationConfig") + { + aOutput.mMotorSimConfigType = PwmConfig::Simple; + aOutput.mMotorSimConfig.mSimple.mMaxSpeed = motorSimConfig["mMaxSpeed"].as(); + } + else if (motorSimConfigTag == "tag:yaml.org,2002:com.snobot.simulator.motor_sim.StaticLoadMotorSimulationConfig") + { + aOutput.mMotorSimConfigType = PwmConfig::Static; + aOutput.mMotorSimConfig.mStatic.mLoad = motorSimConfig["mLoad"].as(); + aOutput.mMotorSimConfig.mStatic.mConversionFactor = motorSimConfig["mConversionFactor"].as(); + } + else if (motorSimConfigTag == "tag:yaml.org,2002:com.snobot.simulator.motor_sim.GravityLoadMotorSimulationConfig") + { + aOutput.mMotorSimConfigType = PwmConfig::Gravity; + aOutput.mMotorSimConfig.mGravity.mLoad = motorSimConfig["mLoad"].as(); + } + else if (motorSimConfigTag == "tag:yaml.org,2002:com.snobot.simulator.motor_sim.RotationalLoadMotorSimulationConfig") + { + aOutput.mMotorSimConfigType = PwmConfig::Rotational; + aOutput.mMotorSimConfig.mRotational.mArmCenterOfMass = motorSimConfig["mArmCenterOfMass"].as(); + aOutput.mMotorSimConfig.mRotational.mArmMass = motorSimConfig["mArmMass"].as(); + aOutput.mMotorSimConfig.mRotational.mConstantAssistTorque = motorSimConfig["mConstantAssistTorque"].as(); + aOutput.mMotorSimConfig.mRotational.mOverCenterAssistTorque = motorSimConfig["mOverCenterAssistTorque"].as(); + } + } + else + { + SNOBOT_LOG(SnobotLogging::LOG_LEVEL_CRITICAL, "Thing is null"); + } + + return aNode; +} + +const YAML::Node& operator>>(const YAML::Node& aNode, BasicModuleConfig& aOutput) +{ + LoadBasicConfig(aNode, aOutput); + return aNode; +} + +const YAML::Node& operator>>(const YAML::Node& configNode, SimulatorConfigV1& config) +{ + ParseMap(configNode["mDefaultI2CWrappers"], config.mDefaultI2CWrappers); + ParseMap(configNode["mDefaultSpiWrappers"], config.mDefaultSpiWrappers); + ParseVector(configNode["mAccelerometers"], config.mAccelerometers); + ParseVector(configNode["mAnalogIn"], config.mAnalogIn); + ParseVector(configNode["mAnalogOut"], config.mAnalogOut); + ParseVector(configNode["mDigitalIO"], config.mDigitalIO); + ParseVector(configNode["mGyros"], config.mGyros); + ParseVector(configNode["mRelays"], config.mRelays); + ParseVector(configNode["mSolenoids"], config.mSolenoids); + ParseVector(configNode["mEncoders"], config.mEncoders); + ParseVector(configNode["mPwm"], config.mPwm); + + return configNode; +} + +SimulatorConfigReaderV1::SimulatorConfigReaderV1() +{ +} + +SimulatorConfigReaderV1::~SimulatorConfigReaderV1() +{ +} + +template +void CreateBasicComponent(std::shared_ptr aFactory, const std::map& wrapperMap, const BasicModuleConfig& aConfig) +{ + aFactory->Create(aConfig.mHandle, aConfig.mType); + auto findIter = wrapperMap.find(aConfig.mHandle); + if (findIter != wrapperMap.end()) + { + findIter->second->SetName(aConfig.mName); + } + else + { + SNOBOT_LOG(SnobotLogging::LOG_LEVEL_CRITICAL, "Could not set name for handle " << aConfig.mHandle); + } +} + +template +void CreateBasicComponents(std::shared_ptr aFactory, const std::map& wrapperMap, const std::vector& aConfigs) +{ + for (auto it : aConfigs) + { + CreateBasicComponent(aFactory, wrapperMap, it); + } +} + +void CreatePwmComponents(std::shared_ptr aFactory, const std::map>& wrapperMap, const std::vector& aConfigs) +{ + for (auto it : aConfigs) + { + CreateBasicComponent(aFactory, wrapperMap, it); + + std::shared_ptr speedController = GetSensorActuatorHelper::GetISpeedControllerWrapper(it.mHandle); + if (!speedController) + { + SNOBOT_LOG(SnobotLogging::LOG_LEVEL_CRITICAL, "Invalid Speed Controller " << it.mHandle); + continue; + } + + DcMotorModelConfig::FactoryParams factoryParams( + it.mMotorModelConfig.mFactoryParams.mMotorType, + it.mMotorModelConfig.mFactoryParams.mNumMotors, + it.mMotorModelConfig.mFactoryParams.mGearReduction, + it.mMotorModelConfig.mFactoryParams.mGearboxEfficiency); + + DcMotorModelConfig motorModelConfig( + factoryParams, + it.mMotorModelConfig.mMotorParams.mNominalVoltage, + it.mMotorModelConfig.mMotorParams.mFreeSpeedRpm, + it.mMotorModelConfig.mMotorParams.mFreeCurrent, + it.mMotorModelConfig.mMotorParams.mStallTorque, + it.mMotorModelConfig.mMotorParams.mStallCurrent, + it.mMotorModelConfig.mMotorParams.mMotorInertia, + it.mMotorModelConfig.mFactoryParams.mHasBrake, + it.mMotorModelConfig.mFactoryParams.mInverted); + + DcMotorModel motorModel(motorModelConfig); + + switch (it.mMotorSimConfigType) + { + case PwmConfig::Simple: + { + speedController->SetMotorSimulator(std::shared_ptr(new SimpleMotorSimulator( + it.mMotorSimConfig.mSimple.mMaxSpeed))); + break; + } + case PwmConfig::Static: + { + speedController->SetMotorSimulator(std::shared_ptr(new StaticLoadDcMotorSim( + motorModel, + it.mMotorSimConfig.mStatic.mLoad, + it.mMotorSimConfig.mStatic.mConversionFactor))); + break; + } + case PwmConfig::Gravity: + { + speedController->SetMotorSimulator(std::shared_ptr(new GravityLoadDcMotorSim( + motorModel, + it.mMotorSimConfig.mGravity.mLoad))); + break; + } + case PwmConfig::Rotational: + { + speedController->SetMotorSimulator(std::shared_ptr(new RotationalLoadDcMotorSim( + motorModel, + speedController, + it.mMotorSimConfig.mRotational.mArmCenterOfMass, + it.mMotorSimConfig.mRotational.mArmMass, + it.mMotorSimConfig.mRotational.mConstantAssistTorque, + it.mMotorSimConfig.mRotational.mOverCenterAssistTorque))); + break; + } + case PwmConfig::None: + default: + break; + } + } +} + +void CreateEncoderComponents(std::shared_ptr aFactory, const std::map>& wrapperMap, const std::vector& aConfigs) +{ + for (auto it : aConfigs) + { + CreateBasicComponent(aFactory, wrapperMap, it); + if (it.mHandle != -1 && it.mConnectedSpeedControllerHandle != -1) + { + std::shared_ptr encoder = GetSensorActuatorHelper::GetIEncoderWrapper(it.mHandle); + std::shared_ptr speedController = GetSensorActuatorHelper::GetISpeedControllerWrapper(it.mConnectedSpeedControllerHandle); + if (encoder && speedController) + { + encoder->SetSpeedController(speedController); + } + else + { + SNOBOT_LOG(SnobotLogging::LOG_LEVEL_CRITICAL, "Necessary components not set (" << encoder << ", " << speedController << ")"); + } + } + } +} + +void SetupSimulator(const SimulatorConfigV1& aConfig) +{ + for (auto it : aConfig.mDefaultI2CWrappers) + { + FactoryContainer::Get().GetI2CWrapperFactory()->RegisterDefaultWrapperType(it.first, it.second); + FactoryContainer::Get().GetI2CWrapperFactory()->GetI2CWrapper(it.first); + } + for (auto it : aConfig.mDefaultSpiWrappers) + { + FactoryContainer::Get().GetSpiWrapperFactory()->RegisterDefaultWrapperType(it.first, it.second); + FactoryContainer::Get().GetSpiWrapperFactory()->GetSpiWrapper(it.first); + } + + CreateBasicComponents(FactoryContainer::Get().GetAccelerometerFactory(), SensorActuatorRegistry::Get().GetIAccelerometerWrapperMap(), aConfig.mAccelerometers); + CreateBasicComponents(FactoryContainer::Get().GetAnalogInFactory(), SensorActuatorRegistry::Get().GetIAnalogInWrapperMap(), aConfig.mAnalogIn); + CreateBasicComponents(FactoryContainer::Get().GetAnalogOutFactory(), SensorActuatorRegistry::Get().GetIAnalogOutWrapperMap(), aConfig.mAnalogOut); + CreateBasicComponents(FactoryContainer::Get().GetDigitalIoFactory(), SensorActuatorRegistry::Get().GetIDigitalIoWrapperMap(), aConfig.mDigitalIO); + CreateBasicComponents(FactoryContainer::Get().GetGyroFactory(), SensorActuatorRegistry::Get().GetIGyroWrapperMap(), aConfig.mGyros); + CreateBasicComponents(FactoryContainer::Get().GetRelayFactory(), SensorActuatorRegistry::Get().GetIRelayWrapperMap(), aConfig.mRelays); + CreateBasicComponents(FactoryContainer::Get().GetSolenoidFactory(), SensorActuatorRegistry::Get().GetISolenoidWrapperMap(), aConfig.mSolenoids); + + CreatePwmComponents(FactoryContainer::Get().GetSpeedControllerFactory(), SensorActuatorRegistry::Get().GetISpeedControllerWrapperMap(), aConfig.mPwm); + CreateEncoderComponents(FactoryContainer::Get().GetEncoderFactory(), SensorActuatorRegistry::Get().GetIEncoderWrapperMap(), aConfig.mEncoders); +} + +bool SimulatorConfigReaderV1::LoadConfig(const std::string& aConfigFile) +{ + namespace fs = std::experimental::filesystem; + fs::path configFile = aConfigFile; + + bool success = true; + SNOBOT_LOG(SnobotLogging::LOG_LEVEL_INFO, "Loading config file '" << fs::canonical(configFile) << "'"); + + try + { + YAML::Node configNode = YAML::LoadFile(aConfigFile); + + SimulatorConfigV1 config; + configNode >> config; + + SetupSimulator(config); + } + catch (std::exception& ex) + { + SNOBOT_LOG(SnobotLogging::LOG_LEVEL_CRITICAL, "Could not parse config file... " << ex.what()); + success = false; + } + + return success; +} diff --git a/snobot_sim/src/main/native/cpp/SnobotSim/Config/V1/SimulatorConfigV1.cpp b/snobot_sim/src/main/native/cpp/SnobotSim/Config/V1/SimulatorConfigV1.cpp new file mode 100644 index 00000000..2271fa31 --- /dev/null +++ b/snobot_sim/src/main/native/cpp/SnobotSim/Config/V1/SimulatorConfigV1.cpp @@ -0,0 +1,44 @@ + +#include "SnobotSim/Config/SimulatorConfigV1.h" + +#include + +template +void PrintVector(std::ostream& aStream, const std::string& aName, std::vector& aVector) +{ + aStream << aName << "\n"; + for (unsigned int i = 0; i < aVector.size(); ++i) + { + aVector[i].Print(aStream, " "); + } +} + +void BasicModuleConfig::Print(std::ostream& aStream, const std::string& aIndent) +{ + aStream << aIndent << "Handle: " << mHandle << "\n" + << aIndent << "Name : " << mName << "\n" + << aIndent << "Type : " << mType << "\n"; +} + +void EncoderConfig::Print(std::ostream& aStream, const std::string& aIndent) +{ + BasicModuleConfig::Print(aStream, aIndent); +} + +void PwmConfig::Print(std::ostream& aStream, const std::string& aIndent) +{ + BasicModuleConfig::Print(aStream, aIndent); +} + +void SimulatorConfigV1::Print(std::ostream& aStream) +{ + PrintVector(aStream, "Accel", mAccelerometers); + PrintVector(aStream, "Analog In", mAnalogIn); + PrintVector(aStream, "Analog Out", mAnalogOut); + PrintVector(aStream, "Digital IO", mDigitalIO); + PrintVector(aStream, "Gyro", mGyros); + PrintVector(aStream, "Relay", mRelays); + PrintVector(aStream, "Solenoid", mSolenoids); + PrintVector(aStream, "Encoders", mEncoders); + PrintVector(aStream, "PWM", mPwm); +} diff --git a/snobot_sim/src/main/native/include/SnobotSim/Config/SimulatorConfigReaderV1.h b/snobot_sim/src/main/native/include/SnobotSim/Config/SimulatorConfigReaderV1.h new file mode 100644 index 00000000..14e48c17 --- /dev/null +++ b/snobot_sim/src/main/native/include/SnobotSim/Config/SimulatorConfigReaderV1.h @@ -0,0 +1,15 @@ + +#pragma once + +#include + +#include "SnobotSim/ExportHelper.h" + +class EXPORT_ SimulatorConfigReaderV1 +{ +public: + SimulatorConfigReaderV1(); + virtual ~SimulatorConfigReaderV1(); + + bool LoadConfig(const std::string& aConfigFile); +}; diff --git a/snobot_sim/src/main/native/include/SnobotSim/Config/SimulatorConfigV1.h b/snobot_sim/src/main/native/include/SnobotSim/Config/SimulatorConfigV1.h new file mode 100644 index 00000000..30131692 --- /dev/null +++ b/snobot_sim/src/main/native/include/SnobotSim/Config/SimulatorConfigV1.h @@ -0,0 +1,115 @@ + +#pragma once + +#include +#include +#include + +struct BasicModuleConfig +{ + int mHandle = 0; + std::string mName = ""; + std::string mType = ""; + + virtual void Print(std::ostream& aStream, const std::string& aIndent = ""); +}; + +struct EncoderConfig : public BasicModuleConfig +{ + int mConnectedSpeedControllerHandle = -1; + + void Print(std::ostream& aStream, const std::string& aIndent = "") override; +}; + +struct SimpleMotorSimulationConfig +{ + double mMaxSpeed; +}; + +struct StaticLoadMotorSimulationConfig +{ + double mLoad; + double mConversionFactor; +}; + +struct GravityLoadMotorSimulationConfig +{ + double mLoad; +}; + +struct DcMotorModelConfigConfig +{ + struct FactoryParams + { + std::string mMotorType; + int mNumMotors; + double mGearReduction; + double mGearboxEfficiency; + + bool mInverted; + bool mHasBrake; + }; + + struct MotorParams + { + double mNominalVoltage; + double mFreeSpeedRpm; + double mFreeCurrent; + double mStallTorque; + double mStallCurrent; + double mMotorInertia; + }; + + FactoryParams mFactoryParams; + MotorParams mMotorParams; +}; + +struct RotationalLoadMotorSimulationConfig +{ + double mArmCenterOfMass; + double mArmMass; + double mConstantAssistTorque; + double mOverCenterAssistTorque; +}; + +struct PwmConfig : public BasicModuleConfig +{ + union MotorSimConfig { + SimpleMotorSimulationConfig mSimple; + StaticLoadMotorSimulationConfig mStatic; + GravityLoadMotorSimulationConfig mGravity; + RotationalLoadMotorSimulationConfig mRotational; + }; + + enum MotorSimConfigType + { + None, + Simple, + Static, + Gravity, + Rotational, + }; + + MotorSimConfig mMotorSimConfig; + MotorSimConfigType mMotorSimConfigType = None; + DcMotorModelConfigConfig mMotorModelConfig; + + void Print(std::ostream& aStream, const std::string& aIndent = "") override; +}; + +struct SimulatorConfigV1 +{ + std::vector mAccelerometers; + std::vector mAnalogIn; + std::vector mAnalogOut; + std::vector mDigitalIO; + std::vector mGyros; + std::vector mRelays; + std::vector mSolenoids; + std::vector mEncoders; + std::vector mPwm; + std::map mDefaultI2CWrappers; + std::map mDefaultSpiWrappers; + + virtual void Print(std::ostream& aStream); +}; diff --git a/snobot_sim/src/main/native/include/SnobotSim/StartStandaloneSimulatorMacro.h b/snobot_sim/src/main/native/include/SnobotSim/StartStandaloneSimulatorMacro.h index f3ec5fb2..9e792ce7 100644 --- a/snobot_sim/src/main/native/include/SnobotSim/StartStandaloneSimulatorMacro.h +++ b/snobot_sim/src/main/native/include/SnobotSim/StartStandaloneSimulatorMacro.h @@ -9,16 +9,19 @@ #include +#include "SnobotSim/Config/SimulatorConfigReaderV1.h" #include "SnobotSim/Logging/SnobotLogger.h" #include "SnobotSim/StandaloneSimulator.h" -#define START_STANDALONE_SIMULATOR(_ClassName_, _SimulatorName_) \ - int main() \ - { \ - SnobotSim::InitializeStandaloneSim(); \ - SNOBOT_LOG(SnobotLogging::LOG_LEVEL_INFO, "Starting SnobotSim with " << #_ClassName_ << " with simulator " << #_SimulatorName_); \ - static _ClassName_ robot; \ - static _SimulatorName_ simulator; \ - std::thread t(&_SimulatorName_::UpdateSimulatorComponentsThread, simulator); \ - robot.StartCompetition(); \ +#define START_STANDALONE_SIMULATOR(_ClassName_, _SimulatorName_, _SimulatorConfigFile_) \ + int main() \ + { \ + SnobotSim::InitializeStandaloneSim(); \ + SNOBOT_LOG(SnobotLogging::LOG_LEVEL_INFO, "Starting SnobotSim with " << #_ClassName_ << " with simulator " << #_SimulatorName_ << ", and config file '" << _SimulatorConfigFile_ << "'"); \ + SimulatorConfigReaderV1 configReader; \ + configReader.LoadConfig(_SimulatorConfigFile_); \ + static _ClassName_ robot; \ + static _SimulatorName_ simulator; \ + std::thread t(&_SimulatorName_::UpdateSimulatorComponentsThread, simulator); \ + robot.StartCompetition(); \ } diff --git a/snobot_sim/src/test/native/cpp/Config/SimulatorConfigReaderV1Test.cpp b/snobot_sim/src/test/native/cpp/Config/SimulatorConfigReaderV1Test.cpp new file mode 100644 index 00000000..624d02ed --- /dev/null +++ b/snobot_sim/src/test/native/cpp/Config/SimulatorConfigReaderV1Test.cpp @@ -0,0 +1,15 @@ + +#include "SnobotSim/Config/SimulatorConfigReaderV1.h" +#include "gtest/gtest.h" + +TEST(LoadConfigFile, TestGoodFile) +{ + SimulatorConfigReaderV1 configReader; + EXPECT_TRUE(configReader.LoadConfig("F:/git/FIRST/SnobotSim/examples/CppWithGuiExample/simulator_config/simulator_config.yml")); +} + +TEST(LoadConfigFile, TestMissingFile) +{ + SimulatorConfigReaderV1 configReader; + EXPECT_FALSE(configReader.LoadConfig("File/Does/Not/Exist.yml")); +} diff --git a/snobot_sim/src/test/native/cpp/main.cpp b/snobot_sim/src/test/native/cpp/main.cpp new file mode 100644 index 00000000..b78a5409 --- /dev/null +++ b/snobot_sim/src/test/native/cpp/main.cpp @@ -0,0 +1,18 @@ + +#include "SnobotSim/Logging/SnobotCoutLogger.h" +#include "SnobotSim/Logging/SnobotLogger.h" +#include "gtest/gtest.h" + +int main(int argc, char** argv) +{ + SnobotLogging::SnobotCoutLogger logger; + logger.SetLogLevel(SnobotLogging::LOG_LEVEL_INFO); + SnobotLogging::SetLogger(&logger); + + ::testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + + SnobotLogging::SetLogger(NULL); + + return ret; +} diff --git a/snobot_sim_gui/src/main/java/com/snobot/simulator/ASimulator.java b/snobot_sim_gui/src/main/java/com/snobot/simulator/ASimulator.java index 10fe0ccf..91a47f00 100644 --- a/snobot_sim_gui/src/main/java/com/snobot/simulator/ASimulator.java +++ b/snobot_sim_gui/src/main/java/com/snobot/simulator/ASimulator.java @@ -1,7 +1,7 @@ package com.snobot.simulator; -import com.snobot.simulator.config.v1.SimulatorConfigReaderV1; import com.snobot.simulator.robot_container.IRobotClassContainer; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; /** * Base class for a custom simulator. @@ -11,18 +11,17 @@ */ public class ASimulator implements ISimulatorUpdater { - private final SimulatorConfigReaderV1 mConfigReader; private String mConfigFile; protected ASimulator() { - mConfigReader = new SimulatorConfigReaderV1(); + } public boolean loadConfig(String aConfigFile) { mConfigFile = aConfigFile; - return mConfigReader.loadConfig(mConfigFile); + return DataAccessorFactory.getInstance().getSimulatorDataAccessor().loadConfigFile(mConfigFile); } diff --git a/snobot_sim_gui/src/main/java/com/snobot/simulator/gui/SimulatorFrame.java b/snobot_sim_gui/src/main/java/com/snobot/simulator/gui/SimulatorFrame.java index 1a867f21..8f717de4 100644 --- a/snobot_sim_gui/src/main/java/com/snobot/simulator/gui/SimulatorFrame.java +++ b/snobot_sim_gui/src/main/java/com/snobot/simulator/gui/SimulatorFrame.java @@ -16,8 +16,8 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import com.snobot.simulator.config.SimulatorConfigWriter; import com.snobot.simulator.gui.joysticks.JoystickManagerDialog; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; /** * Top level frame that displays all of the simulation displays @@ -123,8 +123,6 @@ public void actionPerformed(ActionEvent aEvent) private void saveSettings() { - SimulatorConfigWriter writer = new SimulatorConfigWriter(); - String dumpFile = null; if (mSimulatorConfigFile == null) @@ -156,7 +154,7 @@ private void saveSettings() mSimulatorConfigFile = dumpFile; } - writer.writeConfig(dumpFile); + DataAccessorFactory.getInstance().getSimulatorDataAccessor().saveConfigFile(dumpFile); } showSettingsOptions(false); diff --git a/snobot_sim_java/src/main/java/com/snobot/simulator/wrapper_accessors/java/JavaSimulatorDataAccessor.java b/snobot_sim_java/src/main/java/com/snobot/simulator/wrapper_accessors/java/JavaSimulatorDataAccessor.java index 98c4bf7f..6459b00d 100644 --- a/snobot_sim_java/src/main/java/com/snobot/simulator/wrapper_accessors/java/JavaSimulatorDataAccessor.java +++ b/snobot_sim_java/src/main/java/com/snobot/simulator/wrapper_accessors/java/JavaSimulatorDataAccessor.java @@ -213,4 +213,5 @@ public boolean saveConfigFile(String aConfigFile) { return new SimulatorConfigWriter().writeConfig(aConfigFile); } + } diff --git a/snobot_sim_jni/build.gradle b/snobot_sim_jni/build.gradle index 8decddfe..0314017e 100644 --- a/snobot_sim_jni/build.gradle +++ b/snobot_sim_jni/build.gradle @@ -79,6 +79,8 @@ dependencies { apply from: "${rootDir}/common/extract_native_libraries.gradle" test.dependsOn extract_wpilib +test.dependsOn project(':snobot_sim').packageNativeFilesInJar +test.dependsOn project(':snobot_sim_jni').packageNativeFiles model { diff --git a/snobot_sim_jni/src/main/java/com/snobot/simulator/jni/SnobotSimulatorJni.java b/snobot_sim_jni/src/main/java/com/snobot/simulator/jni/SnobotSimulatorJni.java index 745c43eb..c366df72 100644 --- a/snobot_sim_jni/src/main/java/com/snobot/simulator/jni/SnobotSimulatorJni.java +++ b/snobot_sim_jni/src/main/java/com/snobot/simulator/jni/SnobotSimulatorJni.java @@ -17,4 +17,8 @@ private SnobotSimulatorJni() public static native String getVersion(); public static native void initializeLogging(int aLogLevel); + + public static native boolean loadConfigFile(String aConfigFile); + + public static native boolean saveConfigFile(String aConfigFile); } diff --git a/snobot_sim_jni/src/main/java/com/snobot/simulator/wrapper_accessors/jni/JniSimulatorDataAccessor.java b/snobot_sim_jni/src/main/java/com/snobot/simulator/wrapper_accessors/jni/JniSimulatorDataAccessor.java index 839cb745..df956cb0 100644 --- a/snobot_sim_jni/src/main/java/com/snobot/simulator/wrapper_accessors/jni/JniSimulatorDataAccessor.java +++ b/snobot_sim_jni/src/main/java/com/snobot/simulator/wrapper_accessors/jni/JniSimulatorDataAccessor.java @@ -105,18 +105,18 @@ public void removeSimulatorComponent(Object aComp) } + @Override public boolean loadConfigFile(String aConfigFile) { - // TODO Auto-generated method stub - return false; + return SnobotSimulatorJni.loadConfigFile(aConfigFile); } + @Override public boolean saveConfigFile(String aConfigFile) { - // TODO Auto-generated method stub - return false; + return SnobotSimulatorJni.saveConfigFile(aConfigFile); } } diff --git a/snobot_sim_jni/src/main/native/cpp/SnobotSimHal/SnobotSimulatorJni.cpp b/snobot_sim_jni/src/main/native/cpp/SnobotSimHal/SnobotSimulatorJni.cpp index 8ae821ab..93ded903 100644 --- a/snobot_sim_jni/src/main/native/cpp/SnobotSimHal/SnobotSimulatorJni.cpp +++ b/snobot_sim_jni/src/main/native/cpp/SnobotSimHal/SnobotSimulatorJni.cpp @@ -4,6 +4,7 @@ #include #include "hal/HAL.h" +#include "SnobotSim/Config/SimulatorConfigReaderV1.h" #include "SnobotSim/HalCallbacks/CallbackSetup.h" #include "SnobotSim/Logging/SnobotCoutLogger.h" #include "SnobotSim/Logging/SnobotLogger.h" @@ -127,4 +128,40 @@ JNIEXPORT jboolean JNICALL Java_com_snobot_simulator_jni_SimulationConnectorJni_ return true; } + +/* + * Class: com_snobot_simulator_jni_SnobotSimulatorJni + * Method: loadConfigFile + * Signature: (Ljava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL Java_com_snobot_simulator_jni_SnobotSimulatorJni_loadConfigFile + (JNIEnv * env, jclass, jstring aFilename) +{ + if(aFilename == NULL) + { + SNOBOT_LOG(SnobotLogging::LOG_LEVEL_CRITICAL, "Simulator file was null! Won't hook anything up"); + return true; + } + + SimulatorConfigReaderV1 configReader; + return configReader.LoadConfig(env->GetStringUTFChars(aFilename, NULL)); +} + +/* + * Class: com_snobot_simulator_jni_SnobotSimulatorJni + * Method: saveConfigFile + * Signature: (Ljava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL Java_com_snobot_simulator_jni_SnobotSimulatorJni_saveConfigFile + (JNIEnv * env, jclass, jstring aFilename) +{ + if(aFilename == NULL) + { + SNOBOT_LOG(SnobotLogging::LOG_LEVEL_CRITICAL, "Simulator file was null!"); + return false; + } + + return false; +} + } // extern "C" diff --git a/snobot_sim_jni/src/test/java/com/snobot/simulator/config/TestReadConfig.java b/snobot_sim_jni/src/test/java/com/snobot/simulator/config/TestReadConfig.java new file mode 100644 index 00000000..a389fa2e --- /dev/null +++ b/snobot_sim_jni/src/test/java/com/snobot/simulator/config/TestReadConfig.java @@ -0,0 +1,103 @@ +package com.snobot.simulator.config; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.snobot.simulator.motor_sim.SimpleMotorSimulationConfig; +import com.snobot.simulator.motor_sim.StaticLoadMotorSimulationConfig; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; +import com.snobot.test.utilities.BaseSimulatorJniTest; + + +public class TestReadConfig extends BaseSimulatorJniTest +{ + @Test + public void testReadEmptyFile() + { + String file = "test_files/ConfigTest/ReadConfig/emptyFile.yml"; + Assertions.assertTrue(DataAccessorFactory.getInstance().getSimulatorDataAccessor().loadConfigFile(file)); + } + + @Test + public void testReadNullFile() + { + String file = null; + Assertions.assertTrue(DataAccessorFactory.getInstance().getSimulatorDataAccessor().loadConfigFile(file)); + } + + @Test + public void testReadNonExistingFile() + { + String file = "does_not_exist.yml"; + Assertions.assertFalse(DataAccessorFactory.getInstance().getSimulatorDataAccessor().loadConfigFile(file)); + } + + @Test + public void testReadConfig() + { + String file = "test_files/ConfigTest/ReadConfig/testReadFile.yml"; + Assertions.assertTrue(DataAccessorFactory.getInstance().getSimulatorDataAccessor().loadConfigFile(file)); + + Assertions.assertEquals("I2C ADXL345 X Accel", DataAccessorFactory.getInstance().getAccelerometerAccessor().getName(50)); + Assertions.assertEquals("I2C ADXL345 Y Accel", DataAccessorFactory.getInstance().getAccelerometerAccessor().getName(51)); + Assertions.assertEquals("I2C ADXL345 Z Accel", DataAccessorFactory.getInstance().getAccelerometerAccessor().getName(52)); + Assertions.assertEquals("SPI ADXL345 X Accel", DataAccessorFactory.getInstance().getAccelerometerAccessor().getName(103)); + Assertions.assertEquals("SPI ADXL345 Y Accel", DataAccessorFactory.getInstance().getAccelerometerAccessor().getName(104)); + Assertions.assertEquals("SPI ADXL345 Z Accel", DataAccessorFactory.getInstance().getAccelerometerAccessor().getName(105)); + Assertions.assertEquals("SPI ADXL362 X Accel", DataAccessorFactory.getInstance().getAccelerometerAccessor().getName(156)); + Assertions.assertEquals("SPI ADXL362 Y Accel", DataAccessorFactory.getInstance().getAccelerometerAccessor().getName(157)); + Assertions.assertEquals("SPI ADXL362 Z Accel", DataAccessorFactory.getInstance().getAccelerometerAccessor().getName(158)); + + Assertions.assertEquals("Analog In 0", DataAccessorFactory.getInstance().getAnalogInAccessor().getName(0)); + Assertions.assertEquals("Analog In 1", DataAccessorFactory.getInstance().getAnalogInAccessor().getName(1)); + Assertions.assertEquals("Analog In 2", DataAccessorFactory.getInstance().getAnalogInAccessor().getName(2)); + + Assertions.assertEquals("Digital IO 0", DataAccessorFactory.getInstance().getDigitalAccessor().getName(0)); + Assertions.assertEquals("Digital IO 1", DataAccessorFactory.getInstance().getDigitalAccessor().getName(1)); + Assertions.assertEquals("Digital IO 2", DataAccessorFactory.getInstance().getDigitalAccessor().getName(2)); + Assertions.assertEquals("Digital IO 3", DataAccessorFactory.getInstance().getDigitalAccessor().getName(3)); + Assertions.assertEquals("Digital IO 4", DataAccessorFactory.getInstance().getDigitalAccessor().getName(4)); + Assertions.assertEquals("Digital IO 5", DataAccessorFactory.getInstance().getDigitalAccessor().getName(5)); + Assertions.assertEquals("Digital IO 6", DataAccessorFactory.getInstance().getDigitalAccessor().getName(6)); + Assertions.assertEquals("Digital IO 7", DataAccessorFactory.getInstance().getDigitalAccessor().getName(7)); + Assertions.assertEquals("Digital IO 8", DataAccessorFactory.getInstance().getDigitalAccessor().getName(8)); + Assertions.assertEquals("Digital IO 9", DataAccessorFactory.getInstance().getDigitalAccessor().getName(9)); + + Assertions.assertEquals("Encoder 0", DataAccessorFactory.getInstance().getEncoderAccessor().getName(0)); + Assertions.assertEquals("Encoder 1", DataAccessorFactory.getInstance().getEncoderAccessor().getName(1)); + Assertions.assertEquals("Encoder 2", DataAccessorFactory.getInstance().getEncoderAccessor().getName(2)); + Assertions.assertTrue(DataAccessorFactory.getInstance().getEncoderAccessor().isHookedUp(0)); + Assertions.assertFalse(DataAccessorFactory.getInstance().getEncoderAccessor().isHookedUp(1)); + Assertions.assertFalse(DataAccessorFactory.getInstance().getEncoderAccessor().isHookedUp(2)); + Assertions.assertEquals(1, DataAccessorFactory.getInstance().getEncoderAccessor().getHookedUpId(0)); + + Assertions.assertEquals("Analog Gyro", DataAccessorFactory.getInstance().getGyroAccessor().getName(1)); + + Assertions.assertEquals("Speed Controller 0", DataAccessorFactory.getInstance().getSpeedControllerAccessor().getName(0)); + Assertions.assertEquals("Speed Controller 1", DataAccessorFactory.getInstance().getSpeedControllerAccessor().getName(1)); + Assertions.assertEquals("Speed Controller 2", DataAccessorFactory.getInstance().getSpeedControllerAccessor().getName(2)); + Assertions.assertEquals("Speed Controller 3", DataAccessorFactory.getInstance().getSpeedControllerAccessor().getName(3)); + Assertions.assertEquals("Speed Controller 4", DataAccessorFactory.getInstance().getSpeedControllerAccessor().getName(4)); + Assertions.assertEquals("Speed Controller 5", DataAccessorFactory.getInstance().getSpeedControllerAccessor().getName(5)); + // Assertions.assertEquals("Speed Controller 6", + // DataAccessorFactory.getInstance().getSpeedControllerAccessor().getName(6)); + Assertions.assertEquals("Speed Controller 7", DataAccessorFactory.getInstance().getSpeedControllerAccessor().getName(7)); + Assertions.assertEquals("Speed Controller 8", DataAccessorFactory.getInstance().getSpeedControllerAccessor().getName(8)); + + Assertions.assertEquals("Relay 0", DataAccessorFactory.getInstance().getRelayAccessor().getName(0)); + + Assertions.assertEquals("Solenoid 0", DataAccessorFactory.getInstance().getSolenoidAccessor().getName(0)); + Assertions.assertEquals("Solenoid 1", DataAccessorFactory.getInstance().getSolenoidAccessor().getName(1)); + Assertions.assertEquals("Solenoid 3", DataAccessorFactory.getInstance().getSolenoidAccessor().getName(3)); + + { + SimpleMotorSimulationConfig config = DataAccessorFactory.getInstance().getSpeedControllerAccessor().getMotorSimSimpleModelConfig(0); + Assertions.assertEquals(12, config.mMaxSpeed, DOUBLE_EPSILON); + } + { + StaticLoadMotorSimulationConfig config = DataAccessorFactory.getInstance().getSpeedControllerAccessor().getMotorSimStaticModelConfig(1); + Assertions.assertEquals(.5, config.mLoad, DOUBLE_EPSILON); + Assertions.assertEquals(6.28, config.mConversionFactor, DOUBLE_EPSILON); + } + } +} diff --git a/snobot_sim_jni/test_files/ConfigTest/ReadConfig/emptyFile.yml b/snobot_sim_jni/test_files/ConfigTest/ReadConfig/emptyFile.yml new file mode 100644 index 00000000..9d0b8220 --- /dev/null +++ b/snobot_sim_jni/test_files/ConfigTest/ReadConfig/emptyFile.yml @@ -0,0 +1,2 @@ +!!com.snobot.simulator.config.SimulatorConfig +{} diff --git a/snobot_sim_jni/test_files/ConfigTest/ReadConfig/testReadFile.yml b/snobot_sim_jni/test_files/ConfigTest/ReadConfig/testReadFile.yml new file mode 100644 index 00000000..08466ff8 --- /dev/null +++ b/snobot_sim_jni/test_files/ConfigTest/ReadConfig/testReadFile.yml @@ -0,0 +1,201 @@ +!!com.snobot.simulator.config.v1.SimulatorConfigV1 +mAccelerometers: +- mHandle: 50 + mName: I2C ADXL345 X Accel + mType: com.snobot.simulator.module_wrapper.BaseAccelerometerWrapper +- mHandle: 51 + mName: I2C ADXL345 Y Accel + mType: com.snobot.simulator.module_wrapper.BaseAccelerometerWrapper +- mHandle: 52 + mName: I2C ADXL345 Z Accel + mType: com.snobot.simulator.module_wrapper.BaseAccelerometerWrapper +- mHandle: 103 + mName: SPI ADXL345 X Accel + mType: com.snobot.simulator.module_wrapper.BaseAccelerometerWrapper +- mHandle: 104 + mName: SPI ADXL345 Y Accel + mType: com.snobot.simulator.module_wrapper.BaseAccelerometerWrapper +- mHandle: 105 + mName: SPI ADXL345 Z Accel + mType: com.snobot.simulator.module_wrapper.BaseAccelerometerWrapper +- mHandle: 156 + mName: SPI ADXL362 X Accel + mType: com.snobot.simulator.module_wrapper.BaseAccelerometerWrapper +- mHandle: 157 + mName: SPI ADXL362 Y Accel + mType: com.snobot.simulator.module_wrapper.BaseAccelerometerWrapper +- mHandle: 158 + mName: SPI ADXL362 Z Accel + mType: com.snobot.simulator.module_wrapper.BaseAccelerometerWrapper +mAnalogIn: +- mHandle: 0 + mName: Analog In 0 + mType: com.snobot.simulator.module_wrapper.wpi.WpiAnalogInWrapper +- mHandle: 1 + mName: Analog In 1 + mType: com.snobot.simulator.module_wrapper.wpi.WpiAnalogInWrapper +- mHandle: 2 + mName: Analog In 2 + mType: com.snobot.simulator.module_wrapper.wpi.WpiAnalogInWrapper +mAnalogOut: +- mHandle: 1 + mName: Analog Out 1 + mType: com.snobot.simulator.module_wrapper.wpi.WpiAnalogOutWrapper +mDefaultI2CWrappers: + 0: ADXL345 +mDefaultSpiWrappers: + 0: ADXRS450 + 1: ADXL345 + 2: ADXL362 + 3: ADXRS450 +mDigitalIO: +- mHandle: 0 + mName: Digital IO 0 + mType: com.snobot.simulator.module_wrapper.wpi.WpiDigitalIoWrapper +- mHandle: 1 + mName: Digital IO 1 + mType: com.snobot.simulator.module_wrapper.wpi.WpiDigitalIoWrapper +- mHandle: 2 + mName: Digital IO 2 + mType: com.snobot.simulator.module_wrapper.wpi.WpiDigitalIoWrapper +- mHandle: 3 + mName: Digital IO 3 + mType: com.snobot.simulator.module_wrapper.wpi.WpiDigitalIoWrapper +- mHandle: 4 + mName: Digital IO 4 + mType: com.snobot.simulator.module_wrapper.wpi.WpiDigitalIoWrapper +- mHandle: 5 + mName: Digital IO 5 + mType: com.snobot.simulator.module_wrapper.wpi.WpiDigitalIoWrapper +- mHandle: 6 + mName: Digital IO 6 + mType: com.snobot.simulator.module_wrapper.wpi.WpiDigitalIoWrapper +- mHandle: 7 + mName: Digital IO 7 + mType: com.snobot.simulator.module_wrapper.wpi.WpiDigitalIoWrapper +- mHandle: 8 + mName: Digital IO 8 + mType: com.snobot.simulator.module_wrapper.wpi.WpiDigitalIoWrapper +- mHandle: 9 + mName: Digital IO 9 + mType: com.snobot.simulator.module_wrapper.wpi.WpiDigitalIoWrapper +mEncoders: +- mConnectedSpeedControllerHandle: 1 + mHandle: 0 + mName: Encoder 0 + mType: com.snobot.simulator.module_wrapper.wpi.WpiEncoderWrapper +- mConnectedSpeedControllerHandle: -1 + mHandle: 1 + mName: Encoder 1 + mType: com.snobot.simulator.module_wrapper.wpi.WpiEncoderWrapper +- mConnectedSpeedControllerHandle: -1 + mHandle: 2 + mName: Encoder 2 + mType: com.snobot.simulator.module_wrapper.wpi.WpiEncoderWrapper +mGyros: +- mHandle: 1 + mName: Analog Gyro + mType: com.snobot.simulator.module_wrapper.wpi.WpiAnalogGyroWrapper +- mHandle: 100 + mName: ADXRS450 Gyro + mType: com.snobot.simulator.simulator_components.adx_family.ADXRS450GyroWrapper +- mHandle: 103 + mName: ADXRS450 Gyro + mType: com.snobot.simulator.simulator_components.adx_family.ADXRS450GyroWrapper +mPwm: +- mHandle: 0 + mMotorModelConfig: null + mMotorSimConfig: !!com.snobot.simulator.motor_sim.SimpleMotorSimulationConfig + mMaxSpeed: 12.0 + mName: Speed Controller 0 + mType: com.snobot.simulator.module_wrapper.wpi.WpiPwmWrapper +- mHandle: 1 + mMotorModelConfig: + mGearReduction: 10.0 + mGearboxEfficiency: 1.0 + mHasBrake: false + mInverted: false + mMotorType: RS775 + mNumMotors: 1 + mMotorSimConfig: !!com.snobot.simulator.motor_sim.StaticLoadMotorSimulationConfig + mConversionFactor: 6.28 + mLoad: 0.5 + mName: Speed Controller 1 + mType: com.snobot.simulator.module_wrapper.wpi.WpiPwmWrapper +- mHandle: 2 + mMotorModelConfig: + mGearReduction: 10.0 + mGearboxEfficiency: 1.0 + mHasBrake: false + mInverted: false + mMotorType: RS775 + mNumMotors: 1 + mMotorSimConfig: !!com.snobot.simulator.motor_sim.GravityLoadMotorSimulationConfig + mLoad: 0.5 + mName: Speed Controller 2 + mType: com.snobot.simulator.module_wrapper.wpi.WpiPwmWrapper +- mHandle: 3 + mMotorModelConfig: + mGearReduction: 10.0 + mGearboxEfficiency: 1.0 + mHasBrake: false + mInverted: false + mMotorType: RS775 + mNumMotors: 1 + mMotorSimConfig: !!com.snobot.simulator.motor_sim.RotationalLoadMotorSimulationConfig + mArmCenterOfMass: 1.0 + mArmMass: 1.0 + mConstantAssistTorque: 0.0 + mOverCenterAssistTorque: 0.0 + mName: Speed Controller 3 + mType: com.snobot.simulator.module_wrapper.wpi.WpiPwmWrapper +- mHandle: 4 + mMotorModelConfig: null + mMotorSimConfig: null + mName: Speed Controller 4 + mType: com.snobot.simulator.module_wrapper.wpi.WpiPwmWrapper +- mHandle: 5 + mMotorModelConfig: null + mMotorSimConfig: null + mName: Speed Controller 5 + mType: com.snobot.simulator.module_wrapper.wpi.WpiPwmWrapper +- mHandle: 7 + mMotorModelConfig: null + mMotorSimConfig: null + mName: Speed Controller 7 + mType: com.snobot.simulator.module_wrapper.wpi.WpiPwmWrapper +- mHandle: 8 + mMotorModelConfig: null + mMotorSimConfig: null + mName: Speed Controller 8 + mType: com.snobot.simulator.module_wrapper.wpi.WpiPwmWrapper +mRelays: +- mHandle: 0 + mName: Relay 0 + mType: com.snobot.simulator.module_wrapper.wpi.WpiRelayWrapper +mSimulatorComponents: +- !!com.snobot.simulator.simulator_components.config.TankDriveConfig + mGyroHandle: 1 + mLeftMotorHandle: 0 + mRightMotorHandle: 1 + mTurnKp: 0.5 +- !!com.snobot.simulator.simulator_components.config.TankDriveConfig + mGyroHandle: 100 + mLeftMotorHandle: 0 + mRightMotorHandle: 1 + mTurnKp: 1.0 +- !!com.snobot.simulator.simulator_components.config.TankDriveConfig + mGyroHandle: 103 + mLeftMotorHandle: 0 + mRightMotorHandle: 1 + mTurnKp: 2.0 +mSolenoids: +- mHandle: 0 + mName: Solenoid 0 + mType: com.snobot.simulator.module_wrapper.wpi.WpiSolenoidWrapper +- mHandle: 1 + mName: Solenoid 1 + mType: com.snobot.simulator.module_wrapper.wpi.WpiSolenoidWrapper +- mHandle: 3 + mName: Solenoid 3 + mType: com.snobot.simulator.module_wrapper.wpi.WpiSolenoidWrapper