diff --git a/src/dev/apsabelhaus/tgBoxAnchorDebugDemo/AppTgBoxAnchorDebugDemo.cpp b/src/dev/apsabelhaus/tgBoxAnchorDebugDemo/AppTgBoxAnchorDebugDemo.cpp index 39057b0fe..b58e30c67 100644 --- a/src/dev/apsabelhaus/tgBoxAnchorDebugDemo/AppTgBoxAnchorDebugDemo.cpp +++ b/src/dev/apsabelhaus/tgBoxAnchorDebugDemo/AppTgBoxAnchorDebugDemo.cpp @@ -33,6 +33,7 @@ #include "core/tgSimViewGraphics.h" #include "core/tgSimulation.h" #include "core/tgWorld.h" +#include "sensors/tgDataLogger2.h" // Bullet Physics #include "LinearMath/btVector3.h" // The C++ Standard Library @@ -79,6 +80,15 @@ int main(int argc, char** argv) // Finally, add out model to the simulation simulation.addModel(myModel); + + // For the sensors: + // A string prefix for the filename + std::string log_filename = "~/NTRTsim_logs/AppTgBoxAnchorDebugDemo"; + // First, create the data manager + tgDataLogger2* myDataLogger = new tgDataLogger2(log_filename); + // Next, attach it to the simulation + simulation.addDataManager(myDataLogger); + // and everything else should happen automatically. // Run until the user stops simulation.run(); diff --git a/src/sensors/CMakeLists.txt b/src/sensors/CMakeLists.txt index 056cfdaf6..15d320034 100644 --- a/src/sensors/CMakeLists.txt +++ b/src/sensors/CMakeLists.txt @@ -10,6 +10,7 @@ add_library( ${PROJECT_NAME} SHARED # For the new sensors tgDataManager.cpp + tgDataLogger2.cpp tgSensor.cpp tgRodSensor.cpp ) diff --git a/src/sensors/SensorsRedesignOutline_2017-01-03.docx b/src/sensors/SensorsRedesignOutline_2017-01-03.docx index 77e778140..4a7a7b4c9 100644 Binary files a/src/sensors/SensorsRedesignOutline_2017-01-03.docx and b/src/sensors/SensorsRedesignOutline_2017-01-03.docx differ diff --git a/src/sensors/tgDataLogger2.cpp b/src/sensors/tgDataLogger2.cpp new file mode 100644 index 000000000..a18ff53a4 --- /dev/null +++ b/src/sensors/tgDataLogger2.cpp @@ -0,0 +1,153 @@ +/* + * Copyright © 2012, United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The NASA Tensegrity Robotics Toolkit (NTRT) v1 platform is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. +*/ + +/** + * @file tgDataLogger2.cpp + * @brief Contains the implementation of concrete class tgDataLogger2 + * @author Drew Sabelhaus + * $Id$ + */ + +// This module +//#include "tgDataManager.h" +#include "tgDataLogger2.h" +// This application +#include "tgSensor.h" +//#include "tgSensorInfo.h" +// The C++ Standard Library +//#include // for sprintf +#include +#include +#include + +/** + * The constructor for this class only assigns the filename prefix. + * The actual filename is created in setup. + * This makes it so that, upon reset, a new log file is opened (instead of + * appending to the same one.) + * Call the constructor of the parent class anyway, though it does nothing. + */ +tgDataLogger2::tgDataLogger2(std::string fileNamePrefix) : + tgDataManager(), + m_fileNamePrefix(fileNamePrefix) +{ + //DEBUGGING + std::cout << "tgDataLogger2 constructor." << std::endl; + // Postcondition + assert(invariant()); +} + +/** + * The destructor should not have to do anything. + * Closing the log file is handled by teardown(), and the parent class + * handles deletion of the sensors and sensor infos. + */ +tgDataLogger2::~tgDataLogger2() +{ + //DEBUGGING + std::cout << "tgDataLogger2 destructor." << std::endl; +} + +/** + * Setup will do three things: + * (1) create the full filename, based on the current time from the operating system, + * (2) create the sensors based on the sensor infos that have been added and + * the senseable objects that have also been added, + * (3) opens the log file and writes a heading line (then closes the file.) + */ +void tgDataLogger2::setup() +{ + // Although the parent class doesn't do much in setup at the moment, + // call it here anyway, in case that changes! + tgDataManager::setup(); + //DEBUGGING + std::cout << "tgDataLogger2 setup." << std::endl; + // TO-DO: setup everything! + + // Postcondition + assert(invariant()); +} + +/** + * The parent's teardown method handles the sensors and sensor infos. + */ +void tgDataLogger2::teardown() +{ + // Call the parent's teardown method! This is important! + tgDataManager::teardown(); + //DEBUGGING + std::cout << "tgDataLogger2 teardown." << std::endl; + // Postcondition + assert(invariant()); +} + +/** + * The step method is where data is actually collected! + * This data logger will do two things here: + * (1) iterate through all the sensors, collect their data, + * (2) write that line of data to the log file (then close the log again.) + */ +void tgDataLogger2::step(double dt) +{ + //DEBUGGING + //std::cout << "tgDataLogger2 step." << std::endl; + if (dt <= 0.0) + { + throw std::invalid_argument("dt is not positive"); + } + else + { + //DEBUGGING + //std::cout << "tgDataLogger2 step." << std::endl; + // TO-DO: collect the data. + } + + // Postcondition + assert(invariant()); +} + +/** + * The toString method for tgDataLogger2 should have some specific information + * about (for example) the log file... + */ +std::string tgDataLogger2::toString() const +{ + std::string p = " "; + std::ostringstream os; + // Note that we're using sprintf here to convert an int to a string. + // TO-DO: fix this! + os << "tgDataLogger2" << std::endl; + // << " with " << sprintf("%d",m_sensors.size()) << " sensors."<< std::endl; + + /* + os << prefix << p << "Children:" << std::endl; + for(std::size_t i = 0; i < m_children.size(); i++) { + os << m_children[i]->toString(prefix + p) << std::endl; + } + os << prefix << p << "Tags: [" << getTags() << "]" << std::endl; + os << prefix << ")"; + */ + return os.str(); +} + +std::ostream& +operator<<(std::ostream& os, const tgDataLogger2& obj) +{ + os << obj.toString() << std::endl; + return os; +} diff --git a/src/sensors/tgDataLogger2.h b/src/sensors/tgDataLogger2.h index e668de690..2c0807385 100644 --- a/src/sensors/tgDataLogger2.h +++ b/src/sensors/tgDataLogger2.h @@ -82,10 +82,28 @@ class tgDataLogger2 : public tgDataManager protected: /** - * Store the full name of the file for writing data, as well as + * Store the full name of the file for writing data. + * note that this is NOT what is passed into the constructor: + * that string is modified to create m_fileName. */ + std::string m_fileName; + + /** + * In order to have the filename for the log file be created in + * the setup function, instead of in the constructor, we need to hold + * the filename prefix too. This allows for running setup and teardown + * and having different log files - e.g., when the space bar is pressed, + * a new log file will be opened. + */ + std::string m_fileNamePrefix; + + /** + * Keep track of the total time that the simulation has run. + * This is for adding a timestamp into the log file. + */ + double m_totalTime; -} +}; #endif // TG_DATA_LOGGER2_H diff --git a/src/sensors/tgDataManager.cpp b/src/sensors/tgDataManager.cpp index c3e894caa..3ba8c7e4a 100644 --- a/src/sensors/tgDataManager.cpp +++ b/src/sensors/tgDataManager.cpp @@ -27,9 +27,11 @@ #include "tgDataManager.h" // This application #include "tgSensor.h" +#include "core/tgSenseable.h" //#include "tgSensorInfo.h" // The C++ Standard Library //#include // for sprintf +#include #include #include @@ -38,6 +40,8 @@ */ tgDataManager::tgDataManager() { + //DEBUGGING + std::cout << "tgDataManager constructor." << std::endl; // Postcondition assert(invariant()); } @@ -50,6 +54,9 @@ tgDataManager::tgDataManager() */ tgDataManager::~tgDataManager() { + //DEBUGGING + std::cout << "tgDataManager destructor." << std::endl; + // First, delete everything in m_sensors. const size_t n_Sens = m_sensors.size(); for (size_t i = 0; i < n_Sens; ++i) @@ -63,6 +70,10 @@ tgDataManager::~tgDataManager() } // Next, delete the sensor infos. // TO-DO: fill in. + + // Note that the creation and deletion of the senseable objects, e.g. + // the tgModels, is handled externally. + // tgDataManagers should NOT destroy the objects they are sensing. } /** @@ -71,6 +82,8 @@ tgDataManager::~tgDataManager() */ void tgDataManager::setup() { + //DEBUGGING + std::cout << "tgDataManager setup." << std::endl; // TO-DO: Should we create the sensors here in the setup method of the base? // What's the best way to maximize code re-use? // Postcondition @@ -79,13 +92,16 @@ void tgDataManager::setup() /** * The teardown method has to remove all the sensors and sensor infos. - * Note that this method will likely be re-defined by subclasses, - * in order to manage (for example) log files: close them out, for example. + * Note that this method could be redefined by subclasses, for example to + * do some final step with a mesage-passing algorithm before the simulation ends. * TO-DO: what's a good way to capture the deletion of sensors and sensorInfos * that doesn't require subclasses to copy-and-paste from this teardown method? */ void tgDataManager::teardown() { + //DEBUGGING + std::cout << "tgDataManager teardown." << std::endl; + // First, delete the sensors. // Note that it's good practice to set deleted pointers to NULL here. for (std::size_t i = 0; i < m_sensors.size(); i++) @@ -112,6 +128,8 @@ void tgDataManager::teardown() */ void tgDataManager::step(double dt) { + //DEBUGGING + std::cout << "tgDataManager step." << std::endl; if (dt <= 0.0) { throw std::invalid_argument("dt is not positive"); @@ -139,7 +157,7 @@ void tgDataManager::addSensorInfo(tgSensorInfo* pSensorInfo) throw std::invalid_argument("pSensorInfo is NULL inside tgDataManager::addSensorInfo"); } - m_sensorInfos.push_back(pChild); + m_sensorInfos.push_back(pSensorInfo); // Postcondition assert(invariant()); @@ -147,6 +165,28 @@ void tgDataManager::addSensorInfo(tgSensorInfo* pSensorInfo) } */ +/** + * This method adds sense-able objects to this data manager. + * It takes in a pointer to a sense-able object and pushes it to the + * current list of tgSenseables. + */ +/* +void tgDataManager::addSenseable(tgSensable* pSenseable) +{ + // Precondition + if (pSenseable == NULL) + { + throw std::invalid_argument("pSenseable is NULL inside tgDataManager::addSensable"); + } + + m_senseables.push_back(pSenseable); + + // Postcondition + assert(invariant()); + assert(!m_senseables.empty()); +} +*/ + /** * The toString method for data managers should include a list of the number * of sensors and sensor Infos it has. diff --git a/src/sensors/tgDataManager.h b/src/sensors/tgDataManager.h index 02f619d8b..ce074ceeb 100644 --- a/src/sensors/tgDataManager.h +++ b/src/sensors/tgDataManager.h @@ -30,7 +30,7 @@ //#include "tgCast.h" //#include "tgTaggable.h" //#include "tgTagSearch.h" -//#include "tgSenseable.h" +//#include "core/tgSenseable.h" // The C++ Standard Library #include #include @@ -40,6 +40,7 @@ // Forward declarations //class tgWorld; class tgSensor; +class tgSenseable; //class tgSensorInfo; /** @@ -84,6 +85,13 @@ class tgDataManager */ virtual void step(double dt); + /** + * Add a tgSenseable object to this data manager. + * These objects will be checked via the sensor infos, and sensors will + * be assigned to them if appropriate. + */ + //virtual void addSenseable(tgSenseable* pSenseable); + /** * Add a sensor info object to the current list of sensor infos. * @param[in] pSensorInfo a pointer to a tgSensorInfo. @@ -116,6 +124,12 @@ class tgDataManager */ //std::vector m_sensorInfos; + /** + * A data manager will also have a list of tgSenseable objects + * (really, just tgModels most of the time) that it will collect data from. + */ + //std::vector m_senseables; + }; /**