From 5ca06740900147e5e613f3e8a6e6e24987a8c7d1 Mon Sep 17 00:00:00 2001 From: akhopkar01 Date: Wed, 23 Sep 2020 12:53:40 -0400 Subject: [PATCH 01/39] feat: first draft; includes stub implementation; TODO: modify Unit Tests --- .vscode/c_cpp_properties.json | 53 ++++++++++++++++++++++++----------- .vscode/settings.json | 5 ++-- CMakeLists.txt | 2 +- app/CMakeLists.txt | 2 +- app/PID.cpp | 17 +++++++++++ app/main.cpp | 33 ++++++++++++++++++---- include/PID.h | 46 ++++++++++++++++++++++++++++++ include/lib.hpp | 8 ------ 8 files changed, 132 insertions(+), 34 deletions(-) create mode 100644 app/PID.cpp create mode 100644 include/PID.h delete mode 100644 include/lib.hpp diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 7f19e678..683a0ee0 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -8,26 +8,47 @@ "${workspaceRoot}/vendor/boost", "/usr/include" ], - "browse" : { - "limitSymbolsToIncludedHeaders" : true, - "databaseFilename" : "" - } + "browse": { + "limitSymbolsToIncludedHeaders": true, + "databaseFilename": "" + }, + "macFrameworkPath": [ + "/System/Library/Frameworks", + "/Library/Frameworks" + ], + "intelliSenseMode": "clang-x64", + "compilerPath": "/usr/bin/gcc", + "cStandard": "gnu11", + "cppStandard": "gnu++14" }, { "name": "Linux", - "includePath": ["/usr/include"], - "browse" : { - "limitSymbolsToIncludedHeaders" : true, - "databaseFilename" : "" - } + "includePath": [ + "/usr/include" + ], + "browse": { + "limitSymbolsToIncludedHeaders": true, + "databaseFilename": "" + }, + "intelliSenseMode": "gcc-x64", + "compilerPath": "/usr/bin/gcc", + "cStandard": "gnu11", + "cppStandard": "gnu++14" }, { "name": "Win32", - "includePath": ["c:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include"], - "browse" : { - "limitSymbolsToIncludedHeaders" : true, - "databaseFilename" : "" - } + "includePath": [ + "c:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include" + ], + "browse": { + "limitSymbolsToIncludedHeaders": true, + "databaseFilename": "" + }, + "intelliSenseMode": "msvc-x64", + "compilerPath": "/usr/bin/gcc", + "cStandard": "gnu11", + "cppStandard": "gnu++14" } - ] -} + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 95395d85..c3c3a246 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { // cpp general - "C_Cpp.clang_format_style": "visual studio", + "C_Cpp.clang_format_style": "Google", // cmake "cmake.generator.all": "ninja", @@ -22,5 +22,6 @@ "ms-vscode.cpptools", "RichardHe.you-complete-me", "vector-of-bool.cmake-tools" - ] + ], + "C_Cpp.clang_format_fallbackStyle": "Google" } diff --git a/CMakeLists.txt b/CMakeLists.txt index ccddcaf2..b4881983 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ if (COVERAGE) include(CodeCoverage) set(LCOV_REMOVE_EXTRA "'vendor/*'") setup_target_for_coverage(code_coverage test/cpp-test coverage) - set(COVERAGE_SRCS app/main.cpp include/lib.hpp) + set(COVERAGE_SRCS app/main.cpp app/PID.cpp include/PID.h) SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index c2d13dbe..aa7aceb0 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(shell-app main.cpp) +add_executable(shell-app main.cpp PID.cpp) include_directories( ${CMAKE_SOURCE_DIR}/include ) diff --git a/app/PID.cpp b/app/PID.cpp new file mode 100644 index 00000000..205a71d5 --- /dev/null +++ b/app/PID.cpp @@ -0,0 +1,17 @@ +/** + * Copyright 2020 + * */ + +/** + * @file: PID.cpp + * @brief: Contains the class definition of PID control + * @author: Part 1 : Aditya Khopkar (driver) + * */ + +#include "PID.h" + +double control::PID::compute(double feedback, double setpoint) { + // Stub Implementation + + return 0; +} \ No newline at end of file diff --git a/app/main.cpp b/app/main.cpp index 74232ade..f2d62749 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -1,8 +1,29 @@ +/** + * Copyright 2020 + * */ + +/** + * @file: main.cpp + * @brief: Contains the main function of the program + * @author: Part 1 : Aditya Khopkar (driver) + * */ + #include -#include +#include + +#include "PID.h" + +/** + * @brief: main function + * @param: None + * @return: 0 + * */ +int main() { + // create instance of PID + control::PID controller; -int main() -{ - dummy(); - return 0; -} + // get output + double new_velocity = controller.compute(1.2, 2.5); + std::cout << new_velocity << std::endl; + return 0; +} \ No newline at end of file diff --git a/include/PID.h b/include/PID.h new file mode 100644 index 00000000..454f52e7 --- /dev/null +++ b/include/PID.h @@ -0,0 +1,46 @@ +/** + * Copyright 2020 + * */ + +/** + * @file: PID.h + * @brief: Contains the class declaration of PID control + * @author: Part 1 : Aditya Khopkar (driver) + * */ + +#pragma once + +namespace control { +class PID { + private: + double kp_; + double ki_; + double kd_; + + public: + double setpoint_; + double dt_; + + /** + * @brief: Computes the new value of velocity given a setpoint and current + * value + * @param: feedback: double, setpoint: double + * @return: new velocity: double + * */ + double compute(double, double); + + /** + * @brief: Implementation of constructor + * @param: None + * @return: None + * */ + PID() : kp_{1.2}, ki_{0.4}, kd_{2.0}, dt_{0.1} {} + + /** + * @brief: Destructor call of class + * @param: None + * @return: None + * */ + virtual ~PID() {} +}; +} // namespace control \ No newline at end of file diff --git a/include/lib.hpp b/include/lib.hpp deleted file mode 100644 index 45fd193f..00000000 --- a/include/lib.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -void dummy() -{ - std::cout << "HI" << std::endl; -} From bb1d89c324aceac5f26307db8df4b3c4f462e53e Mon Sep 17 00:00:00 2001 From: akhopkar01 Date: Wed, 23 Sep 2020 14:51:49 -0400 Subject: [PATCH 02/39] fix: minor design changes --- app/main.cpp | 2 +- include/PID.h | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/main.cpp b/app/main.cpp index f2d62749..6e73b2a3 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -5,7 +5,7 @@ /** * @file: main.cpp * @brief: Contains the main function of the program - * @author: Part 1 : Aditya Khopkar (driver) + * @author: Part 1 - Aditya Khopkar (driver) * */ #include diff --git a/include/PID.h b/include/PID.h index 454f52e7..a32f3d9c 100644 --- a/include/PID.h +++ b/include/PID.h @@ -18,7 +18,10 @@ class PID { double kd_; public: - double setpoint_; + // keep track of previous error + double prev_error_; + + // delta time is set to a constant 0.1 double dt_; /** @@ -34,7 +37,7 @@ class PID { * @param: None * @return: None * */ - PID() : kp_{1.2}, ki_{0.4}, kd_{2.0}, dt_{0.1} {} + PID() : kp_{1.2}, ki_{0.4}, kd_{2.0}, dt_{0.1}, prev_error_{0} {} /** * @brief: Destructor call of class From bdc2f59b2da128baccc52cd6dc011152e2b7b23b Mon Sep 17 00:00:00 2001 From: akhopkar01 Date: Wed, 23 Sep 2020 14:52:24 -0400 Subject: [PATCH 03/39] feat: Unit test implementation; work in progress --- test/test.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index 2c5cd069..aae86790 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1,5 +1,10 @@ #include -TEST(dummy, should_pass) { - EXPECT_EQ(1, 1); +#include + +#include "PID.h" + +TEST(PIDControllerTest, should_pass) { + control::PID pid; + ASSERT_NEAR(6, pid.compute(4.0, 8.0), 0.2); } From 712d5c4d4b0c80815cb048ddada47920181c77fd Mon Sep 17 00:00:00 2001 From: akhopkar01 Date: Wed, 23 Sep 2020 16:22:08 -0400 Subject: [PATCH 04/39] feat: Added additional features to the class, refactored code --- app/PID.cpp | 15 ++++++++++++- app/main.cpp | 6 +++--- include/PID.h | 59 +++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/app/PID.cpp b/app/PID.cpp index 205a71d5..b5881714 100644 --- a/app/PID.cpp +++ b/app/PID.cpp @@ -10,8 +10,21 @@ #include "PID.h" +void control::PID::set_kp(double kp) { this->kp_ = kp; } + +void control::PID::set_kd(double kd) { this->kd_ = kd; } + +void control::PID::set_ki(double ki) { this->ki_ = ki; } + double control::PID::compute(double feedback, double setpoint) { // Stub Implementation + // Not iterative return 0; -} \ No newline at end of file +} + +const double control::PID::get_kp() { return this->kp_; } + +const double control::PID::get_kd() { return this->kd_; } + +const double control::PID::get_ki() { return this->ki_; } \ No newline at end of file diff --git a/app/main.cpp b/app/main.cpp index 6e73b2a3..6bd22159 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -1,11 +1,11 @@ /** - * Copyright 2020 + * Copyright 2020 * */ /** * @file: main.cpp * @brief: Contains the main function of the program - * @author: Part 1 - Aditya Khopkar (driver) + * @author: Part 1 - Aditya Khopkar (driver), Rajeshwar N S (navigator) * */ #include @@ -23,7 +23,7 @@ int main() { control::PID controller; // get output - double new_velocity = controller.compute(1.2, 2.5); + double new_velocity = controller.compute(4.0, 8.0); std::cout << new_velocity << std::endl; return 0; } \ No newline at end of file diff --git a/include/PID.h b/include/PID.h index a32f3d9c..891b0182 100644 --- a/include/PID.h +++ b/include/PID.h @@ -1,11 +1,11 @@ /** - * Copyright 2020 + * Copyright 2020 * */ /** * @file: PID.h * @brief: Contains the class declaration of PID control - * @author: Part 1 : Aditya Khopkar (driver) + * @author: Part 1 : Aditya Khopkar (driver), Rajeshwar N S (navigator) * */ #pragma once @@ -16,13 +16,31 @@ class PID { double kp_; double ki_; double kd_; + double prev_error_; + double integral_error_; + double dt_; public: - // keep track of previous error - double prev_error_; + /** + * @brief: Setter for kp + * @param: kp: double + * @return: None + * */ + void set_kp(double); - // delta time is set to a constant 0.1 - double dt_; + /** + * @brief: Setter for kd + * @param: kd: double + * @return: None + * */ + void set_kd(double); + + /** + * @brief: Setter for ki + * @param: ki: double + * @return: None + * */ + void set_ki(double); /** * @brief: Computes the new value of velocity given a setpoint and current @@ -32,12 +50,39 @@ class PID { * */ double compute(double, double); + /** + * @brief: Getter for kp + * @param: None + * @return: const double value + * */ + const double get_kp(); + + /** + * @brief: Getter for kd + * @param: None + * @return: const double value + * */ + const double get_kd(); + + /** + * @brief: Getter for ki + * @param: None + * @return: const double value + * */ + const double get_ki(); + /** * @brief: Implementation of constructor * @param: None * @return: None * */ - PID() : kp_{1.2}, ki_{0.4}, kd_{2.0}, dt_{0.1}, prev_error_{0} {} + PID() + : kp_{1.2}, + ki_{0.4}, + kd_{0.2}, + dt_{1.0}, + prev_error_{0}, + integral_error_{0} {} /** * @brief: Destructor call of class From d7680b34832fca41622e621b076c6eae4614ad5c Mon Sep 17 00:00:00 2001 From: akhopkar01 Date: Wed, 23 Sep 2020 16:22:39 -0400 Subject: [PATCH 05/39] feat: added Unit tests; work in progress --- test/main.cpp | 11 +++++++++++ test/test.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/test/main.cpp b/test/main.cpp index 697a9d70..f4714a7b 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -1,3 +1,14 @@ +/** + * Copyright 2020 + * */ + +/** + * @file: main.cpp (test) + * @brief: This file contains the main function to drive the tests for the + * software + * @author: Part 1 : Aditya Khopkar (driver), Rajeshwar N S (navigator) + * */ + #include int main(int argc, char** argv) { diff --git a/test/test.cpp b/test/test.cpp index aae86790..d6ebdf70 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1,10 +1,53 @@ +/** + * Copyright 2020 + * */ + +/** + * @file: test.cpp + * @brief: This file contains the test functions to Unit test the software + * @author: Part 1 : Aditya Khopkar (driver), Rajeshwar N S (navigator) + * */ + #include #include #include "PID.h" -TEST(PIDControllerTest, should_pass) { - control::PID pid; - ASSERT_NEAR(6, pid.compute(4.0, 8.0), 0.2); +// instance of the class +control::PID pid; + +// temp value +double val = 1.4; + +/** + * @brief: Tests the compute method of the class by returning a double value, + * should pass + * Actual vel = 4.0, Desired vel = 8.0, kp, ki, kd, dt = [1.2, 0.4, + * 0.2, 1] + * */ +TEST(PIDComputeTest, should_pass) { ASSERT_EQ(7.2, pid.compute(4.0, 8.0)); } + +/** + * @brief: tests setter for kp + * */ +TEST(PIDSetters, check_kp) { + pid.set_kp(val); + ASSERT_EQ(val, pid.get_kp()); +} + +/** + * @brief: tests setter for kd + * */ +TEST(PIDSetters, check_kd) { + pid.set_kd(val); + ASSERT_EQ(val, pid.get_kd()); } + +/** + * @brief: tests setter for ki + * */ +TEST(PIDSetters, check_ki) { + pid.set_ki(val); + ASSERT_EQ(val, pid.get_ki()); +} \ No newline at end of file From 9d2597b19324ccae1f5ea4283c226b6d2a66d179 Mon Sep 17 00:00:00 2001 From: akhopkar01 Date: Wed, 23 Sep 2020 16:41:38 -0400 Subject: [PATCH 06/39] feat: included UML diagram --- UML_TDD.pdf | Bin 0 -> 50773 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 UML_TDD.pdf diff --git a/UML_TDD.pdf b/UML_TDD.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1d57b7fabc52e0db240636a737024e70f52a4b00 GIT binary patch literal 50773 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 literal 0 HcmV?d00001 From b82f44739eaed40e0177c2b3ff9b6b971d66ff6c Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Wed, 23 Sep 2020 16:47:17 -0400 Subject: [PATCH 07/39] Update readme.md --- readme.md | 106 +++--------------------------------------------------- 1 file changed, 5 insertions(+), 101 deletions(-) diff --git a/readme.md b/readme.md index aadd5b41..6fdac4a7 100644 --- a/readme.md +++ b/readme.md @@ -1,19 +1,17 @@ -# C++ Boilerplate +# PID Controller (Test Driven Development) [![Build Status](https://travis-ci.org/dpiet/cpp-boilerplate.svg?branch=master)](https://travis-ci.org/dpiet/cpp-boilerplate) [![Coverage Status](https://coveralls.io/repos/github/dpiet/cpp-boilerplate/badge.svg?branch=master)](https://coveralls.io/github/dpiet/cpp-boilerplate?branch=master) --- ## Overview -Simple starter C++ project with: - -- cmake -- googletest +This project is worked in groups to carry out TDD. +Author: [Part 1] Aditya Khopkar (driver), Rajeshwar N S (navigator) ## Standard install via command-line ``` -git clone --recursive https://github.com/dpiet/cpp-boilerplate -cd +git clone --recursive https://github.com/akhopkar01/PID_controller +cd PID_controller mkdir build cd build cmake .. @@ -30,97 +28,3 @@ make make code_coverage ``` This generates a index.html page in the build/coverage sub-directory that can be viewed locally in a web browser. - -## Working with Eclipse IDE ## - -## Installation - -In your Eclipse workspace directory (or create a new one), checkout the repo (and submodules) -``` -mkdir -p ~/workspace -cd ~/workspace -git clone --recursive https://github.com/dpiet/cpp-boilerplate -``` - -In your work directory, use cmake to create an Eclipse project for an [out-of-source build] of cpp-boilerplate - -``` -cd ~/workspace -mkdir -p boilerplate-eclipse -cd boilerplate-eclipse -cmake -G "Eclipse CDT4 - Unix Makefiles" -D CMAKE_BUILD_TYPE=Debug -D CMAKE_ECLIPSE_VERSION=4.7.0 -D CMAKE_CXX_COMPILER_ARG1=-std=c++14 ../cpp-boilerplate/ -``` - -## Import - -Open Eclipse, go to File -> Import -> General -> Existing Projects into Workspace -> -Select "boilerplate-eclipse" directory created previously as root directory -> Finish - -# Edit - -Source files may be edited under the "[Source Directory]" label in the Project Explorer. - - -## Build - -To build the project, in Eclipse, unfold boilerplate-eclipse project in Project Explorer, -unfold Build Targets, double click on "all" to build all projects. - -## Run - -1. In Eclipse, right click on the boilerplate-eclipse in Project Explorer, -select Run As -> Local C/C++ Application - -2. Choose the binaries to run (e.g. shell-app, cpp-test for unit testing) - - -## Debug - - -1. Set breakpoint in source file (i.e. double click in the left margin on the line you want -the program to break). - -2. In Eclipse, right click on the boilerplate-eclipse in Project Explorer, select Debug As -> -Local C/C++ Application, choose the binaries to run (e.g. shell-app). - -3. If prompt to "Confirm Perspective Switch", select yes. - -4. Program will break at the breakpoint you set. - -5. Press Step Into (F5), Step Over (F6), Step Return (F7) to step/debug your program. - -6. Right click on the variable in editor to add watch expression to watch the variable in -debugger window. - -7. Press Terminate icon to terminate debugging and press C/C++ icon to switch back to C/C++ -perspetive view (or Windows->Perspective->Open Perspective->C/C++). - - -## Plugins - -- CppChEclipse - - To install and run cppcheck in Eclipse - - 1. In Eclipse, go to Window -> Preferences -> C/C++ -> cppcheclipse. - Set cppcheck binary path to "/usr/bin/cppcheck". - - 2. To run CPPCheck on a project, right click on the project name in the Project Explorer - and choose cppcheck -> Run cppcheck. - - -- Google C++ Sytle - - To include and use Google C++ Style formatter in Eclipse - - 1. In Eclipse, go to Window -> Preferences -> C/C++ -> Code Style -> Formatter. - Import [eclipse-cpp-google-style][reference-id-for-eclipse-cpp-google-style] and apply. - - 2. To use Google C++ style formatter, right click on the source code or folder in - Project Explorer and choose Source -> Format - -[reference-id-for-eclipse-cpp-google-style]: https://raw.githubusercontent.com/google/styleguide/gh-pages/eclipse-cpp-google-style.xml - -- Git - - It is possible to manage version control through Eclipse and the git plugin, but it typically requires creating another project. If you're interested in this, try it out yourself and contact me on Canvas. From 0c231da486f05358fdfb0d2ca090e493b3e10352 Mon Sep 17 00:00:00 2001 From: akhopkar01 Date: Thu, 24 Sep 2020 01:34:37 -0400 Subject: [PATCH 08/39] fix: Fixed error in test build --- test/CMakeLists.txt | 4 +++- test/test.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2b1cd4cb..6e2ba778 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -4,8 +4,10 @@ add_executable( cpp-test main.cpp test.cpp + ../app/PID.cpp ) target_include_directories(cpp-test PUBLIC ../vendor/googletest/googletest/include - ${CMAKE_SOURCE_DIR}/include) + ${CMAKE_SOURCE_DIR}/include + ) target_link_libraries(cpp-test PUBLIC gtest) diff --git a/test/test.cpp b/test/test.cpp index d6ebdf70..beec7960 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -50,4 +50,4 @@ TEST(PIDSetters, check_kd) { TEST(PIDSetters, check_ki) { pid.set_ki(val); ASSERT_EQ(val, pid.get_ki()); -} \ No newline at end of file +} From 0bf35ceca01992d93ddc2d3e50ec446fcebc2926 Mon Sep 17 00:00:00 2001 From: akhopkar01 Date: Thu, 24 Sep 2020 01:35:22 -0400 Subject: [PATCH 09/39] refactor: Minor design changes --- app/PID.cpp | 10 +++++----- app/main.cpp | 2 +- include/PID.h | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/PID.cpp b/app/PID.cpp index b5881714..0c5ed5b6 100644 --- a/app/PID.cpp +++ b/app/PID.cpp @@ -1,11 +1,11 @@ /** - * Copyright 2020 + * Copyright 2020 * */ /** * @file: PID.cpp * @brief: Contains the class definition of PID control - * @author: Part 1 : Aditya Khopkar (driver) + * @author: Part 1 : Aditya Khopkar (driver), Rajeshwar N S (navigator) * */ #include "PID.h" @@ -23,8 +23,8 @@ double control::PID::compute(double feedback, double setpoint) { return 0; } -const double control::PID::get_kp() { return this->kp_; } +const double& control::PID::get_kp() { return this->kp_; } -const double control::PID::get_kd() { return this->kd_; } +const double& control::PID::get_kd() { return this->kd_; } -const double control::PID::get_ki() { return this->ki_; } \ No newline at end of file +const double& control::PID::get_ki() { return this->ki_; } diff --git a/app/main.cpp b/app/main.cpp index 6bd22159..5e7c4f4e 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -26,4 +26,4 @@ int main() { double new_velocity = controller.compute(4.0, 8.0); std::cout << new_velocity << std::endl; return 0; -} \ No newline at end of file +} diff --git a/include/PID.h b/include/PID.h index 891b0182..ff70a3db 100644 --- a/include/PID.h +++ b/include/PID.h @@ -16,9 +16,9 @@ class PID { double kp_; double ki_; double kd_; + double dt_; double prev_error_; double integral_error_; - double dt_; public: /** @@ -55,21 +55,21 @@ class PID { * @param: None * @return: const double value * */ - const double get_kp(); + const double& get_kp(); /** * @brief: Getter for kd * @param: None * @return: const double value * */ - const double get_kd(); + const double& get_kd(); /** * @brief: Getter for ki * @param: None * @return: const double value * */ - const double get_ki(); + const double& get_ki(); /** * @brief: Implementation of constructor @@ -91,4 +91,4 @@ class PID { * */ virtual ~PID() {} }; -} // namespace control \ No newline at end of file +} // namespace control From 0e5d5d27a530658f624c0db3c2871dd585120dbb Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Thu, 24 Sep 2020 01:37:21 -0400 Subject: [PATCH 10/39] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 6fdac4a7..4b3e3f12 100644 --- a/readme.md +++ b/readme.md @@ -6,7 +6,7 @@ ## Overview This project is worked in groups to carry out TDD. -Author: [Part 1] Aditya Khopkar (driver), Rajeshwar N S (navigator) +Author: Part 1 - Aditya Khopkar (driver), Rajeshwar N S (navigator) ## Standard install via command-line ``` From b0948da345d93ed5071d71e8c10d1902832ba48a Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Thu, 24 Sep 2020 01:37:48 -0400 Subject: [PATCH 11/39] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 4b3e3f12..ac551ade 100644 --- a/readme.md +++ b/readme.md @@ -5,7 +5,7 @@ ## Overview -This project is worked in groups to carry out TDD. +This project is worked in groups to carry out TDD. \\ Author: Part 1 - Aditya Khopkar (driver), Rajeshwar N S (navigator) ## Standard install via command-line From d0be33a4d8403a8871e3bc50c50fede1049a41bf Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Thu, 24 Sep 2020 16:47:12 -0400 Subject: [PATCH 12/39] Update readme.md --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index ac551ade..26260d65 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ # PID Controller (Test Driven Development) -[![Build Status](https://travis-ci.org/dpiet/cpp-boilerplate.svg?branch=master)](https://travis-ci.org/dpiet/cpp-boilerplate) -[![Coverage Status](https://coveralls.io/repos/github/dpiet/cpp-boilerplate/badge.svg?branch=master)](https://coveralls.io/github/dpiet/cpp-boilerplate?branch=master) +[![Build Status](https://travis-ci.org/akhopkar01/PID_controller.svg?branch=master)](https://travis-ci.org/akhopkar01/PID_controller) +[![Coverage Status](https://coveralls.io/repos/github/akhopkar01/PID_controller/badge.svg?branch=master)](https://coveralls.io/github/akhopkar01/PID_controller?branch=master) --- ## Overview From cb587fd79e4a0ea9bb240a7a5306db078637bb2d Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Thu, 24 Sep 2020 16:47:49 -0400 Subject: [PATCH 13/39] Update readme.md --- readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 26260d65..dfe50150 100644 --- a/readme.md +++ b/readme.md @@ -5,7 +5,8 @@ ## Overview -This project is worked in groups to carry out TDD. \\ +This project is worked in groups to carry out TDD. + Author: Part 1 - Aditya Khopkar (driver), Rajeshwar N S (navigator) ## Standard install via command-line From 5dbf17cdc6f8495a9cfe7cf9063cc69989d2b826 Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Thu, 24 Sep 2020 16:48:20 -0400 Subject: [PATCH 14/39] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index dfe50150..569d50ab 100644 --- a/readme.md +++ b/readme.md @@ -7,7 +7,7 @@ This project is worked in groups to carry out TDD. -Author: Part 1 - Aditya Khopkar (driver), Rajeshwar N S (navigator) +Author: [ Part 1 ] Aditya Khopkar (driver), Rajeshwar N S (navigator) ## Standard install via command-line ``` From 78cd8a3286b4ff81d5d75d61ef6a68eb78092340 Mon Sep 17 00:00:00 2001 From: selyard <70611145+selyard@users.noreply.github.com> Date: Thu, 24 Sep 2020 20:37:43 -0400 Subject: [PATCH 15/39] Update readme.md Updated with authors for Part 2 of project. --- readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 569d50ab..550f0183 100644 --- a/readme.md +++ b/readme.md @@ -7,7 +7,9 @@ This project is worked in groups to carry out TDD. -Author: [ Part 1 ] Aditya Khopkar (driver), Rajeshwar N S (navigator) +Author: +[ Part 1 ] Aditya Khopkar (driver), Rajeshwar N S (navigator) +[ Part 2 ] Spencer Elyard (driver), Daniel Sahu (navigator) ## Standard install via command-line ``` From b20fe2e8c1ffc029fd360b9392ed9beeab6d7465 Mon Sep 17 00:00:00 2001 From: selyard Date: Thu, 24 Sep 2020 20:53:46 -0400 Subject: [PATCH 16/39] Add PID controller function; modify constructor/destructor for PID class. --- app/PID.cpp | 31 +++++++++++++++++++++++++++---- include/PID.h | 12 +++--------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/app/PID.cpp b/app/PID.cpp index 0c5ed5b6..441cc7c0 100644 --- a/app/PID.cpp +++ b/app/PID.cpp @@ -10,6 +10,16 @@ #include "PID.h" +// constructor +control::PID::PID() { + kp_ = 1.2; + ki_ = 0.4; + kd_ = 0.2; + dt_ = 1; + prev_error_ = 0.0; + integral_error_ = 0.0; +} + void control::PID::set_kp(double kp) { this->kp_ = kp; } void control::PID::set_kd(double kd) { this->kd_ = kd; } @@ -17,10 +27,19 @@ void control::PID::set_kd(double kd) { this->kd_ = kd; } void control::PID::set_ki(double ki) { this->ki_ = ki; } double control::PID::compute(double feedback, double setpoint) { - // Stub Implementation - // Not iterative - - return 0; + // calculate current error + double currentError = setpoint - feedback; + // Proportional controller portion + double proportional = kp_ * currentError; + // Integral controller portion + double integral = ki_ * (integral_error_ + currentError*dt_); + // Derivative + double derivative = kd_ * ((currentError - prev_error_) / dt_); + // calculate output + double output = proportional + integral + derivative; + // save error as previous prev_error_ + prev_error_ = currentError; + return output; } const double& control::PID::get_kp() { return this->kp_; } @@ -28,3 +47,7 @@ const double& control::PID::get_kp() { return this->kp_; } const double& control::PID::get_kd() { return this->kd_; } const double& control::PID::get_ki() { return this->ki_; } + +// destructor +control::PID::~PID() { +} diff --git a/include/PID.h b/include/PID.h index ff70a3db..7cff8cbd 100644 --- a/include/PID.h +++ b/include/PID.h @@ -76,19 +76,13 @@ class PID { * @param: None * @return: None * */ - PID() - : kp_{1.2}, - ki_{0.4}, - kd_{0.2}, - dt_{1.0}, - prev_error_{0}, - integral_error_{0} {} + PID(); /** * @brief: Destructor call of class * @param: None * @return: None * */ - virtual ~PID() {} + virtual ~PID(); }; -} // namespace control +}; // namespace control From f865154dde590815598c29c670b55040e40077e4 Mon Sep 17 00:00:00 2001 From: selyard <70611145+selyard@users.noreply.github.com> Date: Thu, 24 Sep 2020 20:55:32 -0400 Subject: [PATCH 17/39] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 550f0183..f4255601 100644 --- a/readme.md +++ b/readme.md @@ -13,7 +13,7 @@ Author: ## Standard install via command-line ``` -git clone --recursive https://github.com/akhopkar01/PID_controller +git clone --recursive https://github.com/selyard/PID_controller cd PID_controller mkdir build cd build From 3e16d099c7a5f5f993af77f32e879ac3c045ecca Mon Sep 17 00:00:00 2001 From: selyard <70611145+selyard@users.noreply.github.com> Date: Thu, 24 Sep 2020 21:08:05 -0400 Subject: [PATCH 18/39] Update readme.md Updated Travis CI, Coveralls badges. --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index f4255601..1b75069a 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ # PID Controller (Test Driven Development) -[![Build Status](https://travis-ci.org/akhopkar01/PID_controller.svg?branch=master)](https://travis-ci.org/akhopkar01/PID_controller) -[![Coverage Status](https://coveralls.io/repos/github/akhopkar01/PID_controller/badge.svg?branch=master)](https://coveralls.io/github/akhopkar01/PID_controller?branch=master) +[![Build Status](https://travis-ci.com/selyard/PID_controller.svg?branch=master)](https://travis-ci.com/github/selyard/PID_controller) +[![Coverage Status](https://coveralls.io/repos/github/selyard/PID_controller/badge.svg?branch=master)](https://coveralls.io/github/selyard/PID_controller?branch=master) --- ## Overview From aad60652ae9b7743f96cfa60525660e11687bd50 Mon Sep 17 00:00:00 2001 From: selyard Date: Thu, 24 Sep 2020 21:09:32 -0400 Subject: [PATCH 19/39] Adding Coveralls config file. --- .coveralls.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .coveralls.yml diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 00000000..8194317d --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1 @@ +repo_token: aaQLZMqNHM2PYdcQYO2kW2tIG7waVUoLj From 7d6202c57855548e602f8a138c9fce18979e6cf6 Mon Sep 17 00:00:00 2001 From: selyard <70611145+selyard@users.noreply.github.com> Date: Fri, 25 Sep 2020 19:56:08 -0400 Subject: [PATCH 20/39] Update .travis.yml Add Coveralls support for Travis CI --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 56dece5b..4ca29540 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ script: - test/cpp-test after_success: - - coveralls --root .. -E ".*external.*" -E ".*CMakeFiles.*" -E ".*test/.*.cpp.*" + - coveralls --root .. -E ".*external.*" -E ".*CMakeFiles.*" -E ".*test/.*.cpp.*" -t 8XWBtaqK7X1obrBYliWhEdyiz35hmdl8E notifications: email: false From 1c81cecf838744e28797e48db2df31e96d1d1d23 Mon Sep 17 00:00:00 2001 From: selyard Date: Sat, 26 Sep 2020 13:32:38 -0400 Subject: [PATCH 21/39] Update author fields, add ToDo to readme. --- app/PID.cpp | 1 + app/main.cpp | 1 + include/PID.h | 1 + readme.md | 3 +++ 4 files changed, 6 insertions(+) diff --git a/app/PID.cpp b/app/PID.cpp index 441cc7c0..4814928f 100644 --- a/app/PID.cpp +++ b/app/PID.cpp @@ -6,6 +6,7 @@ * @file: PID.cpp * @brief: Contains the class definition of PID control * @author: Part 1 : Aditya Khopkar (driver), Rajeshwar N S (navigator) + * @author: Part 2 - Spencer Elyard (driver), Daniel Sahu (navigator) * */ #include "PID.h" diff --git a/app/main.cpp b/app/main.cpp index 5e7c4f4e..9ab4fa5f 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -6,6 +6,7 @@ * @file: main.cpp * @brief: Contains the main function of the program * @author: Part 1 - Aditya Khopkar (driver), Rajeshwar N S (navigator) + * @author: Part 2 - Spencer Elyard (driver), Daniel Sahu (navigator) * */ #include diff --git a/include/PID.h b/include/PID.h index 7cff8cbd..4d7f9b31 100644 --- a/include/PID.h +++ b/include/PID.h @@ -6,6 +6,7 @@ * @file: PID.h * @brief: Contains the class declaration of PID control * @author: Part 1 : Aditya Khopkar (driver), Rajeshwar N S (navigator) + * @author: Part 2 - Spencer Elyard (driver), Daniel Sahu (navigator) * */ #pragma once diff --git a/readme.md b/readme.md index 1b75069a..b53b301b 100644 --- a/readme.md +++ b/readme.md @@ -31,3 +31,6 @@ make make code_coverage ``` This generates a index.html page in the build/coverage sub-directory that can be viewed locally in a web browser. + +## TO DO for future: +- Investigate additional test cases for PID controller From 443d0a558a77efe42965e40803447b3e2fad3b04 Mon Sep 17 00:00:00 2001 From: selyard Date: Sat, 26 Sep 2020 13:33:09 -0400 Subject: [PATCH 22/39] Update Travis, Coveralls tokens. --- .coveralls.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.coveralls.yml b/.coveralls.yml index 8194317d..98312c17 100644 --- a/.coveralls.yml +++ b/.coveralls.yml @@ -1 +1 @@ -repo_token: aaQLZMqNHM2PYdcQYO2kW2tIG7waVUoLj +repo_token: 8XWBtaqK7X1obrBYliWhEdyiz35hmdl8E From d611eade875a55e8075ef0d6ce0719de607d1fcc Mon Sep 17 00:00:00 2001 From: akhopkar01 Date: Mon, 28 Sep 2020 18:54:13 -0400 Subject: [PATCH 23/39] Naming convention-handled; minor changes --- app/PID.cpp | 39 +++++++++++++++++++-------------------- app/main.cpp | 6 +++--- include/PID.h | 16 ++++++++-------- results/cppcheck | 8 ++++++++ results/cpplint | 4 ++++ test/test.cpp | 16 +++++++++------- 6 files changed, 51 insertions(+), 38 deletions(-) create mode 100644 results/cppcheck create mode 100644 results/cpplint diff --git a/app/PID.cpp b/app/PID.cpp index 4814928f..f8bff8bf 100644 --- a/app/PID.cpp +++ b/app/PID.cpp @@ -13,42 +13,41 @@ // constructor control::PID::PID() { - kp_ = 1.2; - ki_ = 0.4; - kd_ = 0.2; - dt_ = 1; - prev_error_ = 0.0; - integral_error_ = 0.0; + kp_ = 1.2; + ki_ = 0.4; + kd_ = 0.2; + dt_ = 1; + prev_error_ = 0.0; + integral_error_ = 0.0; } -void control::PID::set_kp(double kp) { this->kp_ = kp; } +void control::PID::SetKp(double kp) { this->kp_ = kp; } -void control::PID::set_kd(double kd) { this->kd_ = kd; } +void control::PID::SetKd(double kd) { this->kd_ = kd; } -void control::PID::set_ki(double ki) { this->ki_ = ki; } +void control::PID::SetKi(double ki) { this->ki_ = ki; } -double control::PID::compute(double feedback, double setpoint) { +double control::PID::Compute(double feedback, double setpoint) { // calculate current error - double currentError = setpoint - feedback; + double current_error = setpoint - feedback; // Proportional controller portion - double proportional = kp_ * currentError; + double proportional = kp_ * current_error; // Integral controller portion - double integral = ki_ * (integral_error_ + currentError*dt_); + double integral = ki_ * (integral_error_ + current_error * dt_); // Derivative - double derivative = kd_ * ((currentError - prev_error_) / dt_); + double derivative = kd_ * ((current_error - prev_error_) / dt_); // calculate output double output = proportional + integral + derivative; // save error as previous prev_error_ - prev_error_ = currentError; + prev_error_ = current_error; return output; } -const double& control::PID::get_kp() { return this->kp_; } +const double& control::PID::GetKp() { return this->kp_; } -const double& control::PID::get_kd() { return this->kd_; } +const double& control::PID::GetKd() { return this->kd_; } -const double& control::PID::get_ki() { return this->ki_; } +const double& control::PID::GetKi() { return this->ki_; } // destructor -control::PID::~PID() { -} +control::PID::~PID() {} diff --git a/app/main.cpp b/app/main.cpp index 9ab4fa5f..d0d805b6 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -22,9 +22,9 @@ int main() { // create instance of PID control::PID controller; - // get output - double new_velocity = controller.compute(4.0, 8.0); - std::cout << new_velocity << std::endl; + double new_velocity = controller.Compute(4.0, 8.0); + std::cout << "Actual Velocity: " << 4.0 << " Desired Velocity: " << 8.0 + << " New Velocity: " << new_velocity << std::endl; return 0; } diff --git a/include/PID.h b/include/PID.h index 4d7f9b31..610629bc 100644 --- a/include/PID.h +++ b/include/PID.h @@ -27,21 +27,21 @@ class PID { * @param: kp: double * @return: None * */ - void set_kp(double); + void SetKp(double); /** * @brief: Setter for kd * @param: kd: double * @return: None * */ - void set_kd(double); + void SetKd(double); /** * @brief: Setter for ki * @param: ki: double * @return: None * */ - void set_ki(double); + void SetKi(double); /** * @brief: Computes the new value of velocity given a setpoint and current @@ -49,28 +49,28 @@ class PID { * @param: feedback: double, setpoint: double * @return: new velocity: double * */ - double compute(double, double); + double Compute(double, double); /** * @brief: Getter for kp * @param: None * @return: const double value * */ - const double& get_kp(); + const double& GetKp(); /** * @brief: Getter for kd * @param: None * @return: const double value * */ - const double& get_kd(); + const double& GetKd(); /** * @brief: Getter for ki * @param: None * @return: const double value * */ - const double& get_ki(); + const double& GetKi(); /** * @brief: Implementation of constructor @@ -86,4 +86,4 @@ class PID { * */ virtual ~PID(); }; -}; // namespace control +} // namespace control diff --git a/results/cppcheck b/results/cppcheck new file mode 100644 index 00000000..a645d2dd --- /dev/null +++ b/results/cppcheck @@ -0,0 +1,8 @@ +Checking app/PID.cpp ... +1/4 files checked 41% done +Checking app/main.cpp ... +2/4 files checked 59% done +Checking test/main.cpp ... +3/4 files checked 70% done +Checking test/test.cpp ... +4/4 files checked 100% done diff --git a/results/cpplint b/results/cpplint new file mode 100644 index 00000000..a563a608 --- /dev/null +++ b/results/cpplint @@ -0,0 +1,4 @@ +Done processing ./app/PID.cpp +Done processing ./app/main.cpp +Done processing ./test/main.cpp +Done processing ./test/test.cpp diff --git a/test/test.cpp b/test/test.cpp index beec7960..f077957c 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -26,28 +26,30 @@ double val = 1.4; * Actual vel = 4.0, Desired vel = 8.0, kp, ki, kd, dt = [1.2, 0.4, * 0.2, 1] * */ -TEST(PIDComputeTest, should_pass) { ASSERT_EQ(7.2, pid.compute(4.0, 8.0)); } +TEST(PIDComputeTest, should_pass) { + EXPECT_DOUBLE_EQ(7.2, pid.Compute(4.0, 8.0)); +} /** * @brief: tests setter for kp * */ TEST(PIDSetters, check_kp) { - pid.set_kp(val); - ASSERT_EQ(val, pid.get_kp()); + pid.SetKp(val); + EXPECT_DOUBLE_EQ(val, pid.GetKp()); } /** * @brief: tests setter for kd * */ TEST(PIDSetters, check_kd) { - pid.set_kd(val); - ASSERT_EQ(val, pid.get_kd()); + pid.SetKd(val); + EXPECT_DOUBLE_EQ(val, pid.GetKd()); } /** * @brief: tests setter for ki * */ TEST(PIDSetters, check_ki) { - pid.set_ki(val); - ASSERT_EQ(val, pid.get_ki()); + pid.SetKi(val); + EXPECT_DOUBLE_EQ(val, pid.GetKi()); } From c8b7a1b3291d90f3acd64c0a6c6a02664ab89065 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 28 Sep 2020 22:16:57 -0400 Subject: [PATCH 24/39] coveralls-test --- app/PID.cpp | 27 ++++++++++++++++++++------- app/main.cpp | 2 -- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/app/PID.cpp b/app/PID.cpp index f8bff8bf..dc8feb79 100644 --- a/app/PID.cpp +++ b/app/PID.cpp @@ -21,11 +21,17 @@ control::PID::PID() { integral_error_ = 0.0; } -void control::PID::SetKp(double kp) { this->kp_ = kp; } +void control::PID::SetKp(double kp) { + this->kp_ = kp; +} -void control::PID::SetKd(double kd) { this->kd_ = kd; } +void control::PID::SetKd(double kd) { + this->kd_ = kd; +} -void control::PID::SetKi(double ki) { this->ki_ = ki; } +void control::PID::SetKi(double ki) { + this->ki_ = ki; +} double control::PID::Compute(double feedback, double setpoint) { // calculate current error @@ -43,11 +49,18 @@ double control::PID::Compute(double feedback, double setpoint) { return output; } -const double& control::PID::GetKp() { return this->kp_; } +const double& control::PID::GetKp() { + return this->kp_; +} -const double& control::PID::GetKd() { return this->kd_; } +const double& control::PID::GetKd() { + return this->kd_; +} -const double& control::PID::GetKi() { return this->ki_; } +const double& control::PID::GetKi() { + return this->ki_; +} // destructor -control::PID::~PID() {} +control::PID::~PID() { +} diff --git a/app/main.cpp b/app/main.cpp index d0d805b6..455920d0 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -20,9 +20,7 @@ * @return: 0 * */ int main() { - // create instance of PID control::PID controller; - // get output double new_velocity = controller.Compute(4.0, 8.0); std::cout << "Actual Velocity: " << 4.0 << " Desired Velocity: " << 8.0 << " New Velocity: " << new_velocity << std::endl; From 14b722707305663f4d3c47d2d098b63b648869be Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 28 Sep 2020 22:22:11 -0400 Subject: [PATCH 25/39] updated travis-coverall links --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index b53b301b..d5a25aea 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ # PID Controller (Test Driven Development) -[![Build Status](https://travis-ci.com/selyard/PID_controller.svg?branch=master)](https://travis-ci.com/github/selyard/PID_controller) -[![Coverage Status](https://coveralls.io/repos/github/selyard/PID_controller/badge.svg?branch=master)](https://coveralls.io/github/selyard/PID_controller?branch=master) +[![Build Status](https://travis-ci.com/akhopkar01/PID_controller.svg?branch=master)](https://travis-ci.com/github/akhopkar01/PID_controller) +[![Coverage Status](https://coveralls.io/repos/github/akhopkar01/PID_controller/badge.svg?branch=master)](https://coveralls.io/github/akhopkar01/PID_controller?branch=master) --- ## Overview From 803727eb6deec5290e5ea87e2db2ee2a3bc59a43 Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Mon, 28 Sep 2020 23:16:06 -0400 Subject: [PATCH 26/39] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index d5a25aea..605b5981 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,5 @@ # PID Controller (Test Driven Development) -[![Build Status](https://travis-ci.com/akhopkar01/PID_controller.svg?branch=master)](https://travis-ci.com/github/akhopkar01/PID_controller) +[![Build Status](https://travis-ci.org/akhopkar01/PID_controller.svg?branch=master)](https://travis-ci.com/github/akhopkar01/PID_controller) [![Coverage Status](https://coveralls.io/repos/github/akhopkar01/PID_controller/badge.svg?branch=master)](https://coveralls.io/github/akhopkar01/PID_controller?branch=master) --- From a13f84b494bd12ea0069fbcc4ce84ff6dad3f8e4 Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Mon, 28 Sep 2020 23:17:02 -0400 Subject: [PATCH 27/39] Update .travis.yml --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4ca29540..1806e5aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,6 @@ script: - test/cpp-test after_success: - - coveralls --root .. -E ".*external.*" -E ".*CMakeFiles.*" -E ".*test/.*.cpp.*" -t 8XWBtaqK7X1obrBYliWhEdyiz35hmdl8E - + - coveralls --root .. -E ".*external.*" -E ".*CMakeFiles.*" -E ".*test/.*.cpp.*" -t WpS2LBk3t7xe2Vt8usbpbp03mDsNUHLud notifications: email: false From f111d3ebc1ec308ee25b91f4d3b899b65926999e Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Mon, 28 Sep 2020 23:17:16 -0400 Subject: [PATCH 28/39] Update .coveralls.yml --- .coveralls.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.coveralls.yml b/.coveralls.yml index 98312c17..57bbaa1a 100644 --- a/.coveralls.yml +++ b/.coveralls.yml @@ -1 +1 @@ -repo_token: 8XWBtaqK7X1obrBYliWhEdyiz35hmdl8E +repo_token: WpS2LBk3t7xe2Vt8usbpbp03mDsNUHLud From eba3bb3fc2b33de48fbc34908449ef07853410db Mon Sep 17 00:00:00 2001 From: akhopkar01 Date: Mon, 28 Sep 2020 23:42:04 -0400 Subject: [PATCH 29/39] Code Coverage test --- app/PID.cpp | 27 +++++++-------------------- app/main.cpp | 3 ++- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/app/PID.cpp b/app/PID.cpp index dc8feb79..f8bff8bf 100644 --- a/app/PID.cpp +++ b/app/PID.cpp @@ -21,17 +21,11 @@ control::PID::PID() { integral_error_ = 0.0; } -void control::PID::SetKp(double kp) { - this->kp_ = kp; -} +void control::PID::SetKp(double kp) { this->kp_ = kp; } -void control::PID::SetKd(double kd) { - this->kd_ = kd; -} +void control::PID::SetKd(double kd) { this->kd_ = kd; } -void control::PID::SetKi(double ki) { - this->ki_ = ki; -} +void control::PID::SetKi(double ki) { this->ki_ = ki; } double control::PID::Compute(double feedback, double setpoint) { // calculate current error @@ -49,18 +43,11 @@ double control::PID::Compute(double feedback, double setpoint) { return output; } -const double& control::PID::GetKp() { - return this->kp_; -} +const double& control::PID::GetKp() { return this->kp_; } -const double& control::PID::GetKd() { - return this->kd_; -} +const double& control::PID::GetKd() { return this->kd_; } -const double& control::PID::GetKi() { - return this->ki_; -} +const double& control::PID::GetKi() { return this->ki_; } // destructor -control::PID::~PID() { -} +control::PID::~PID() {} diff --git a/app/main.cpp b/app/main.cpp index 455920d0..547bc459 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -22,7 +22,8 @@ int main() { control::PID controller; double new_velocity = controller.Compute(4.0, 8.0); + double kp = controller.GetKp(); std::cout << "Actual Velocity: " << 4.0 << " Desired Velocity: " << 8.0 - << " New Velocity: " << new_velocity << std::endl; + << " New Velocity: " << new_velocity << " " << kp << std::endl; return 0; } From a7496c697abfad3b9e5047e5343aff841e556216 Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Mon, 28 Sep 2020 23:50:31 -0400 Subject: [PATCH 30/39] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 605b5981..31fb04a6 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,5 @@ # PID Controller (Test Driven Development) -[![Build Status](https://travis-ci.org/akhopkar01/PID_controller.svg?branch=master)](https://travis-ci.com/github/akhopkar01/PID_controller) +[![Build Status](https://travis-ci.org/akhopkar01/PID_controller.svg?branch=master)](https://travis-ci.org/github/akhopkar01/PID_controller) [![Coverage Status](https://coveralls.io/repos/github/akhopkar01/PID_controller/badge.svg?branch=master)](https://coveralls.io/github/akhopkar01/PID_controller?branch=master) --- From 31f11cc56c26ed9be2a5161983273d596a76cb4e Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Tue, 29 Sep 2020 00:09:26 -0400 Subject: [PATCH 31/39] Update .travis.yml --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1806e5aa..d35eba1f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,8 @@ matrix: before_install: - pip install --user cpp-coveralls + - sudo -H pip install --upgrade requests[security] + install: - sudo apt-get install -y -qq lcov script: @@ -34,6 +36,6 @@ script: - test/cpp-test after_success: - - coveralls --root .. -E ".*external.*" -E ".*CMakeFiles.*" -E ".*test/.*.cpp.*" -t WpS2LBk3t7xe2Vt8usbpbp03mDsNUHLud + - coveralls --root .. -E ".*external.*" -E ".*CMakeFiles.*" -E ".*test/.*.cpp.*" notifications: email: false From 8306a7ec004edd5eee95494a5cff9be5955b47c1 Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Tue, 29 Sep 2020 00:09:41 -0400 Subject: [PATCH 32/39] Delete .coveralls.yml --- .coveralls.yml | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .coveralls.yml diff --git a/.coveralls.yml b/.coveralls.yml deleted file mode 100644 index 57bbaa1a..00000000 --- a/.coveralls.yml +++ /dev/null @@ -1 +0,0 @@ -repo_token: WpS2LBk3t7xe2Vt8usbpbp03mDsNUHLud From b0414a6c263f7a83346d5ba46e5a6e6e05bb40ca Mon Sep 17 00:00:00 2001 From: akhopkar01 Date: Tue, 29 Sep 2020 00:14:46 -0400 Subject: [PATCH 33/39] changed include path --- app/main.cpp | 2 +- test/test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/main.cpp b/app/main.cpp index 547bc459..9e996f47 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -12,7 +12,7 @@ #include #include -#include "PID.h" +#include "../include/PID.h" /** * @brief: main function diff --git a/test/test.cpp b/test/test.cpp index f077957c..f0fb763a 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -12,7 +12,7 @@ #include -#include "PID.h" +#include "../include/PID.h" // instance of the class control::PID pid; From 3a22623f26a90a4418ba48c336ca6980011d5c82 Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Tue, 29 Sep 2020 00:20:30 -0400 Subject: [PATCH 34/39] Update readme.md --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 31fb04a6..ae644289 100644 --- a/readme.md +++ b/readme.md @@ -9,6 +9,7 @@ This project is worked in groups to carry out TDD. Author: [ Part 1 ] Aditya Khopkar (driver), Rajeshwar N S (navigator) + [ Part 2 ] Spencer Elyard (driver), Daniel Sahu (navigator) ## Standard install via command-line From 8ce353d1825000988ad1590cdf1fce3d5457a432 Mon Sep 17 00:00:00 2001 From: akhopkar01 Date: Tue, 29 Sep 2020 00:24:56 -0400 Subject: [PATCH 35/39] fix: Minor change Ln 24 --- app/main.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/main.cpp b/app/main.cpp index 9e996f47..b43cbe32 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -22,8 +22,7 @@ int main() { control::PID controller; double new_velocity = controller.Compute(4.0, 8.0); - double kp = controller.GetKp(); std::cout << "Actual Velocity: " << 4.0 << " Desired Velocity: " << 8.0 - << " New Velocity: " << new_velocity << " " << kp << std::endl; + << " New Velocity: " << new_velocity << std::endl; return 0; } From 23c3c807250adc1ca09054c27830045959f53331 Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Tue, 29 Sep 2020 15:27:52 -0400 Subject: [PATCH 36/39] Update readme.md --- readme.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/readme.md b/readme.md index ae644289..198ff630 100644 --- a/readme.md +++ b/readme.md @@ -14,7 +14,7 @@ Author: ## Standard install via command-line ``` -git clone --recursive https://github.com/selyard/PID_controller +git clone --recursive https://github.com/akhopkar01/PID_controller cd PID_controller mkdir build cd build @@ -32,6 +32,3 @@ make make code_coverage ``` This generates a index.html page in the build/coverage sub-directory that can be viewed locally in a web browser. - -## TO DO for future: -- Investigate additional test cases for PID controller From fa9a814e94e2408c7ae1329934b5a5620c0d986c Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Tue, 29 Sep 2020 15:38:27 -0400 Subject: [PATCH 37/39] Update readme.md --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 198ff630..d3aee302 100644 --- a/readme.md +++ b/readme.md @@ -5,9 +5,9 @@ ## Overview -This project is worked in groups to carry out TDD. +This project is worked in groups to carry out TDD. We have implemented a PID controller with Unit Tests to validate software quality. -Author: +### Authors: [ Part 1 ] Aditya Khopkar (driver), Rajeshwar N S (navigator) [ Part 2 ] Spencer Elyard (driver), Daniel Sahu (navigator) From 0595295c952f1605973138c6a863b087c55a2639 Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Tue, 29 Sep 2020 15:41:33 -0400 Subject: [PATCH 38/39] Update readme.md --- readme.md | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/readme.md b/readme.md index d3aee302..831d7093 100644 --- a/readme.md +++ b/readme.md @@ -32,3 +32,68 @@ make make code_coverage ``` This generates a index.html page in the build/coverage sub-directory that can be viewed locally in a web browser. + +## Working with Eclipse IDE ## + +## Installation + +In your Eclipse workspace directory (or create a new one), checkout the repo (and submodules) +``` +mkdir -p ~/workspace +cd ~/workspace +git clone --recursive https://github.com/danielmohansahu/mobile-pid-controller +``` + +In your work directory, use cmake to create an Eclipse project for an [out-of-source build] of mobile-pid-controller + +``` +cd ~/workspace +mkdir -p boilerplate-eclipse +cd boilerplate-eclipse +cmake -G "Eclipse CDT4 - Unix Makefiles" -D CMAKE_BUILD_TYPE=Debug -D CMAKE_ECLIPSE_VERSION=4.7.0 -D CMAKE_CXX_COMPILER_ARG1=-std=c++14 ../mobile-pid-controller/ +``` + +## Import + +Open Eclipse, go to File -> Import -> General -> Existing Projects into Workspace -> +Select "boilerplate-eclipse" directory created previously as root directory -> Finish + +## Edit + +Source files may be edited under the "[Source Directory]" label in the Project Explorer. + + +## Build + +To build the project, in Eclipse, unfold boilerplate-eclipse project in Project Explorer, +unfold Build Targets, double click on "all" to build all projects. + +## Run + +1. In Eclipse, right click on the boilerplate-eclipse in Project Explorer, +select Run As -> Local C/C++ Application + +2. Choose the binaries to run (e.g. shell-app, cpp-test for unit testing) + + +## Debug + + +1. Set breakpoint in source file (i.e. double click in the left margin on the line you want +the program to break). + +2. In Eclipse, right click on the boilerplate-eclipse in Project Explorer, select Debug As -> +Local C/C++ Application, choose the binaries to run (e.g. shell-app). + +3. If prompt to "Confirm Perspective Switch", select yes. + +4. Program will break at the breakpoint you set. + +5. Press Step Into (F5), Step Over (F6), Step Return (F7) to step/debug your program. + +6. Right click on the variable in editor to add watch expression to watch the variable in +debugger window. + +7. Press Terminate icon to terminate debugging and press C/C++ icon to switch back to C/C++ +perspetive view (or Windows->Perspective->Open Perspective->C/C++). + From 5f1904fd7753fe389397fa959ec9dfc98ffe3ee3 Mon Sep 17 00:00:00 2001 From: Aditya Khopkar <57739865+akhopkar01@users.noreply.github.com> Date: Tue, 29 Sep 2020 18:49:49 -0400 Subject: [PATCH 39/39] Update readme.md --- readme.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/readme.md b/readme.md index 831d7093..6894810c 100644 --- a/readme.md +++ b/readme.md @@ -12,6 +12,9 @@ This project is worked in groups to carry out TDD. We have implemented a PID con [ Part 2 ] Spencer Elyard (driver), Daniel Sahu (navigator) +### TO-DO for future: +Investigate additional test-cases for compute + ## Standard install via command-line ``` git clone --recursive https://github.com/akhopkar01/PID_controller