1 #pragma once 2 3 #include "pid.hpp" 4 5 #include <chrono> 6 #include <cstring> 7 #include <fstream> 8 #include <iostream> 9 #include <string> 10 11 namespace pid_control 12 { 13 namespace ec 14 { 15 16 // Trivial class for information exported from core PID loop function 17 struct PidCoreContext 18 { 19 double input; 20 double setpoint; 21 double error; 22 23 double proportionalTerm; 24 double integralTerm1; 25 double integralTerm2; 26 27 double derivativeTerm; 28 29 double feedFwdTerm; 30 double output1; 31 double output2; 32 33 double minOut; 34 double maxOut; 35 36 double integralTerm3; 37 double output3; 38 39 double integralTerm; 40 double output; 41 42 bool operator!=(const PidCoreContext& rhs) const = default; 43 bool operator==(const PidCoreContext& rhs) const = default; 44 }; 45 46 // Optional decorator class for each PID loop, to support logging 47 // Although this is a trivial class, it ended up needing the Six Horsemen 48 struct PidCoreLog 49 { 50 std::string nameOriginal; 51 std::string nameClean; 52 std::ofstream fileContext; 53 std::ofstream fileCoeffs; 54 std::chrono::milliseconds lastLog; 55 PidCoreContext lastContext; 56 bool moved; 57 58 PidCoreLog() : 59 nameOriginal(), nameClean(), fileContext(), fileCoeffs(), lastLog(), 60 lastContext(), moved(false) 61 {} 62 63 PidCoreLog(const PidCoreLog& copy) = delete; 64 65 PidCoreLog& operator=(const PidCoreLog& copy) = delete; 66 67 PidCoreLog(PidCoreLog&& move) 68 { 69 // Reuse assignment operator below 70 *this = std::move(move); 71 } 72 73 PidCoreLog& operator=(PidCoreLog&& move) 74 { 75 if (this != &move) 76 { 77 *this = std::move(move); 78 79 // Mark the moved object, so destructor knows it was moved 80 move.moved = true; 81 } 82 return *this; 83 } 84 85 ~PidCoreLog() 86 { 87 // Do not close files if ownership was moved to another object 88 if (!moved) 89 { 90 fileContext.close(); 91 fileCoeffs.close(); 92 } 93 } 94 }; 95 96 // Initializes logging files, call once per PID loop initialization 97 void LogInit(const std::string& name, pid_info_t* pidinfoptr); 98 99 // Returns PidCoreLog pointer, or nullptr if this PID loop not being logged 100 PidCoreLog* LogPeek(const std::string& name); 101 102 // Logs a line of logging, if different, or it has been long enough 103 void LogContext(PidCoreLog& pidLog, const std::chrono::milliseconds& msNow, 104 const PidCoreContext& coreLog); 105 106 // Takes a timestamp, suitable for column 1 of logging file output 107 std::chrono::milliseconds LogTimestamp(void); 108 109 } // namespace ec 110 } // namespace pid_control 111