blob: d46787626003f2f21f0b8ecf841693e3fd99b509 [file] [log] [blame]
Tyler Chatow37ecdcd2019-01-26 20:18:42 -08001#include "y2019/constants.h"
2
3#include <inttypes.h>
4
5#include <map>
6
7#if __has_feature(address_sanitizer)
8#include "sanitizer/lsan_interface.h"
9#endif
10
11#include "aos/logging/logging.h"
12#include "aos/mutex/mutex.h"
13#include "aos/network/team_number.h"
14#include "aos/once.h"
Theo Bafrali00e42272019-02-12 01:07:46 -080015#include "y2019/control_loops/superstructure/elevator/integral_elevator_plant.h"
16#include "y2019/control_loops/superstructure/intake/integral_intake_plant.h"
17#include "y2019/control_loops/superstructure/stilts/integral_stilts_plant.h"
18#include "y2019/control_loops/superstructure/wrist/integral_wrist_plant.h"
Tyler Chatow37ecdcd2019-01-26 20:18:42 -080019
20namespace y2019 {
21namespace constants {
22
Theo Bafrali00e42272019-02-12 01:07:46 -080023using ::frc971::zeroing::PotAndAbsoluteEncoderZeroingEstimator;
24
Tyler Chatow37ecdcd2019-01-26 20:18:42 -080025const int Values::kZeroingSampleSize;
James Kuszmaul09f564a2019-02-18 17:37:09 -080026constexpr size_t Values::kNumCameras;
Tyler Chatow37ecdcd2019-01-26 20:18:42 -080027
28namespace {
29
30const uint16_t kCompTeamNumber = 971;
31const uint16_t kPracticeTeamNumber = 9971;
Alex Perry5fb5ff22019-02-09 21:53:17 -080032const uint16_t kCodingRobotTeamNumber = 7971;
Tyler Chatow37ecdcd2019-01-26 20:18:42 -080033
James Kuszmaul22c5ab32019-02-09 14:45:58 -080034constexpr double FeetToMeters(double ft) {
35 return 0.3048 * ft;
36}
37constexpr double InchToMeters(double in) {
38 return 0.0254 * in;
39}
40constexpr double DegToRad(double deg) {
41 return deg * M_PI / 180.0;
42}
43
Tyler Chatow37ecdcd2019-01-26 20:18:42 -080044const Values *DoGetValuesForTeam(uint16_t team) {
45 Values *const r = new Values();
Alex Perry5fb5ff22019-02-09 21:53:17 -080046 Values::PotAndAbsConstants *const elevator = &r->elevator;
Theo Bafrali00e42272019-02-12 01:07:46 -080047 ::frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemParams<
48 ::frc971::zeroing::PotAndAbsoluteEncoderZeroingEstimator>
49 *const elevator_params = &(elevator->subsystem_params);
Alex Perry5fb5ff22019-02-09 21:53:17 -080050 Values::PotAndAbsConstants *const stilts = &r->stilts;
Theo Bafrali00e42272019-02-12 01:07:46 -080051 ::frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemParams<
52 ::frc971::zeroing::PotAndAbsoluteEncoderZeroingEstimator>
53 *const stilts_params = &(stilts->subsystem_params);
Alex Perry5fb5ff22019-02-09 21:53:17 -080054 Values::PotAndAbsConstants *const wrist = &r->wrist;
Theo Bafrali00e42272019-02-12 01:07:46 -080055 ::frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemParams<
56 ::frc971::zeroing::PotAndAbsoluteEncoderZeroingEstimator>
57 *const wrist_params = &(wrist->subsystem_params);
58 ::frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemParams<
59 ::frc971::zeroing::AbsoluteEncoderZeroingEstimator> *const intake =
60 &r->intake;
Alex Perry5fb5ff22019-02-09 21:53:17 -080061
Theo Bafrali00e42272019-02-12 01:07:46 -080062 // Elevator constants.
Austin Schuh7f87b472019-02-15 23:20:57 -080063 elevator_params->zeroing_voltage = 3.0;
Theo Bafrali00e42272019-02-12 01:07:46 -080064 elevator_params->operating_voltage = 12.0;
65 elevator_params->zeroing_profile_params = {0.1, 1.0};
Austin Schuh7f87b472019-02-15 23:20:57 -080066 elevator_params->default_profile_params = {4.0, 16.0};
Theo Bafrali00e42272019-02-12 01:07:46 -080067 elevator_params->range = Values::kElevatorRange();
68 elevator_params->make_integral_loop =
69 &control_loops::superstructure::elevator::MakeIntegralElevatorLoop;
70 elevator_params->zeroing_constants.average_filter_size =
71 Values::kZeroingSampleSize;
72 elevator_params->zeroing_constants.one_revolution_distance =
Alex Perry5fb5ff22019-02-09 21:53:17 -080073 M_PI * 2.0 * constants::Values::kElevatorEncoderRatio();
Theo Bafrali00e42272019-02-12 01:07:46 -080074 elevator_params->zeroing_constants.zeroing_threshold = 0.005;
75 elevator_params->zeroing_constants.moving_buffer_size = 20;
76 elevator_params->zeroing_constants.allowable_encoder_error = 0.9;
Alex Perry5fb5ff22019-02-09 21:53:17 -080077
Theo Bafrali00e42272019-02-12 01:07:46 -080078 // Wrist constants.
79 wrist_params->zeroing_voltage = 4.0;
80 wrist_params->operating_voltage = 12.0;
81 wrist_params->zeroing_profile_params = {0.5, 2.0};
Austin Schuh7f87b472019-02-15 23:20:57 -080082 wrist_params->default_profile_params = {10.0, 40.0};
Theo Bafrali00e42272019-02-12 01:07:46 -080083 wrist_params->range = Values::kWristRange();
84 wrist_params->make_integral_loop =
85 &control_loops::superstructure::wrist::MakeIntegralWristLoop;
86 wrist_params->zeroing_constants.average_filter_size =
87 Values::kZeroingSampleSize;
88 wrist_params->zeroing_constants.one_revolution_distance =
Alex Perry5fb5ff22019-02-09 21:53:17 -080089 M_PI * 2.0 * constants::Values::kWristEncoderRatio();
Theo Bafrali00e42272019-02-12 01:07:46 -080090 wrist_params->zeroing_constants.zeroing_threshold = 0.0005;
91 wrist_params->zeroing_constants.moving_buffer_size = 20;
92 wrist_params->zeroing_constants.allowable_encoder_error = 0.9;
93
94 // Intake constants.
Austin Schuh7f87b472019-02-15 23:20:57 -080095 intake->zeroing_voltage = 3.0;
Theo Bafrali00e42272019-02-12 01:07:46 -080096 intake->operating_voltage = 12.0;
97 intake->zeroing_profile_params = {0.5, 3.0};
Austin Schuh7f87b472019-02-15 23:20:57 -080098 intake->default_profile_params = {6.0, 30.0};
Theo Bafrali00e42272019-02-12 01:07:46 -080099 intake->range = Values::kIntakeRange();
100 intake->make_integral_loop =
101 control_loops::superstructure::intake::MakeIntegralIntakeLoop;
102 intake->zeroing_constants.average_filter_size = Values::kZeroingSampleSize;
103 intake->zeroing_constants.one_revolution_distance =
104 M_PI * 2.0 * constants::Values::kIntakeEncoderRatio();
105 intake->zeroing_constants.zeroing_threshold = 0.0005;
106 intake->zeroing_constants.moving_buffer_size = 20;
107 intake->zeroing_constants.allowable_encoder_error = 0.9;
Austin Schuhc9c157a2019-02-19 13:36:22 -0800108 intake->zeroing_constants.middle_position = Values::kIntakeRange().middle();
Theo Bafrali00e42272019-02-12 01:07:46 -0800109
110 // Stilts constants.
Austin Schuh7f87b472019-02-15 23:20:57 -0800111 stilts_params->zeroing_voltage = 3.0;
Theo Bafrali00e42272019-02-12 01:07:46 -0800112 stilts_params->operating_voltage = 12.0;
Austin Schuh7f87b472019-02-15 23:20:57 -0800113 stilts_params->zeroing_profile_params = {0.1, 0.5};
Austin Schuh08bd22d2019-02-22 20:48:20 -0800114 stilts_params->default_profile_params = {0.15, 0.5};
Theo Bafrali00e42272019-02-12 01:07:46 -0800115 stilts_params->range = Values::kStiltsRange();
116 stilts_params->make_integral_loop =
117 &control_loops::superstructure::stilts::MakeIntegralStiltsLoop;
118 stilts_params->zeroing_constants.average_filter_size =
119 Values::kZeroingSampleSize;
120 stilts_params->zeroing_constants.one_revolution_distance =
121 M_PI * 2.0 * constants::Values::kStiltsEncoderRatio();
122 stilts_params->zeroing_constants.zeroing_threshold = 0.0005;
123 stilts_params->zeroing_constants.moving_buffer_size = 20;
124 stilts_params->zeroing_constants.allowable_encoder_error = 0.9;
Tyler Chatow37ecdcd2019-01-26 20:18:42 -0800125
James Kuszmaul09f564a2019-02-18 17:37:09 -0800126 r->camera_noise_parameters = {.max_viewable_distance = 10.0,
127 .heading_noise = 0.02,
128 .nominal_distance_noise = 0.06,
129 .nominal_skew_noise = 0.1,
130 .nominal_height_noise = 0.01};
131
James Kuszmaul81df16a2019-03-03 17:17:34 -0800132 constexpr double kInchesToMeters = 0.0254;
Tyler Chatow37ecdcd2019-01-26 20:18:42 -0800133 switch (team) {
134 // A set of constants for tests.
135 case 1:
Theo Bafrali00e42272019-02-12 01:07:46 -0800136 elevator_params->zeroing_constants.measured_absolute_position = 0.0;
Alex Perry5fb5ff22019-02-09 21:53:17 -0800137 elevator->potentiometer_offset = 0.0;
138
Theo Bafrali00e42272019-02-12 01:07:46 -0800139 intake->zeroing_constants.measured_absolute_position = 0.0;
Alex Perry5fb5ff22019-02-09 21:53:17 -0800140
Theo Bafrali00e42272019-02-12 01:07:46 -0800141 wrist_params->zeroing_constants.measured_absolute_position = 0.0;
Alex Perry5fb5ff22019-02-09 21:53:17 -0800142 wrist->potentiometer_offset = 0.0;
Theo Bafrali00e42272019-02-12 01:07:46 -0800143
144 stilts_params->zeroing_constants.measured_absolute_position = 0.0;
145 stilts->potentiometer_offset = 0.0;
James Kuszmaul09f564a2019-02-18 17:37:09 -0800146
147 // Deliberately make FOV a bit large so that we are overly conservative in
148 // our EKF.
149 for (auto &camera : r->cameras) {
150 camera.fov = M_PI_2 * 1.1;
151 }
152 r->cameras[0].pose.set_theta(M_PI);
153 r->cameras[1].pose.set_theta(0.26);
154 r->cameras[2].pose.set_theta(-0.26);
155 r->cameras[3].pose.set_theta(M_PI_2);
156 r->cameras[4].pose.set_theta(-M_PI_2);
Tyler Chatow37ecdcd2019-01-26 20:18:42 -0800157 break;
158
159 case kCompTeamNumber:
Austin Schuh4b5e3222019-02-19 16:48:50 -0800160 elevator_params->zeroing_constants.measured_absolute_position = 0.024407;
161 elevator->potentiometer_offset = -0.075017 + 0.015837 + 0.009793 - 0.012017;
Alex Perry5fb5ff22019-02-09 21:53:17 -0800162
Austin Schuhc9c157a2019-02-19 13:36:22 -0800163 intake->zeroing_constants.measured_absolute_position = 1.860016;
Alex Perry5fb5ff22019-02-09 21:53:17 -0800164
Austin Schuhc9c157a2019-02-19 13:36:22 -0800165 wrist_params->zeroing_constants.measured_absolute_position = 0.163840;
166 wrist->potentiometer_offset = -4.257454;
Theo Bafrali00e42272019-02-12 01:07:46 -0800167
Austin Schuhc9c157a2019-02-19 13:36:22 -0800168 stilts_params->zeroing_constants.measured_absolute_position = 0.030049;
169 stilts->potentiometer_offset = -0.015760 + 0.011604;
Tyler Chatow37ecdcd2019-01-26 20:18:42 -0800170 break;
171
172 case kPracticeTeamNumber:
Austin Schuh4b5e3222019-02-19 16:48:50 -0800173 elevator_params->zeroing_constants.measured_absolute_position = 0.167722;
174 elevator->potentiometer_offset = -0.022320 + 0.020567 - 0.022355 - 0.006497;
Alex Perry5fb5ff22019-02-09 21:53:17 -0800175
Austin Schuh862d4de2019-02-17 14:15:18 -0800176 intake->zeroing_constants.measured_absolute_position = 1.756847;
Austin Schuhed7f8632019-02-15 23:12:20 -0800177
178 wrist_params->zeroing_constants.measured_absolute_position = 0.357394;
179 wrist->potentiometer_offset = -1.479097 - 2.740303;
180
Sabina Davis2184a282019-03-02 11:59:03 -0800181 stilts_params->zeroing_constants.measured_absolute_position = 0.048258;
182 stilts->potentiometer_offset = -0.093820 + 0.0124 - 0.008334;
Alex Perry5fb5ff22019-02-09 21:53:17 -0800183 break;
184
185 case kCodingRobotTeamNumber:
Theo Bafrali00e42272019-02-12 01:07:46 -0800186 elevator_params->zeroing_constants.measured_absolute_position = 0.0;
Alex Perry5fb5ff22019-02-09 21:53:17 -0800187 elevator->potentiometer_offset = 0.0;
188
Theo Bafrali00e42272019-02-12 01:07:46 -0800189 intake->zeroing_constants.measured_absolute_position = 0.0;
Alex Perry5fb5ff22019-02-09 21:53:17 -0800190
Theo Bafrali00e42272019-02-12 01:07:46 -0800191 wrist_params->zeroing_constants.measured_absolute_position = 0.0;
Alex Perry5fb5ff22019-02-09 21:53:17 -0800192 wrist->potentiometer_offset = 0.0;
Theo Bafrali00e42272019-02-12 01:07:46 -0800193
194 stilts_params->zeroing_constants.measured_absolute_position = 0.0;
195 stilts->potentiometer_offset = 0.0;
James Kuszmaul81df16a2019-03-03 17:17:34 -0800196
197 // Deliberately make FOV a bit large so that we are overly conservative in
198 // our EKF.
199 for (auto &camera : r->cameras) {
200 camera.fov = M_PI_2 * 1.1;
201 }
202 // 0 - 2 ar ecurrently unpopulated:
203 r->cameras[0].pose.set_theta(M_PI);
204 r->cameras[1].pose.set_theta(0.26);
205 r->cameras[2].pose.set_theta(-0.26);
206 // 3 is front right
207 r->cameras[3].pose.set_theta(-12.2377 / 180.0 * M_PI);
208 *r->cameras[3].pose.mutable_pos() << 4.98126 * kInchesToMeters,
209 1.96988 * kInchesToMeters, 33.4276 * kInchesToMeters;
210 // 4 is back
211 r->cameras[4].pose.set_theta(M_PI + 2.581 * M_PI / 180.0);
212 *r->cameras[4].pose.mutable_pos() << -6.93309 * kInchesToMeters,
213 2.64735 * kInchesToMeters, 32.8758 * kInchesToMeters;
Tyler Chatow37ecdcd2019-01-26 20:18:42 -0800214 break;
215
216 default:
217 LOG(FATAL, "unknown team #%" PRIu16 "\n", team);
218 }
219
220 return r;
221}
222
223const Values *DoGetValues() {
224 uint16_t team = ::aos::network::GetTeamNumber();
225 LOG(INFO, "creating a Constants for team %" PRIu16 "\n", team);
226 return DoGetValuesForTeam(team);
227}
228
229} // namespace
230
231const Values &GetValues() {
232 static ::aos::Once<const Values> once(DoGetValues);
233 return *once.Get();
234}
235
236const Values &GetValuesForTeam(uint16_t team_number) {
237 static ::aos::Mutex mutex;
238 ::aos::MutexLocker locker(&mutex);
239
240 // IMPORTANT: This declaration has to stay after the mutex is locked to avoid
241 // race conditions.
242 static ::std::map<uint16_t, const Values *> values;
243
244 if (values.count(team_number) == 0) {
245 values[team_number] = DoGetValuesForTeam(team_number);
246#if __has_feature(address_sanitizer)
247 __lsan_ignore_object(values[team_number]);
248#endif
249 }
250 return *values[team_number];
251}
252
James Kuszmaul22c5ab32019-02-09 14:45:58 -0800253constexpr size_t Field::kNumTargets;
254constexpr size_t Field::kNumObstacles;
255
256Field::Field() {
257 // TODO(james): These values need to re-verified. I got them by skimming the
258 // manual and they all seem to be pretty much correct.
259 //
260 // Note: Per //frc971/control_loops/pose.h, coordinate system is:
261 // -In meters
262 // -Origin at center of our driver's station wall
263 // -Positive X-axis pointing straight out from driver's station
264 // -Positive Y-axis pointing straight left from the driver's perspective
265 // -Positive Z-axis is straight up.
266 // -The angle of the target is such that the angle is the angle you would
267 // need to be facing to see it straight-on. I.e., if the target angle is
268 // pi / 2.0, then you would be able to see it face on by facing straight
269 // left from the driver's point of view (if you were standing in the right
270 // spot).
271 constexpr double kCenterFieldX = FeetToMeters(27.0) + InchToMeters(1.125);
272
273 constexpr double kFarSideCargoBayX =
274 kCenterFieldX - InchToMeters(20.875);
275 constexpr double kMidSideCargoBayX = kFarSideCargoBayX - InchToMeters(21.75);
276 constexpr double kNearSideCargoBayX = kMidSideCargoBayX - InchToMeters(21.75);
277 constexpr double kSideCargoBayY = InchToMeters(24 + 3 + 0.875);
278 constexpr double kSideCargoBayTheta = -M_PI_2;
279
280 constexpr double kFaceCargoBayX =
281 kCenterFieldX - InchToMeters(7 * 12 + 11.75 + 9);
282 constexpr double kFaceCargoBayY = InchToMeters(10.875);
283 constexpr double kFaceCargoBayTheta = 0.0;
284
285 constexpr double kRocketX = kCenterFieldX - FeetToMeters(8);
286 constexpr double kRocketY = InchToMeters((26 * 12 + 10.5) / 2.0);
287
288 constexpr double kRocketPortX = kRocketX;
289 constexpr double kRocketPortY = kRocketY - 0.70;
290 constexpr double kRocketPortTheta = M_PI_2;
291
292 // Half of portal + guess at width * cos(61.5 deg)
293 const double kRocketHatchXOffset = InchToMeters(14.634);
294 const double kRocketHatchY = kRocketPortY + InchToMeters(9.326);
295 const double kRocketNearX = kRocketX - kRocketHatchXOffset;
296 const double kRocketFarX = kRocketX + kRocketHatchXOffset;
297 constexpr double kRocketNearTheta = DegToRad(28.5);
298 constexpr double kRocketFarTheta = M_PI - kRocketNearTheta;
299
300 constexpr double kHpSlotY = InchToMeters((26 * 12 + 10.5) / 2.0 - 25.9);
301 constexpr double kHpSlotTheta = M_PI;
302
303 constexpr double kNormalZ = 0.80;
304 constexpr double kPortZ = 0.99;
305
306 const Pose far_side_cargo_bay({kFarSideCargoBayX, kSideCargoBayY, kNormalZ},
307 kSideCargoBayTheta);
308 const Pose mid_side_cargo_bay({kMidSideCargoBayX, kSideCargoBayY, kNormalZ},
309 kSideCargoBayTheta);
310 const Pose near_side_cargo_bay({kNearSideCargoBayX, kSideCargoBayY, kNormalZ},
311 kSideCargoBayTheta);
312
313 const Pose face_cargo_bay({kFaceCargoBayX, kFaceCargoBayY, kNormalZ},
314 kFaceCargoBayTheta);
315
316 const Pose rocket_port({kRocketPortX, kRocketPortY, kPortZ},
317 kRocketPortTheta);
318
319 const Pose rocket_near({kRocketNearX, kRocketHatchY, kNormalZ},
320 kRocketNearTheta);
321 const Pose rocket_far({kRocketFarX, kRocketHatchY, kNormalZ},
322 kRocketFarTheta);
323
324 const Pose hp_slot({0.0, kHpSlotY, kNormalZ}, kHpSlotTheta);
325
326 const ::std::array<Pose, 8> quarter_field_targets{
327 {far_side_cargo_bay, mid_side_cargo_bay, near_side_cargo_bay,
328 face_cargo_bay, rocket_port, rocket_near, rocket_far, hp_slot}};
329
330 // Mirror across center field mid-line (short field axis):
331 ::std::array<Pose, 16> half_field_targets;
332 ::std::copy(quarter_field_targets.begin(), quarter_field_targets.end(),
333 half_field_targets.begin());
334 for (int ii = 0; ii < 8; ++ii) {
335 const int jj = ii + 8;
336 half_field_targets[jj] = quarter_field_targets[ii];
337 half_field_targets[jj].mutable_pos()->x() =
338 2.0 * kCenterFieldX - half_field_targets[jj].rel_pos().x();
339 half_field_targets[jj].set_theta(
340 aos::math::NormalizeAngle(M_PI - half_field_targets[jj].rel_theta()));
341 }
342
343 ::std::array<Pose, 32> target_poses_;
344
345 // Mirror across x-axis (long field axis):
346 ::std::copy(half_field_targets.begin(), half_field_targets.end(),
347 target_poses_.begin());
348 for (int ii = 0; ii < 16; ++ii) {
349 const int jj = ii + 16;
350 target_poses_[jj] = half_field_targets[ii];
351 target_poses_[jj].mutable_pos()->y() *= -1;
352 target_poses_[jj].set_theta(-target_poses_[jj].rel_theta());
353 }
354 for (int ii = 0; ii < 32; ++ii) {
355 targets_[ii] = {target_poses_[ii]};
356 }
357
358 // Define rocket obstacles as just being a single line that should block any
359 // cameras trying to see through the rocket up and down the field.
360 // This line is parallel to the driver's station wall and extends behind
361 // the portal.
362 Obstacle rocket_obstacle({{kRocketPortX, kRocketY, 0.0}, 0.0},
363 {{kRocketPortX, kRocketPortY + 0.01, 0.0}, 0.0});
364 // First, we mirror rocket obstacles across x-axis:
365 Obstacle rocket_obstacle2({{kRocketPortX, -kRocketY, 0.0}, 0.0},
366 {{kRocketPortX, -kRocketPortY - 0.01, 0.0}, 0.0});
367
368 // Define an obstacle for the Hab that extends striaght out a few feet from
369 // the driver's station wall.
370 // TODO(james): Does this actually block our view?
371 const double kHabL3X = FeetToMeters(4.0);
372 Obstacle hab_obstacle({}, {{kHabL3X, 0.0, 0.0}, 0.0});
373 ::std::array<Obstacle, 3> half_obstacles{
374 {rocket_obstacle, rocket_obstacle2, hab_obstacle}};
375 ::std::copy(half_obstacles.begin(), half_obstacles.end(), obstacles_.begin());
376
377 // Next, we mirror across the mid-line (short axis) to duplicate the
378 // rockets and hab to opposite side of the field.
379 for (int ii = 0; ii < 3; ++ii) {
380 const int jj = ii + 3;
381 obstacles_[jj] = half_obstacles[ii];
382 obstacles_[jj].mutable_pose1()->mutable_pos()->x() =
383 2.0 * kCenterFieldX - obstacles_[jj].mutable_pose1()->rel_pos().x();
384 obstacles_[jj].mutable_pose2()->mutable_pos()->x() =
385 2.0 * kCenterFieldX - obstacles_[jj].mutable_pose2()->rel_pos().x();
386 }
387
388 // Finally, define a rectangular cargo ship.
389 const double kCargoCornerX = kFaceCargoBayX + 0.1;
390 const double kCargoCornerY = kSideCargoBayY - 0.1;
391 ::std::array<Pose, 4> cargo_corners{
392 {{{kCargoCornerX, kCargoCornerY, 0.0}, 0.0},
393 {{kCargoCornerX, -kCargoCornerY, 0.0}, 0.0},
394 {{2.0 * kCenterFieldX - kCargoCornerX, -kCargoCornerY, 0.0}, 0.0},
395 {{2.0 * kCenterFieldX - kCargoCornerX, kCargoCornerY, 0.0}, 0.0}}};
396 for (int ii = 6; ii < 10; ++ii) {
397 obstacles_[ii] = Obstacle(cargo_corners[ii % cargo_corners.size()],
398 cargo_corners[(ii + 1) % cargo_corners.size()]);
399 }
400}
401
Tyler Chatow37ecdcd2019-01-26 20:18:42 -0800402} // namespace constants
403} // namespace y2019