blob: cf7df67cc634da4becc7126b8e724b7944d58cc5 [file] [log] [blame]
Patrick Ventured1491722019-02-08 14:37:45 -08001/**
2 * Copyright 2019 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "pid/buildjson.hpp"
18
19#include "conf.hpp"
20
Patrick Ventured1491722019-02-08 14:37:45 -080021#include <nlohmann/json.hpp>
Patrick Venturea83a3ec2020-08-04 09:52:05 -070022
Bonnie Lo0e8fc392022-10-05 10:20:55 +080023#include <iostream>
Patrick Venturea83a3ec2020-08-04 09:52:05 -070024#include <map>
Patrick Ventured1491722019-02-08 14:37:45 -080025#include <tuple>
26
Patrick Venturea0764872020-08-08 07:48:43 -070027namespace pid_control
28{
29
Patrick Ventured1491722019-02-08 14:37:45 -080030using json = nlohmann::json;
31
James Feistf81f2882019-02-26 11:26:36 -080032namespace conf
33{
34void from_json(const json& j, conf::ControllerInfo& c)
Patrick Ventured1491722019-02-08 14:37:45 -080035{
36 j.at("type").get_to(c.type);
37 j.at("inputs").get_to(c.inputs);
38 j.at("setpoint").get_to(c.setpoint);
39
40 /* TODO: We need to handle parsing other PID controller configurations.
41 * We can do that by checking for different keys and making the decision
42 * accordingly.
43 */
44 auto p = j.at("pid");
Patrick Ventured1491722019-02-08 14:37:45 -080045
46 auto positiveHysteresis = p.find("positiveHysteresis");
Hank Liou375f7092019-03-29 20:15:42 +080047 auto negativeHysteresis = p.find("negativeHysteresis");
48 auto positiveHysteresisValue = 0.0;
49 auto negativeHysteresisValue = 0.0;
50 if (positiveHysteresis != p.end())
Patrick Ventured1491722019-02-08 14:37:45 -080051 {
Hank Liou375f7092019-03-29 20:15:42 +080052 p.at("positiveHysteresis").get_to(positiveHysteresisValue);
Patrick Ventured1491722019-02-08 14:37:45 -080053 }
Hank Liou375f7092019-03-29 20:15:42 +080054 if (negativeHysteresis != p.end())
Patrick Ventured1491722019-02-08 14:37:45 -080055 {
Hank Liou375f7092019-03-29 20:15:42 +080056 p.at("negativeHysteresis").get_to(negativeHysteresisValue);
Patrick Ventured1491722019-02-08 14:37:45 -080057 }
58
Hank Liou375f7092019-03-29 20:15:42 +080059 if (c.type != "stepwise")
Patrick Ventured1491722019-02-08 14:37:45 -080060 {
Hank Liou375f7092019-03-29 20:15:42 +080061 p.at("samplePeriod").get_to(c.pidInfo.ts);
62 p.at("proportionalCoeff").get_to(c.pidInfo.proportionalCoeff);
63 p.at("integralCoeff").get_to(c.pidInfo.integralCoeff);
Bonnie Lo0e8fc392022-10-05 10:20:55 +080064 p.at("derivativeCoeff").get_to(c.pidInfo.derivativeCoeff);
Hank Liou375f7092019-03-29 20:15:42 +080065 p.at("feedFwdOffsetCoeff").get_to(c.pidInfo.feedFwdOffset);
66 p.at("feedFwdGainCoeff").get_to(c.pidInfo.feedFwdGain);
67 p.at("integralLimit_min").get_to(c.pidInfo.integralLimit.min);
68 p.at("integralLimit_max").get_to(c.pidInfo.integralLimit.max);
69 p.at("outLim_min").get_to(c.pidInfo.outLim.min);
70 p.at("outLim_max").get_to(c.pidInfo.outLim.max);
71 p.at("slewNeg").get_to(c.pidInfo.slewNeg);
72 p.at("slewPos").get_to(c.pidInfo.slewPos);
73
74 c.pidInfo.positiveHysteresis = positiveHysteresisValue;
75 c.pidInfo.negativeHysteresis = negativeHysteresisValue;
Patrick Ventured1491722019-02-08 14:37:45 -080076 }
77 else
78 {
Hank Liou375f7092019-03-29 20:15:42 +080079 p.at("samplePeriod").get_to(c.stepwiseInfo.ts);
80 p.at("isCeiling").get_to(c.stepwiseInfo.isCeiling);
81
82 for (size_t i = 0; i < ec::maxStepwisePoints; i++)
83 {
84 c.stepwiseInfo.reading[i] =
85 std::numeric_limits<double>::quiet_NaN();
86 c.stepwiseInfo.output[i] = std::numeric_limits<double>::quiet_NaN();
87 }
88
89 auto reading = p.find("reading");
90 if (reading != p.end())
91 {
92 auto r = p.at("reading");
93 for (size_t i = 0; i < ec::maxStepwisePoints; i++)
94 {
95 auto n = r.find(std::to_string(i));
96 if (n != r.end())
97 {
98 r.at(std::to_string(i)).get_to(c.stepwiseInfo.reading[i]);
99 }
100 }
101 }
102
103 auto output = p.find("output");
104 if (output != p.end())
105 {
106 auto o = p.at("output");
107 for (size_t i = 0; i < ec::maxStepwisePoints; i++)
108 {
109 auto n = o.find(std::to_string(i));
110 if (n != o.end())
111 {
112 o.at(std::to_string(i)).get_to(c.stepwiseInfo.output[i]);
113 }
114 }
115 }
116
117 c.stepwiseInfo.positiveHysteresis = positiveHysteresisValue;
118 c.stepwiseInfo.negativeHysteresis = negativeHysteresisValue;
Patrick Ventured1491722019-02-08 14:37:45 -0800119 }
120}
James Feistf81f2882019-02-26 11:26:36 -0800121} // namespace conf
Patrick Ventured1491722019-02-08 14:37:45 -0800122
Patrick Venture1df9e872020-10-08 15:35:01 -0700123std::pair<std::map<int64_t, conf::PIDConf>, std::map<int64_t, conf::ZoneConfig>>
Patrick Ventured1491722019-02-08 14:37:45 -0800124 buildPIDsFromJson(const json& data)
125{
126 // zone -> pids
James Feistf81f2882019-02-26 11:26:36 -0800127 std::map<int64_t, conf::PIDConf> pidConfig;
Patrick Ventured1491722019-02-08 14:37:45 -0800128 // zone -> configs
Patrick Venture1df9e872020-10-08 15:35:01 -0700129 std::map<int64_t, conf::ZoneConfig> zoneConfig;
Patrick Ventured1491722019-02-08 14:37:45 -0800130
131 /* TODO: if zones is empty, that's invalid. */
132 auto zones = data["zones"];
133 for (const auto& zone : zones)
134 {
135 int64_t id;
James Feistf81f2882019-02-26 11:26:36 -0800136 conf::PIDConf thisZone;
Patrick Venture1df9e872020-10-08 15:35:01 -0700137 conf::ZoneConfig thisZoneConfig;
Patrick Ventured1491722019-02-08 14:37:45 -0800138
139 /* TODO: using at() throws a specific exception we can catch */
140 id = zone["id"];
James Feist3484bed2019-02-25 13:28:18 -0800141 thisZoneConfig.minThermalOutput = zone["minThermalOutput"];
Patrick Ventured1491722019-02-08 14:37:45 -0800142 thisZoneConfig.failsafePercent = zone["failsafePercent"];
143
Bonnie Lo0e8fc392022-10-05 10:20:55 +0800144 auto findTimeInterval = zone.find("cycleIntervalTimeMS");
145 if (findTimeInterval != zone.end())
146 {
147 uint64_t tmp;
148 findTimeInterval->get_to(tmp);
149 if (tmp != 0)
150 {
151 thisZoneConfig.cycleTime.cycleIntervalTimeMS = tmp;
152 }
153 else
154 {
155 std::cerr << "cycleIntervalTimeMS cannot be 0. Use default "
156 << thisZoneConfig.cycleTime.cycleIntervalTimeMS
157 << " ms\n";
158 }
159 }
160
161 auto findUpdateThermalsTime = zone.find("updateThermalsTimeMS");
162 if (findUpdateThermalsTime != zone.end())
163 {
164 uint64_t tmp;
165 findUpdateThermalsTime->get_to(tmp);
166 if (tmp != 0)
167 {
168 thisZoneConfig.cycleTime.updateThermalsTimeMS = tmp;
169 }
170 else
171 {
172 std::cerr << "updateThermalsTimeMS cannot be 0. Use default "
173 << thisZoneConfig.cycleTime.updateThermalsTimeMS
174 << " ms\n";
175 }
176 }
177
178 double updateCount =
179 double(thisZoneConfig.cycleTime.updateThermalsTimeMS) /
180 double(thisZoneConfig.cycleTime.cycleIntervalTimeMS);
181
182 /* Check if updateThermalsTimeMS could be divided by cycleIntervalTimeMS
183 * without leaving a remainder */
184 if (updateCount != std::ceil(updateCount))
185 {
186 std::cerr
187 << "updateThermalsTimeMS cannot be divided by "
188 "cycleIntervalTimeMS without leaving a remainder. Using the "
189 "smallest integer that is not less than the result.\n";
190 updateCount = std::ceil(updateCount);
191 }
192 thisZoneConfig.cycleTime.updateThermalsTimeMS = updateCount;
193
Patrick Ventured1491722019-02-08 14:37:45 -0800194 auto pids = zone["pids"];
195 for (const auto& pid : pids)
196 {
197 auto name = pid["name"];
James Feistf81f2882019-02-26 11:26:36 -0800198 auto item = pid.get<conf::ControllerInfo>();
Patrick Ventured1491722019-02-08 14:37:45 -0800199
200 thisZone[name] = item;
201 }
202
203 pidConfig[id] = thisZone;
204 zoneConfig[id] = thisZoneConfig;
205 }
206
207 return std::make_pair(pidConfig, zoneConfig);
208}
Patrick Venturea0764872020-08-08 07:48:43 -0700209
210} // namespace pid_control