1d1491724SPatrick Venture /** 2d1491724SPatrick Venture * Copyright 2019 Google Inc. 3d1491724SPatrick Venture * 4d1491724SPatrick Venture * Licensed under the Apache License, Version 2.0 (the "License"); 5d1491724SPatrick Venture * you may not use this file except in compliance with the License. 6d1491724SPatrick Venture * You may obtain a copy of the License at 7d1491724SPatrick Venture * 8d1491724SPatrick Venture * http://www.apache.org/licenses/LICENSE-2.0 9d1491724SPatrick Venture * 10d1491724SPatrick Venture * Unless required by applicable law or agreed to in writing, software 11d1491724SPatrick Venture * distributed under the License is distributed on an "AS IS" BASIS, 12d1491724SPatrick Venture * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d1491724SPatrick Venture * See the License for the specific language governing permissions and 14d1491724SPatrick Venture * limitations under the License. 15d1491724SPatrick Venture */ 16d1491724SPatrick Venture 17d1491724SPatrick Venture #include "pid/buildjson.hpp" 18d1491724SPatrick Venture 19d1491724SPatrick Venture #include "conf.hpp" 2031058fd3SJosh Lehan #include "util.hpp" 21d1491724SPatrick Venture 22d1491724SPatrick Venture #include <nlohmann/json.hpp> 23a83a3eccSPatrick Venture 240e8fc398SBonnie Lo #include <iostream> 2531058fd3SJosh Lehan #include <limits> 26a83a3eccSPatrick Venture #include <map> 27d1491724SPatrick Venture #include <tuple> 28d1491724SPatrick Venture 29a076487aSPatrick Venture namespace pid_control 30a076487aSPatrick Venture { 31a076487aSPatrick Venture 32d1491724SPatrick Venture using json = nlohmann::json; 33d1491724SPatrick Venture 34f81f2886SJames Feist namespace conf 35f81f2886SJames Feist { 3631058fd3SJosh Lehan 37f81f2886SJames Feist void from_json(const json& j, conf::ControllerInfo& c) 38d1491724SPatrick Venture { 3931058fd3SJosh Lehan std::vector<std::string> inputNames; 40*3f0f7bc3SJosh Lehan std::vector<std::string> missingAcceptableNames; 4131058fd3SJosh Lehan 42d1491724SPatrick Venture j.at("type").get_to(c.type); 4331058fd3SJosh Lehan j.at("inputs").get_to(inputNames); 44d1491724SPatrick Venture j.at("setpoint").get_to(c.setpoint); 45d1491724SPatrick Venture 4631058fd3SJosh Lehan std::vector<double> inputTempToMargin; 4731058fd3SJosh Lehan 4831058fd3SJosh Lehan auto findTempToMargin = j.find("tempToMargin"); 4931058fd3SJosh Lehan if (findTempToMargin != j.end()) 5031058fd3SJosh Lehan { 5131058fd3SJosh Lehan findTempToMargin->get_to(inputTempToMargin); 5231058fd3SJosh Lehan } 5331058fd3SJosh Lehan 54*3f0f7bc3SJosh Lehan auto findMissingAcceptable = j.find("missingIsAcceptable"); 55*3f0f7bc3SJosh Lehan if (findMissingAcceptable != j.end()) 56*3f0f7bc3SJosh Lehan { 57*3f0f7bc3SJosh Lehan findMissingAcceptable->get_to(missingAcceptableNames); 58*3f0f7bc3SJosh Lehan } 59*3f0f7bc3SJosh Lehan 60*3f0f7bc3SJosh Lehan c.inputs = spliceInputs(inputNames, inputTempToMargin, 61*3f0f7bc3SJosh Lehan missingAcceptableNames); 6231058fd3SJosh Lehan 63d1491724SPatrick Venture /* TODO: We need to handle parsing other PID controller configurations. 64d1491724SPatrick Venture * We can do that by checking for different keys and making the decision 65d1491724SPatrick Venture * accordingly. 66d1491724SPatrick Venture */ 67d1491724SPatrick Venture auto p = j.at("pid"); 68375f7098SHank Liou 69375f7098SHank Liou auto positiveHysteresis = p.find("positiveHysteresis"); 70375f7098SHank Liou auto negativeHysteresis = p.find("negativeHysteresis"); 71c612c051SJosh Lehan auto derivativeCoeff = p.find("derivativeCoeff"); 72375f7098SHank Liou auto positiveHysteresisValue = 0.0; 73375f7098SHank Liou auto negativeHysteresisValue = 0.0; 74c612c051SJosh Lehan auto derivativeCoeffValue = 0.0; 75375f7098SHank Liou if (positiveHysteresis != p.end()) 76375f7098SHank Liou { 77c612c051SJosh Lehan positiveHysteresis->get_to(positiveHysteresisValue); 78375f7098SHank Liou } 79375f7098SHank Liou if (negativeHysteresis != p.end()) 80375f7098SHank Liou { 81c612c051SJosh Lehan negativeHysteresis->get_to(negativeHysteresisValue); 82c612c051SJosh Lehan } 83c612c051SJosh Lehan if (derivativeCoeff != p.end()) 84c612c051SJosh Lehan { 85c612c051SJosh Lehan derivativeCoeff->get_to(derivativeCoeffValue); 86375f7098SHank Liou } 87375f7098SHank Liou 889fe3a3c7Sykchiu auto failSafePercent = j.find("FailSafePercent"); 899fe3a3c7Sykchiu auto failSafePercentValue = 0; 909fe3a3c7Sykchiu if (failSafePercent != j.end()) 919fe3a3c7Sykchiu { 929fe3a3c7Sykchiu failSafePercent->get_to(failSafePercentValue); 939fe3a3c7Sykchiu } 949fe3a3c7Sykchiu c.failSafePercent = failSafePercentValue; 959fe3a3c7Sykchiu 96375f7098SHank Liou if (c.type != "stepwise") 97375f7098SHank Liou { 98d1491724SPatrick Venture p.at("samplePeriod").get_to(c.pidInfo.ts); 99d1491724SPatrick Venture p.at("proportionalCoeff").get_to(c.pidInfo.proportionalCoeff); 100d1491724SPatrick Venture p.at("integralCoeff").get_to(c.pidInfo.integralCoeff); 101903b0427SPatrick Venture p.at("feedFwdOffsetCoeff").get_to(c.pidInfo.feedFwdOffset); 102d1491724SPatrick Venture p.at("feedFwdGainCoeff").get_to(c.pidInfo.feedFwdGain); 103d1491724SPatrick Venture p.at("integralLimit_min").get_to(c.pidInfo.integralLimit.min); 104d1491724SPatrick Venture p.at("integralLimit_max").get_to(c.pidInfo.integralLimit.max); 105d1491724SPatrick Venture p.at("outLim_min").get_to(c.pidInfo.outLim.min); 106d1491724SPatrick Venture p.at("outLim_max").get_to(c.pidInfo.outLim.max); 107d1491724SPatrick Venture p.at("slewNeg").get_to(c.pidInfo.slewNeg); 108d1491724SPatrick Venture p.at("slewPos").get_to(c.pidInfo.slewPos); 109d1491724SPatrick Venture 110c612c051SJosh Lehan // Unlike other coefficients, treat derivativeCoeff as an optional 111c612c051SJosh Lehan // parameter, as support for it is fairly new, to avoid breaking 112c612c051SJosh Lehan // existing configurations in the field that predate it. 113375f7098SHank Liou c.pidInfo.positiveHysteresis = positiveHysteresisValue; 114375f7098SHank Liou c.pidInfo.negativeHysteresis = negativeHysteresisValue; 115c612c051SJosh Lehan c.pidInfo.derivativeCoeff = derivativeCoeffValue; 116d1491724SPatrick Venture } 117d1491724SPatrick Venture else 118d1491724SPatrick Venture { 119375f7098SHank Liou p.at("samplePeriod").get_to(c.stepwiseInfo.ts); 120375f7098SHank Liou p.at("isCeiling").get_to(c.stepwiseInfo.isCeiling); 121375f7098SHank Liou 122375f7098SHank Liou for (size_t i = 0; i < ec::maxStepwisePoints; i++) 123375f7098SHank Liou { 124375f7098SHank Liou c.stepwiseInfo.reading[i] = 125375f7098SHank Liou std::numeric_limits<double>::quiet_NaN(); 126375f7098SHank Liou c.stepwiseInfo.output[i] = std::numeric_limits<double>::quiet_NaN(); 127d1491724SPatrick Venture } 128d1491724SPatrick Venture 129375f7098SHank Liou auto reading = p.find("reading"); 130375f7098SHank Liou if (reading != p.end()) 131d1491724SPatrick Venture { 132375f7098SHank Liou auto r = p.at("reading"); 133375f7098SHank Liou for (size_t i = 0; i < ec::maxStepwisePoints; i++) 134375f7098SHank Liou { 135375f7098SHank Liou auto n = r.find(std::to_string(i)); 136375f7098SHank Liou if (n != r.end()) 137375f7098SHank Liou { 138375f7098SHank Liou r.at(std::to_string(i)).get_to(c.stepwiseInfo.reading[i]); 139d1491724SPatrick Venture } 140375f7098SHank Liou } 141375f7098SHank Liou } 142375f7098SHank Liou 143375f7098SHank Liou auto output = p.find("output"); 144375f7098SHank Liou if (output != p.end()) 145d1491724SPatrick Venture { 146375f7098SHank Liou auto o = p.at("output"); 147375f7098SHank Liou for (size_t i = 0; i < ec::maxStepwisePoints; i++) 148375f7098SHank Liou { 149375f7098SHank Liou auto n = o.find(std::to_string(i)); 150375f7098SHank Liou if (n != o.end()) 151375f7098SHank Liou { 152375f7098SHank Liou o.at(std::to_string(i)).get_to(c.stepwiseInfo.output[i]); 153375f7098SHank Liou } 154375f7098SHank Liou } 155375f7098SHank Liou } 156375f7098SHank Liou 157375f7098SHank Liou c.stepwiseInfo.positiveHysteresis = positiveHysteresisValue; 158375f7098SHank Liou c.stepwiseInfo.negativeHysteresis = negativeHysteresisValue; 159d1491724SPatrick Venture } 160d1491724SPatrick Venture } 16131058fd3SJosh Lehan 162f81f2886SJames Feist } // namespace conf 163d1491724SPatrick Venture 164239aa7d7SHarvey Wu inline void getCycleTimeSetting(const auto& zone, const int id, 165239aa7d7SHarvey Wu const std::string& attributeName, 166239aa7d7SHarvey Wu uint64_t& value) 167239aa7d7SHarvey Wu { 168239aa7d7SHarvey Wu auto findAttributeName = zone.find(attributeName); 169239aa7d7SHarvey Wu if (findAttributeName != zone.end()) 170239aa7d7SHarvey Wu { 171239aa7d7SHarvey Wu uint64_t tmpAttributeValue = 0; 172239aa7d7SHarvey Wu findAttributeName->get_to(tmpAttributeValue); 173239aa7d7SHarvey Wu if (tmpAttributeValue >= 1) 174239aa7d7SHarvey Wu { 175239aa7d7SHarvey Wu value = tmpAttributeValue; 176239aa7d7SHarvey Wu } 177239aa7d7SHarvey Wu else 178239aa7d7SHarvey Wu { 179239aa7d7SHarvey Wu std::cerr << "Zone " << id << ": " << attributeName 180239aa7d7SHarvey Wu << " is invalid. Use default " << value << " ms\n"; 181239aa7d7SHarvey Wu } 182239aa7d7SHarvey Wu } 183239aa7d7SHarvey Wu else 184239aa7d7SHarvey Wu { 185239aa7d7SHarvey Wu std::cerr << "Zone " << id << ": " << attributeName 186239aa7d7SHarvey Wu << " cannot find setting. Use default " << value << " ms\n"; 187239aa7d7SHarvey Wu } 188239aa7d7SHarvey Wu } 189239aa7d7SHarvey Wu 1901df9e879SPatrick Venture std::pair<std::map<int64_t, conf::PIDConf>, std::map<int64_t, conf::ZoneConfig>> 191d1491724SPatrick Venture buildPIDsFromJson(const json& data) 192d1491724SPatrick Venture { 193d1491724SPatrick Venture // zone -> pids 194f81f2886SJames Feist std::map<int64_t, conf::PIDConf> pidConfig; 195d1491724SPatrick Venture // zone -> configs 1961df9e879SPatrick Venture std::map<int64_t, conf::ZoneConfig> zoneConfig; 197d1491724SPatrick Venture 198d1491724SPatrick Venture /* TODO: if zones is empty, that's invalid. */ 199d1491724SPatrick Venture auto zones = data["zones"]; 200d1491724SPatrick Venture for (const auto& zone : zones) 201d1491724SPatrick Venture { 202d1491724SPatrick Venture int64_t id; 203f81f2886SJames Feist conf::PIDConf thisZone; 2041df9e879SPatrick Venture conf::ZoneConfig thisZoneConfig; 205d1491724SPatrick Venture 206d1491724SPatrick Venture /* TODO: using at() throws a specific exception we can catch */ 207d1491724SPatrick Venture id = zone["id"]; 2083484bedaSJames Feist thisZoneConfig.minThermalOutput = zone["minThermalOutput"]; 209d1491724SPatrick Venture thisZoneConfig.failsafePercent = zone["failsafePercent"]; 210d1491724SPatrick Venture 211239aa7d7SHarvey Wu getCycleTimeSetting(zone, id, "cycleIntervalTimeMS", 212239aa7d7SHarvey Wu thisZoneConfig.cycleTime.cycleIntervalTimeMS); 213239aa7d7SHarvey Wu getCycleTimeSetting(zone, id, "updateThermalsTimeMS", 214239aa7d7SHarvey Wu thisZoneConfig.cycleTime.updateThermalsTimeMS); 2150e8fc398SBonnie Lo 216d1491724SPatrick Venture auto pids = zone["pids"]; 217d1491724SPatrick Venture for (const auto& pid : pids) 218d1491724SPatrick Venture { 219d1491724SPatrick Venture auto name = pid["name"]; 220f81f2886SJames Feist auto item = pid.get<conf::ControllerInfo>(); 221d1491724SPatrick Venture 2227c6d35d5Sykchiu if (thisZone.find(name) != thisZone.end()) 2237c6d35d5Sykchiu { 2247c6d35d5Sykchiu std::cerr << "Warning: zone " << id 2257c6d35d5Sykchiu << " have the same pid name " << name << std::endl; 2267c6d35d5Sykchiu } 2277c6d35d5Sykchiu 228d1491724SPatrick Venture thisZone[name] = item; 229d1491724SPatrick Venture } 230d1491724SPatrick Venture 231d1491724SPatrick Venture pidConfig[id] = thisZone; 232d1491724SPatrick Venture zoneConfig[id] = thisZoneConfig; 233d1491724SPatrick Venture } 234d1491724SPatrick Venture 235d1491724SPatrick Venture return std::make_pair(pidConfig, zoneConfig); 236d1491724SPatrick Venture } 237a076487aSPatrick Venture 238a076487aSPatrick Venture } // namespace pid_control 239