Skip to content

Science/trackPatch.tl

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
#   Copyright (c) 2024 MBARI
#   MBARI Proprietary Information. Confidential. All Rights Reserved
#   Unauthorized copying or distribution of this file via any medium is strictly
#   prohibited.
#
#   WARNING - This file contains information whose export is restricted by the
#   Export Administration Act of 1979 (Title 50, U.S.C., App. 2401 et seq.), as
#   amended. Violations of these export laws are subject to severe civil and/or
#   criminal penalties.

mission trackPatch {
  """
  Vehicle runs yo-yos, with patch detect enabled for cholorphyll
  concentration.
  """

  arguments {
    # Vehicle safety parameters

    MinAltitude = 5 meter
      """
      Minimum altitude for the entire mission.
      """

    MaxDepth = 65 meter
      """
      Maximum depth for the entire mission.
      """

    MinWaterDepth = 10 meter
      """
      Minimum water depth for the entire mission.
      """

    MinOffshore = 2000 meter
      """
      Minimum offshore distance for the entire mission.
      """

    NeedCommsTime = 180 minute
      """
      Maximum time between surfacings for communications
      """

    MissionTimeout = 56 hour
      """
      Timeout for the entire mission
      """

    MassDefault = Control:VerticalControl.massDefault
      """
      Static setting for mass during the mission. Defaults to massDefault
      setting in the Config/Control.cfg file.
      """

    BuoyancyNeutral = Control:VerticalControl.buoyancyNeutral
      """
      Buoyancy bladder position while performing the YoYo behavior. Defaults
      to buoyancyNeutral setting in the Config/Control.cfg file.
      """

    # Basic guidance settings

    YoYoMinDepth = 5.0 meter
      """
      Minimum depth during yo-yo's.
      """

    YoYoMaxDepth = 25.0 meter
      """
      Maximum depth during yo-yo's.
      """

    YoYoUpPitch = 20.0 degree
      """
      Pitch when yo-yo's are ascending.
      """

    YoYoDownPitch = -20.0 degree
      """
      Pitch when yo-yo's are descending.
      """

    Speed = 1 meter_per_second
      """
      Vehicle speed.
      """

    WpMaxDistance = 1000 meter
      """
      Maximum length of each tracking leg
      """

    WpTimeout = 8000 second
      """
      Maximum duration of each tracking leg
      """

    WaterFrame = true
      """
      Set WaterFrame true to drive towards waypoints in the water frame of
      reference
      """

    Repeat = 20 count
      """
      Maximum number of tracking legs
      """

    # Constant settings for each tracking leg

    Turn = 90 degree
      """
      Amount to turn at each leg
      """

    Reverse = 180 degree
      """
      Change in bearing which reverses vehicle direction
      """

    TwoPi = 360 degree
      """
      Applied to stop run-up of angles
      """

    TimeWindowPeakRpt = NaN minute
      """
      If greater than zero, report a peak every window. If NaN or zero, this
      variable is ignored.
      """

    # debug
    #       </Description><Units:minute/><Value>1</Value></DefineArg>

    LowPassWindowLen = 20 count
      """
      Low-pass window length (based on depth sensor sampling interval 0.4
      second) for low-pass filtering.
      """

    PeakChlShallowBnd = 10 meter
      """
      Shallow depth bound for detecting chl peak on each descent or ascent
      profile.
      """

    # debug
    #       </Description><Units:meter/><Value>3</Value></DefineArg>

    PeakChlDeepBnd = 20 meter
      """
      Deep depth bound for detecting chl peak on each descent or ascent
      profile.
      """

    # debug
    #       </Description><Units:meter/><Value>8</Value></DefineArg>

    NumOfProfilesSlidingwindow = 10 count
      """
      Length of horizontal sliding window. The highest yoyo-wise chl peak
      (after low-pass filtering by a filter of length FilterWidthHorizontal)
      within this window.
      """

    FilterWidth = 4 count
      """
      Width of boxcar filter used in horizontal patch detection
      """

    BeginThreshold = NaN microgram_per_liter
      """
      If non-NaN, sets threshold for starting horizontal patch detection
      """

    OffPeakFraction = 80 percent
      """
      When filtered horizontal value is this fraction of the peak, consider it
      outside the patch.
      """

    PatchMode = false
      """
      If true, use center of "in peak" range as the turn-around point. If
      false use maximum horizontal peak location as the turn-around point.
      """

    PatchTrackingHorizontal = true
      """
      Set true to turn on horizontal patch tracking
      """

    # Variable Settings for each tracking leg

    WpBearing = -90 degree
      """
      Bearing being followed in the current leg. Set this to initialize start
      direction of patch tracking.
      """
  }

  output {
    PatchDetectOn = false
      """
      Mission sets this to true when the patch has been crossed.
      """

    WpDone = false
      """
      Mission sets this to true when the cross-patch waypoint has been
      reached.
      """

    PatchChl = NaN microgram_per_liter

    PatchChlDepth = NaN meter

    PatchChlLatitude = NaN degree

    PatchChlLongitude = NaN degree

    PatchChlDistance = 0 meter
  }

  # The timeout

  timeout duration=MissionTimeout

  # And now the mission

  behavior Guidance:AltitudeEnvelope {
    run in parallel

    set minAltitude = MinAltitude
  }

  behavior Guidance:DepthEnvelope {
    run in parallel

    set maxDepth = MaxDepth
  }

  insert id="SurfaceCommsSplit" Insert/Surface.tl {
    redefineArg SurfacePitch = 20 degree
    redefineArg SurfaceSpeed = 1 meter_per_second
    redefineArg UnpackSplitAtSurface = true
  }

  aggregate SurfaceComms {
    run when ( called )

    insert Insert/Surface.tl {
      redefineArg SurfacePitch = 20 degree
      redefineArg SurfaceSpeed = 1 meter_per_second
    }
  }

  # GPS Update.  Don't go too long w/o a GPS fix.

  aggregate NeedComms {
    run when (
      Universal:platform_pitch_angle > 0 degree
      and ( elapsed ( Universal:time_fix ) > NeedCommsTime )
      or ( elapsed ( Universal:time_fix ) > ( NeedCommsTime + 10 minute ) )
    )

    syslog important "NeedComms Timeout Surfacing"

    call refId="SurfaceComms"
  }

  behavior Guidance:OffshoreEnvelope {
    run in parallel

    set minOffshore = MinOffshore
  }

  behavior Guidance:WaterDepthEnvelope {
    run in parallel

    set minWaterDepth = MinWaterDepth
  }

  behavior Guidance:Pitch {
    run in parallel

    set massPosition = MassDefault
  }

  behavior Guidance:Buoyancy {
    run in parallel

    set position = BuoyancyNeutral
  }

  # If we're executing here or below, lets' get science data!

  insert Insert/Science.tl {
    redefineArg PeakDetectChlActive = true
    redefineArg PatchTracking = true
    redefineArg TimeWindowPeakReport = TimeWindowPeakRpt
    redefineArg LowPassWindowLength = LowPassWindowLen
    redefineArg PeakShallowBound = PeakChlShallowBnd
    redefineArg PeakDeepBound = PeakChlDeepBnd
    redefineArg OffPeakFractionHorizontal = OffPeakFraction
  }

  behavior Guidance:SetSpeed {
    run in parallel

    set speed = Speed
  }

  behavior Guidance:DepthEnvelope {
    run in parallel

    set minDepth = YoYoMinDepth
    set maxDepth = YoYoMaxDepth
    set downPitch = YoYoDownPitch
    set upPitch = YoYoUpPitch
  }

  behavior Guidance:YoYo {
    run in parallel

    set downPitch = YoYoDownPitch
    set upPitch = YoYoUpPitch
  }

  aggregate PatchDetectHorizontal {
    run in sequence repeat=Repeat

    aggregate PatchDetection {
      run when ( PatchDetectOn )

      behavior Trigger:PeakDetectHorizontal id="PeakDetectHorizontalTrigger" {
        run in sequence

        break if ( WpDone )

        set patchTracking = PatchTrackingHorizontal
        set detectFrom = Science:PeakChl
        set depthFrom = Science:PeakChlDepth
        set latitudeFrom = Science:PeakChlLatitude
        set longitudeFrom = Science:PeakChlLongitude
        set beginThreshold = BeginThreshold
        set offPeakFraction = OffPeakFraction
        set filterWidth = FilterWidth
        set numProfilesSlidingwindow = NumOfProfilesSlidingwindow
        set centerPeak = PatchMode
        outputArg PatchChl = peakDetect
        outputArg PatchChlDepth = peakDepth
        outputArg PatchChlLatitude = peakLatitude
        outputArg PatchChlLongitude = peakLongitude
        outputArg PatchChlDistance = peakDistance
      }

      syslog important "Fell below OffPeakFraction. Patch value is " + PatchChl~microgram_per_liter
           + " at lat = " + PatchChlLatitude~degree + ", lon = " + PatchChlLongitude~degree + ", dep = "
           + PatchChlDepth~meter + ", distance = " + PatchChlDistance~meter

      sendData service=express (
        PatchChl,
        PatchChlDepth,
        PatchChlLatitude,
        PatchChlLongitude
      )

      assign id="AssignPatchDetectOff" in sequence PatchDetectOn = false
    }

    assign id="AssignPatchDetectOn" in sequence PatchDetectOn = true

    syslog important "Next: bearing for CrossLeg: " + WpBearing~degree + ". WpMaxDistance = "
         + WpMaxDistance~meter + ". Current lat, lon = " + Universal:latitude~degree + ", "
         + Universal:longitude~degree + "."

    aggregate CrossLeg {
      """
      This is a long leg across the width of the patch. Also the first
      leg in a mission run. Two waypoints run in parallel: a short run
      to the surfacing point, and a longer run to the edge of the
      patch.
      """

      run in sequence

      break if (
        WpDone
        or ( PatchDetectOn == false )
      )

      behavior Guidance:Waypoint id="CrossSurfaceWp" {
        run in sequence

        timeout duration=WpTimeout

        set distanceDelta = PatchChlDistance
        set distanceDeltaBearing = WpBearing
        set waterFrame = WaterFrame
      }

      call refId="SurfaceComms"

      behavior Guidance:Waypoint id="CrossPeakWp" {
        run in sequence

        timeout duration=WpTimeout

        set distanceDelta = WpMaxDistance
        set distanceDeltaBearing = WpBearing
        set waterFrame = WaterFrame
      }

      syslog important "CrossPeakWp done. Lat, lon = " + Universal:latitude~degree + ", "
           + Universal:longitude~degree + ". Patch value is " + PatchChl~microgram_per_liter + " at lat = "
           + PatchChlLatitude~degree + ", lon = " + PatchChlLongitude~degree + ", dep = "
           + PatchChlDepth~meter + ", distance = " + PatchChlDistance~meter

      assign id="AssignPatchDetectOffInCrossLeg" in sequence PatchDetectOn = false

      assign id="AssignWpDoneInCrossLeg" in sequence WpDone = true
    }

    assign id="AssignWpBearingForInLeg" in sequence WpBearing = ( WpBearing + Reverse ) % TwoPi

    syslog important "Next: bearing for InLeg: " + WpBearing~degree + ". Current lat, lon = "
         + Universal:latitude~degree + ", " + Universal:longitude~degree + ". Patch value is "
         + PatchChl~microgram_per_liter + " at lat = " + PatchChlLatitude~degree + ", lon = "
         + PatchChlLongitude~degree + ", dep = " + PatchChlDepth~meter + ", distance = "
         + PatchChlDistance~meter

    behavior Guidance:Waypoint id="InLegWp" {
      """
      Simply drive back towards the patch center
      """

      run in sequence

      timeout duration=WpTimeout

      set distanceDelta = PatchChlDistance
      set distanceDeltaBearing = WpBearing
      set waterFrame = WaterFrame
    }

    assign id="AssignWpBearingForOutLeg" in sequence WpBearing = ( WpBearing - Turn ) % TwoPi

    syslog important "Next: bearing for OutLeg: " + WpBearing~degree + ". WpMaxDistance = "
         + WpMaxDistance~meter + ". Current lat, lon = " + Universal:latitude~degree + ", "
         + Universal:longitude~degree + ". Patch value is " + PatchChl~microgram_per_liter + " at lat = "
         + PatchChlLatitude~degree + ", lon = " + PatchChlLongitude~degree + ", dep = "
         + PatchChlDepth~meter + ", distance = " + PatchChlDistance~meter

    call refId="SurfaceCommsSplit"

    assign id="AssignPatchDetectOnForOutLeg" in sequence PatchDetectOn = true

    aggregate OutLeg {
      """
      Drive outward until edge of patch is detected.
      """

      run in sequence

      break if (
        WpDone
        or ( PatchDetectOn == false )
      )

      behavior Guidance:Waypoint id="OutLegWp" {
        run in sequence

        timeout duration=WpTimeout

        set distanceDelta = WpMaxDistance
        set distanceDeltaBearing = WpBearing
        set waterFrame = WaterFrame
      }

      assign id="AssignPatchDetectOffInOutLeg" in sequence PatchDetectOn = false

      assign id="AssignWpDoneInOutLeg" in sequence WpDone = true
    }

    assign id="AssignWpBearingForCrossLeg" in sequence WpBearing = ( WpBearing + Reverse ) % TwoPi
  }
}