-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
leaf_system.h
2037 lines (1769 loc) · 91.2 KB
/
leaf_system.h
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
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#pragma once
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>
#include "drake/common/default_scalars.h"
#include "drake/common/drake_assert.h"
#include "drake/common/drake_copyable.h"
#include "drake/common/eigen_types.h"
#include "drake/common/unused.h"
#include "drake/common/value.h"
#include "drake/systems/framework/abstract_value_cloner.h"
#include "drake/systems/framework/abstract_values.h"
#include "drake/systems/framework/basic_vector.h"
#include "drake/systems/framework/continuous_state.h"
#include "drake/systems/framework/discrete_values.h"
#include "drake/systems/framework/leaf_context.h"
#include "drake/systems/framework/leaf_output_port.h"
#include "drake/systems/framework/model_values.h"
#include "drake/systems/framework/system.h"
#include "drake/systems/framework/system_constraint.h"
#include "drake/systems/framework/system_output.h"
#include "drake/systems/framework/system_scalar_converter.h"
#include "drake/systems/framework/value_producer.h"
namespace drake {
namespace systems {
/** A superclass template that extends System with some convenience utilities
that are not applicable to Diagrams.
@tparam_default_scalar */
template <typename T>
class LeafSystem : public System<T> {
public:
// LeafSystem objects are neither copyable nor moveable.
DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(LeafSystem)
~LeafSystem() override;
/** Shadows System<T>::AllocateContext to provide a more concrete return
type LeafContext<T>. */
std::unique_ptr<LeafContext<T>> AllocateContext() const;
// =========================================================================
// Implementations of System<T> methods.
#ifndef DRAKE_DOXYGEN_CXX
// The three methods below are hidden from doxygen, as described in
// documentation for their corresponding methods in System.
std::unique_ptr<EventCollection<PublishEvent<T>>>
AllocateForcedPublishEventCollection() const override;
std::unique_ptr<EventCollection<DiscreteUpdateEvent<T>>>
AllocateForcedDiscreteUpdateEventCollection() const override;
std::unique_ptr<EventCollection<UnrestrictedUpdateEvent<T>>>
AllocateForcedUnrestrictedUpdateEventCollection() const override;
#endif
std::unique_ptr<ContextBase> DoAllocateContext() const final;
// TODO(sherm/russt): Initialize the discrete state from the model vector
// pending resolution of #7058.
/** Default implementation: sets all continuous state to the model vector
given in DeclareContinuousState (or zero if no model vector was given) and
discrete states to zero. Overrides must not change the number of state
variables. */
void SetDefaultState(const Context<T>& context,
State<T>* state) const override;
/** Default implementation: sets all numeric parameters to the model vector
given to DeclareNumericParameter, or else if no model was provided sets
the numeric parameter to one. It sets all abstract parameters to the
model value given to DeclareAbstractParameter. Overrides must not change
the number of parameters. */
void SetDefaultParameters(const Context<T>& context,
Parameters<T>* parameters) const override;
std::unique_ptr<ContinuousState<T>> AllocateTimeDerivatives() const final;
std::unique_ptr<DiscreteValues<T>> AllocateDiscreteVariables() const final;
std::multimap<int, int> GetDirectFeedthroughs() const final;
protected:
// Promote so we don't need "this->" in defaults which show up in Doxygen.
using SystemBase::all_sources_ticket;
/** Default constructor that declares no inputs, outputs, state, parameters,
events, nor scalar-type conversion support (AutoDiff, etc.). To enable
AutoDiff support, use the SystemScalarConverter-based constructor. */
LeafSystem();
/** Constructor that declares no inputs, outputs, state, parameters, or
events, but allows subclasses to declare scalar-type conversion support
(AutoDiff, etc.).
The scalar-type conversion support will use @p converter.
To enable scalar-type conversion support, pass a `SystemTypeTag<S>{}`
where `S` must be the exact class of `this` being constructed.
See @ref system_scalar_conversion for detailed background and examples
related to scalar-type conversion support. */
explicit LeafSystem(SystemScalarConverter converter);
/** Provides a new instance of the leaf context for this system. Derived
leaf systems with custom derived leaf system contexts should override this
to provide a context of the appropriate type. The returned context should
be "empty"; invoked by AllocateContext(), the caller will take the
responsibility to initialize the core LeafContext data. The default
implementation provides a default-constructed `LeafContext<T>`. */
virtual std::unique_ptr<LeafContext<T>> DoMakeLeafContext() const;
/** Derived classes that impose restrictions on what resources are permitted
should check those restrictions by implementing this. For example, a
derived class might require a single input and single output. Note that
the supplied Context will be complete except that input and output
dependencies on peer and parent subcontexts will not yet have been set up,
so you may not consider them for validation.
The default implementation does nothing. */
virtual void DoValidateAllocatedLeafContext(
const LeafContext<T>& context) const {
unused(context);
}
// =========================================================================
// Implementations of System<T> methods.
T DoCalcWitnessValue(const Context<T>& context,
const WitnessFunction<T>& witness_func) const final;
void AddTriggeredWitnessFunctionToCompositeEventCollection(
Event<T>* event,
CompositeEventCollection<T>* events) const final;
/** Computes the next update time based on the configured periodic events, for
scalar types that are arithmetic, or aborts for scalar types that are not
arithmetic. Subclasses that require aperiodic events should override, but
be sure to invoke the parent class implementation at the start of the
override if you want periodic events to continue to be handled.
@post `time` is set to a value greater than or equal to
`context.get_time()` on return.
@warning If you override this method, think carefully before setting
`time` to `context.get_time()` on return, which can inadvertently
cause simulations of systems derived from %LeafSystem to loop
interminably. Such a loop will occur if, for example, the
event(s) does not modify the state. */
void DoCalcNextUpdateTime(const Context<T>& context,
CompositeEventCollection<T>* events,
T* time) const override;
/** Emits a graphviz fragment for this System. Leaf systems are visualized as
records. For instance, a leaf system with 2 inputs and 1 output is:
@verbatim
123456 [shape= record, label="name | {<u0> 0 |<y0> 0} | {<u1> 1 | }"];
@endverbatim
which looks like:
@verbatim
+------------+----+
| name | u0 | u1 |
| | y0 | |
+-------+----+----+
@endverbatim */
void GetGraphvizFragment(int max_depth,
std::stringstream* dot) const override;
void GetGraphvizInputPortToken(const InputPort<T>& port,
int max_depth,
std::stringstream *dot) const final;
void GetGraphvizOutputPortToken(const OutputPort<T>& port,
int max_depth,
std::stringstream *dot) const final;
// =========================================================================
// Allocation helper utilities.
/** Returns a copy of the state declared in the most recent
DeclareContinuousState() call, or else a zero-sized state if that method
has never been called. */
std::unique_ptr<ContinuousState<T>> AllocateContinuousState() const;
/** Returns a copy of the states declared in DeclareDiscreteState() calls. */
std::unique_ptr<DiscreteValues<T>> AllocateDiscreteState() const;
/** Returns a copy of the states declared in DeclareAbstractState() calls. */
std::unique_ptr<AbstractValues> AllocateAbstractState() const;
/** Returns a copy of the parameters declared in DeclareNumericParameter()
and DeclareAbstractParameter() calls. */
std::unique_ptr<Parameters<T>> AllocateParameters() const;
// =========================================================================
// New methods for subclasses to use
/** Declares a numeric parameter using the given @p model_vector.
LeafSystem's default implementation of SetDefaultParameters() will reset
parameters to their model vectors. If the @p model_vector declares any
VectorBase::GetElementBounds() constraints, they will be re-declared as
inequality constraints on this system (see
DeclareInequalityConstraint()). Returns the index of the new parameter. */
int DeclareNumericParameter(const BasicVector<T>& model_vector);
/** Extracts the numeric parameters of type U from the @p context at @p index.
Asserts if the context is not a LeafContext, or if it does not have a
vector-valued parameter of type U at @p index. */
template <template <typename> class U = BasicVector>
const U<T>& GetNumericParameter(const Context<T>& context, int index) const {
this->ValidateContext(context);
static_assert(std::is_base_of_v<BasicVector<T>, U<T>>,
"U must be a subclass of BasicVector.");
const auto& leaf_context =
dynamic_cast<const systems::LeafContext<T>&>(context);
const auto* const params =
dynamic_cast<const U<T>*>(&leaf_context.get_numeric_parameter(index));
DRAKE_ASSERT(params != nullptr);
return *params;
}
/** Extracts the numeric parameters of type U from the @p context at @p index.
Asserts if the context is not a LeafContext, or if it does not have a
vector-valued parameter of type U at @p index. */
template <template <typename> class U = BasicVector>
U<T>& GetMutableNumericParameter(Context<T>* context, int index) const {
this->ValidateContext(context);
static_assert(std::is_base_of_v<BasicVector<T>, U<T>>,
"U must be a subclass of BasicVector.");
auto* leaf_context = dynamic_cast<systems::LeafContext<T>*>(context);
DRAKE_ASSERT(leaf_context != nullptr);
auto* const params = dynamic_cast<U<T>*>(
&leaf_context->get_mutable_numeric_parameter(index));
DRAKE_ASSERT(params != nullptr);
return *params;
}
/** Declares an abstract parameter using the given @p model_value.
LeafSystem's default implementation of SetDefaultParameters() will reset
parameters to their model values. Returns the index of the new
parameter. */
int DeclareAbstractParameter(const AbstractValue& model_value);
// =========================================================================
/** @anchor declare_periodic_events
@name Declare periodic events
Methods in this group declare that this System has an event that
is triggered periodically. The first periodic trigger will occur at
t = `offset_sec`, and it will recur at every `period_sec` thereafter.
Several signatures are provided to allow for a general Event object to be
triggered or for simpler class member functions to be invoked instead.
Reaching a designated time causes a periodic event to be dispatched
to one of the three available types of event dispatcher: publish (read
only), discrete update, and unrestricted update.
@note If you want to handle timed events that are _not_ periodic
(timers, alarms, etc.), overload DoCalcNextUpdateTime() rather than using
the methods in this section.
Template arguments to these methods are inferred from the argument lists
and need not be specified explicitly.
@pre `period_sec` > 0 and `offset_sec` ≥ 0. */
//@{
/** Declares that a Publish event should occur periodically and that it should
invoke the given event handler method. The handler should be a class
member function (method) with this signature:
@code
EventStatus MySystem::MyPublish(const Context<T>&) const;
@endcode
where `MySystem` is a class derived from `LeafSystem<T>` and the method
name is arbitrary.
See @ref declare_periodic_events "Declare periodic events" for more
information.
@pre `this` must be dynamic_cast-able to MySystem.
@pre `publish` must not be null.
@see DeclarePeriodicDiscreteUpdateEvent()
@see DeclarePeriodicUnrestrictedUpdateEvent()
@see DeclarePeriodicEvent() */
template <class MySystem>
void DeclarePeriodicPublishEvent(
double period_sec, double offset_sec,
EventStatus (MySystem::*publish)(const Context<T>&) const) {
static_assert(std::is_base_of_v<LeafSystem<T>, MySystem>,
"Expected to be invoked from a LeafSystem-derived System.");
DRAKE_DEMAND(publish != nullptr);
DeclarePeriodicEvent(
period_sec, offset_sec,
PublishEvent<T>(TriggerType::kPeriodic, [publish](
const System<T>& system,
const Context<T>& context,
const PublishEvent<T>&) {
const auto& sys = dynamic_cast<const MySystem&>(system);
// TODO(sherm1) Forward the return status.
(sys.*publish)(context); // Ignore return status for now.
}));
}
/** This variant accepts a handler that is assumed to succeed rather than
one that returns an EventStatus result. The handler signature is:
@code
void MySystem::MyPublish(const Context<T>&) const;
@endcode
See the other signature for more information.
@exclude_from_pydrake_mkdoc{This overload is not bound.} */
template <class MySystem>
void DeclarePeriodicPublishEvent(double period_sec, double offset_sec,
void (MySystem::*publish)(const Context<T>&)
const) {
static_assert(std::is_base_of_v<LeafSystem<T>, MySystem>,
"Expected to be invoked from a LeafSystem-derived System.");
DRAKE_DEMAND(publish != nullptr);
DeclarePeriodicEvent(
period_sec, offset_sec,
PublishEvent<T>(
TriggerType::kPeriodic,
[publish](const System<T>& system,
const Context<T>& context,
const PublishEvent<T>&) {
const auto& sys = dynamic_cast<const MySystem&>(system);
(sys.*publish)(context);
// TODO(sherm1) return EventStatus::Succeeded()
}));
}
/** Declares that a DiscreteUpdate event should occur periodically and that it
should invoke the given event handler method. The handler should be a
class member function (method) with this signature:
@code
EventStatus MySystem::MyUpdate(const Context<T>&,
DiscreteValues<T>*) const;
@endcode
where `MySystem` is a class derived from `LeafSystem<T>` and the method
name is arbitrary.
See @ref declare_periodic_events "Declare periodic events" for more
information.
@pre `this` must be dynamic_cast-able to MySystem.
@pre `update` must not be null.
@see DeclarePeriodicPublishEvent()
@see DeclarePeriodicUnrestrictedUpdateEvent()
@see DeclarePeriodicEvent() */
template <class MySystem>
void DeclarePeriodicDiscreteUpdateEvent(
double period_sec, double offset_sec,
EventStatus (MySystem::*update)(const Context<T>&, DiscreteValues<T>*)
const) {
static_assert(std::is_base_of_v<LeafSystem<T>, MySystem>,
"Expected to be invoked from a LeafSystem-derived System.");
DRAKE_DEMAND(update != nullptr);
DeclarePeriodicEvent(
period_sec, offset_sec,
DiscreteUpdateEvent<T>(
TriggerType::kPeriodic,
[update](const System<T>& system,
const Context<T>& context,
const DiscreteUpdateEvent<T>&,
DiscreteValues<T>* xd) {
const auto& sys = dynamic_cast<const MySystem&>(system);
// TODO(sherm1) Forward the return status.
(sys.*update)(context, &*xd); // Ignore return status for now.
}));
}
/** This variant accepts a handler that is assumed to succeed rather than
one that returns an EventStatus result. The handler signature is:
@code
void MySystem::MyUpdate(const Context<T>&,
DiscreteValues<T>*) const;
@endcode
See the other signature for more information.
@exclude_from_pydrake_mkdoc{This overload is not bound.} */
template <class MySystem>
void DeclarePeriodicDiscreteUpdateEvent(
double period_sec, double offset_sec,
void (MySystem::*update)(const Context<T>&, DiscreteValues<T>*) const) {
static_assert(std::is_base_of_v<LeafSystem<T>, MySystem>,
"Expected to be invoked from a LeafSystem-derived System.");
DRAKE_DEMAND(update != nullptr);
DeclarePeriodicEvent(
period_sec, offset_sec,
DiscreteUpdateEvent<T>(
TriggerType::kPeriodic,
[update](const System<T>& system,
const Context<T>& context,
const DiscreteUpdateEvent<T>&,
DiscreteValues<T>* xd) {
const auto& sys = dynamic_cast<const MySystem&>(system);
(sys.*update)(context, &*xd);
// TODO(sherm1) return EventStatus::Succeeded()
}));
}
/** Declares that an UnrestrictedUpdate event should occur periodically and
that it should invoke the given event handler method. The handler should
be a class member function (method) with this signature:
@code
EventStatus MySystem::MyUpdate(const Context<T>&, State<T>*) const;
@endcode
where `MySystem` is a class derived from `LeafSystem<T>` and the method
name is arbitrary.
See @ref declare_periodic_events "Declare periodic events" for more
information.
@pre `this` must be dynamic_cast-able to MySystem.
@pre `update` must not be null.
@see DeclarePeriodicPublishEvent()
@see DeclarePeriodicDiscreteUpdateEvent()
@see DeclarePeriodicEvent() */
template <class MySystem>
void DeclarePeriodicUnrestrictedUpdateEvent(
double period_sec, double offset_sec,
EventStatus (MySystem::*update)(const Context<T>&, State<T>*) const) {
static_assert(std::is_base_of_v<LeafSystem<T>, MySystem>,
"Expected to be invoked from a LeafSystem-derived System.");
DRAKE_DEMAND(update != nullptr);
DeclarePeriodicEvent(
period_sec, offset_sec,
UnrestrictedUpdateEvent<T>(
TriggerType::kPeriodic,
[update](const System<T>& system,
const Context<T>& context,
const UnrestrictedUpdateEvent<T>&, State<T>* x) {
const auto& sys = dynamic_cast<const MySystem&>(system);
// TODO(sherm1) Forward the return status.
(sys.*update)(context, &*x); // Ignore return status for now.
}));
}
/** This variant accepts a handler that is assumed to succeed rather than
one that returns an EventStatus result. The handler signature is:
@code
void MySystem::MyUpdate(const Context<T>&, State<T>*) const;
@endcode
See the other signature for more information.
@exclude_from_pydrake_mkdoc{This overload is not bound.} */
template <class MySystem>
void DeclarePeriodicUnrestrictedUpdateEvent(
double period_sec, double offset_sec,
void (MySystem::*update)(const Context<T>&, State<T>*) const) {
static_assert(std::is_base_of_v<LeafSystem<T>, MySystem>,
"Expected to be invoked from a LeafSystem-derived System.");
DRAKE_DEMAND(update != nullptr);
DeclarePeriodicEvent(
period_sec, offset_sec,
UnrestrictedUpdateEvent<T>(
TriggerType::kPeriodic,
[update](const System<T>& system, const Context<T>& context,
const UnrestrictedUpdateEvent<T>&, State<T>* x) {
const auto& sys = dynamic_cast<const MySystem&>(system);
(sys.*update)(context, &*x);
// TODO(sherm1) return EventStatus::Succeeded()
}));
}
/** (Advanced) Declares that a particular Event object should be dispatched
periodically. This is the most general form for declaring periodic events
and most users should use one of the other methods in this group instead.
@see DeclarePeriodicPublishEvent()
@see DeclarePeriodicDiscreteUpdateEvent()
@see DeclarePeriodicUnrestrictedUpdateEvent()
See @ref declare_periodic_events "Declare periodic events" for more
information.
Depending on the type of `event`, when triggered it will be passed to
the Publish, DiscreteUpdate, or UnrestrictedUpdate event dispatcher. If
the `event` object contains a handler function, Drake's default
dispatchers will invoke that handler. If not, then no further action is
taken. Thus an `event` with no handler has no effect unless its dispatcher
has been overridden. We strongly recommend that you _do not_ override the
dispatcher and instead _do_ supply a handler.
The given `event` object is deep-copied (cloned), and the copy is stored
internally so you do not need to keep the object around after this call.
@pre `event`'s associated trigger type must be TriggerType::kUnknown or
already set to TriggerType::kPeriodic. */
template <typename EventType>
void DeclarePeriodicEvent(double period_sec, double offset_sec,
const EventType& event) {
DRAKE_DEMAND(event.get_trigger_type() == TriggerType::kUnknown ||
event.get_trigger_type() == TriggerType::kPeriodic);
PeriodicEventData periodic_data;
periodic_data.set_period_sec(period_sec);
periodic_data.set_offset_sec(offset_sec);
auto event_copy = event.Clone();
event_copy->set_trigger_type(TriggerType::kPeriodic);
periodic_events_.emplace_back(
std::make_pair(periodic_data, std::move(event_copy)));
}
/** (To be deprecated) Declares a periodic publish event that invokes the
Publish() dispatcher but does not provide a handler function. This does
guarantee that a Simulator step will end exactly at the publish time,
but otherwise has no effect unless the DoPublish() dispatcher has been
overloaded (not recommended). */
void DeclarePeriodicPublish(double period_sec, double offset_sec = 0);
/** (To be deprecated) Declares a periodic discrete update event that invokes
the DiscreteUpdate() dispatcher but does not provide a handler
function. This does guarantee that a Simulator step will end exactly at
the update time, but otherwise has no effect unless the
DoDiscreteUpdate() dispatcher has been overloaded (not recommended). */
void DeclarePeriodicDiscreteUpdate(double period_sec, double offset_sec = 0);
/** (To be deprecated) Declares a periodic unrestricted update event that
invokes the UnrestrictedUpdate() dispatcher but does not provide a handler
function. This does guarantee that a Simulator step will end exactly at
the update time, but otherwise has no effect unless the
DoUnrestrictedUpdate() dispatcher has been overloaded (not recommended). */
void DeclarePeriodicUnrestrictedUpdate(double period_sec,
double offset_sec = 0);
//@}
// =========================================================================
/** @anchor declare_per-step_events
@name Declare per-step events
These methods are used to declare events that are triggered whenever the
Drake Simulator advances the simulated trajectory. Note that each call to
Simulator::AdvanceTo() typically generates many trajectory-advancing
steps of varying time intervals; per-step events are triggered for each
of those steps.
Per-step events are useful for taking discrete action at every point of a
simulated trajectory (generally spaced irregularly in time) without
missing anything. For example, per-step events can be used to implement
a high-accuracy signal delay by maintaining a buffer of past signal
values, updated at each step. Because the steps are smaller in regions
of rapid change, the interpolated signal retains the accuracy provided
by the denser sampling. A periodic sampling would produce less-accurate
interpolations.
As with any Drake event trigger type, a per-step event is dispatched to
one of the three available types of event dispatcher: publish (read only),
discrete state update, and unrestricted state update. Several signatures
are provided below to allow for a general Event object to be triggered, or
simpler class member functions to be invoked instead.
Per-step events are issued as follows: First, the Simulator::Initialize()
method queries and records the set of declared per-step events. That set
does not change during a simulation. Any per-step publish events are
dispatched at the end of Initialize() to publish the initial value of the
trajectory. Then every AdvanceTo() internal step dispatches unrestricted
and discrete update events at the start of the step, and dispatches
publish events at the end of the step (that is, after time advances).
This means that a per-step event at fixed step size h behaves
identically to a periodic event of period h, offset 0.
Template arguments to these methods are inferred from the argument lists
and need not be specified explicitly. */
//@{
/** Declares that a Publish event should occur at initialization and at the
end of every trajectory-advancing step and that it should invoke the
given event handler method. The handler should be a class member function
(method) with this signature:
@code
EventStatus MySystem::MyPublish(const Context<T>&) const;
@endcode
where `MySystem` is a class derived from `LeafSystem<T>` and the method
name is arbitrary.
@warning These per-step publish events are independent of the Simulator's
optional "publish every time step" and "publish at initialization"
features. Generally if you are declaring per-step publish events yourself
you should turn off those Simulation options.
See @ref declare_per-step_events "Declare per-step events" for more
information.
@pre `this` must be dynamic_cast-able to MySystem.
@pre `publish` must not be null.
@see DeclarePerStepDiscreteUpdateEvent()
@see DeclarePerStepUnrestrictedUpdateEvent()
@see DeclarePerStepEvent()
@see Simulator::set_publish_at_initialization()
@see Simulator::set_publish_every_time_step() */
template <class MySystem>
void DeclarePerStepPublishEvent(
EventStatus (MySystem::*publish)(const Context<T>&) const) {
static_assert(std::is_base_of_v<LeafSystem<T>, MySystem>,
"Expected to be invoked from a LeafSystem-derived System.");
DRAKE_DEMAND(publish != nullptr);
DeclarePerStepEvent<PublishEvent<T>>(PublishEvent<T>(
TriggerType::kPerStep,
[publish](const System<T>& system, const Context<T>& context,
const PublishEvent<T>&) {
const auto& sys = dynamic_cast<const MySystem&>(system);
// TODO(sherm1) Forward the return status.
(sys.*publish)(context); // Ignore return status for now.
}));
}
/** Declares that a DiscreteUpdate event should occur at the start of every
trajectory-advancing step and that it should invoke the given event
handler method. The handler should be a class member function (method)
with this signature:
@code
EventStatus MySystem::MyUpdate(const Context<T>&,
DiscreteValues<T>*) const;
@endcode
where `MySystem` is a class derived from `LeafSystem<T>` and the method
name is arbitrary.
See @ref declare_per-step_events "Declare per-step events" for more
information.
@pre `this` must be dynamic_cast-able to MySystem.
@pre `update` must not be null.
@see DeclarePerStepPublishEvent()
@see DeclarePerStepUnrestrictedUpdateEvent()
@see DeclarePerStepEvent() */
template <class MySystem>
void DeclarePerStepDiscreteUpdateEvent(EventStatus (MySystem::*update)(
const Context<T>&, DiscreteValues<T>*) const) {
static_assert(std::is_base_of_v<LeafSystem<T>, MySystem>,
"Expected to be invoked from a LeafSystem-derived System.");
DRAKE_DEMAND(update != nullptr);
DeclarePerStepEvent(
DiscreteUpdateEvent<T>(
TriggerType::kPerStep,
[update](const System<T>& system, const Context<T>& context,
const DiscreteUpdateEvent<T>&, DiscreteValues<T>* xd) {
const auto& sys = dynamic_cast<const MySystem&>(system);
// TODO(sherm1) Forward the return status.
(sys.*update)(context, &*xd); // Ignore return status for now.
}));
}
/** Declares that an UnrestrictedUpdate event should occur at the start of
every trajectory-advancing step and that it should invoke the given
event handler method. The handler should be a class member function
(method) with this signature:
@code
EventStatus MySystem::MyUpdate(const Context<T>&,
State<T>*) const;
@endcode
where `MySystem` is a class derived from `LeafSystem<T>` and the method
name is arbitrary.
See @ref declare_per-step_events "Declare per-step events" for more
information.
@pre `this` must be dynamic_cast-able to MySystem.
@pre `update` must not be null.
@see DeclarePerStepPublishEvent()
@see DeclarePerStepDiscreteUpdateEvent()
@see DeclarePerStepEvent() */
template <class MySystem>
void DeclarePerStepUnrestrictedUpdateEvent(
EventStatus (MySystem::*update)(const Context<T>&, State<T>*) const) {
static_assert(std::is_base_of_v<LeafSystem<T>, MySystem>,
"Expected to be invoked from a LeafSystem-derived System.");
DRAKE_DEMAND(update != nullptr);
DeclarePerStepEvent(UnrestrictedUpdateEvent<T>(
TriggerType::kPerStep,
[update](const System<T>& system, const Context<T>& context,
const UnrestrictedUpdateEvent<T>&, State<T>* x) {
const auto& sys = dynamic_cast<const MySystem&>(system);
// TODO(sherm1) Forward the return status.
(sys.*update)(context, &*x); // Ignore return status for now.
}));
}
/** (Advanced) Declares that a particular Event object should be dispatched at
every trajectory-advancing step. Publish events are dispatched at
the end of initialization and at the end of each step. Discrete- and
unrestricted update events are dispatched at the start of each step.
This is the most general form for declaring per-step events and most users
should use one of the other methods in this group instead.
@see DeclarePerStepPublishEvent()
@see DeclarePerStepDiscreteUpdateEvent()
@see DeclarePerStepUnrestrictedUpdateEvent()
See @ref declare_per-step_events "Declare per-step events" for more
information.
Depending on the type of `event`, at each step it will be passed to
the Publish, DiscreteUpdate, or UnrestrictedUpdate event dispatcher. If
the `event` object contains a handler function, Drake's default
dispatchers will invoke that handler. If not, then no further action is
taken. Thus an `event` with no handler has no effect unless its dispatcher
has been overridden. We strongly recommend that you _do not_ override the
dispatcher and instead _do_ supply a handler.
The given `event` object is deep-copied (cloned), and the copy is stored
internally so you do not need to keep the object around after this call.
@pre `event`'s associated trigger type must be TriggerType::kUnknown or
already set to TriggerType::kPerStep. */
template <typename EventType>
void DeclarePerStepEvent(const EventType& event) {
DRAKE_DEMAND(event.get_trigger_type() == TriggerType::kUnknown ||
event.get_trigger_type() == TriggerType::kPerStep);
event.AddToComposite(TriggerType::kPerStep, &per_step_events_);
}
//@}
// =========================================================================
/** @anchor declare_initialization_events
@name Declare initialization events
These methods are used to declare events that occur when the Drake
Simulator::Initialize() method is invoked.
During Initialize(), initialization-triggered unrestricted update events
are dispatched first for the whole Diagram, then initialization-triggered
discrete update events are dispatched for the whole Diagram. No other
_update_ events occur during initialization. On the other hand, any
_publish_ events, including initialization-triggered, per-step,
and time-triggered publish events that trigger at the initial time, are
dispatched together during initialization.
Template arguments to these methods are inferred from the argument lists
and need not be specified explicitly. */
//@{
/** Declares that a Publish event should occur at initialization and that it
should invoke the given event handler method. The handler should be a
class member function (method) with this signature:
@code
EventStatus MySystem::MyPublish(const Context<T>&) const;
@endcode
where `MySystem` is a class derived from `LeafSystem<T>` and the method
name is arbitrary.
See @ref declare_initialization_events "Declare initialization events" for
more information.
@pre `this` must be dynamic_cast-able to MySystem.
@pre `publish` must not be null.
@see DeclareInitializationDiscreteUpdateEvent()
@see DeclareInitializationUnrestrictedUpdateEvent()
@see DeclareInitializationEvent() */
template <class MySystem>
void DeclareInitializationPublishEvent(
EventStatus(MySystem::*publish)(const Context<T>&) const) {
static_assert(std::is_base_of_v<LeafSystem<T>, MySystem>,
"Expected to be invoked from a LeafSystem-derived System.");
auto this_ptr = dynamic_cast<const MySystem*>(this);
DRAKE_DEMAND(this_ptr != nullptr);
DRAKE_DEMAND(publish != nullptr);
DeclareInitializationEvent<PublishEvent<T>>(PublishEvent<T>(
TriggerType::kInitialization,
[this_ptr, publish](const Context<T>& context,
const PublishEvent<T>&) {
// TODO(sherm1) Forward the return status.
(this_ptr->*publish)(context); // Ignore return status for now.
}));
}
/** Declares that a DiscreteUpdate event should occur at initialization
and that it should invoke the given event handler method. The handler
should be a class member function (method) with this signature:
@code
EventStatus MySystem::MyUpdate(const Context<T>&,
DiscreteValues<T>*) const;
@endcode
where `MySystem` is a class derived from `LeafSystem<T>` and the method
name is arbitrary.
See @ref declare_initialization_events "Declare initialization events" for
more information.
@pre `this` must be dynamic_cast-able to MySystem.
@pre `update` must not be null.
@see DeclareInitializationPublishEvent()
@see DeclareInitializationUnrestrictedUpdateEvent()
@see DeclareInitializationEvent() */
template <class MySystem>
void DeclareInitializationDiscreteUpdateEvent(
EventStatus(MySystem::*update)
(const Context<T>&, DiscreteValues<T>*) const) {
static_assert(std::is_base_of_v<LeafSystem<T>, MySystem>,
"Expected to be invoked from a LeafSystem-derived System.");
auto this_ptr = dynamic_cast<const MySystem*>(this);
DRAKE_DEMAND(this_ptr != nullptr);
DRAKE_DEMAND(update != nullptr);
DeclareInitializationEvent(DiscreteUpdateEvent<T>(
TriggerType::kInitialization,
[this_ptr, update](const Context<T>& context,
const DiscreteUpdateEvent<T>&,
DiscreteValues<T>* xd) {
// TODO(sherm1) Forward the return status.
(this_ptr->*update)(context,
&*xd); // Ignore return status for now.
}));
}
/** Declares that an UnrestrictedUpdate event should occur at initialization
and that it should invoke the given event handler method. The handler
should be a class member function (method) with this signature:
@code
EventStatus MySystem::MyUpdate(const Context<T>&,
State<T>*) const;
@endcode
where `MySystem` is a class derived from `LeafSystem<T>` and the method
name is arbitrary.
See @ref declare_initialization_events "Declare initialization events" for
more information.
@pre `this` must be dynamic_cast-able to MySystem.
@pre `update` must not be null.
@see DeclareInitializationPublishEvent()
@see DeclareInitializationDiscreteUpdateEvent()
@see DeclareInitializationEvent() */
template <class MySystem>
void DeclareInitializationUnrestrictedUpdateEvent(
EventStatus(MySystem::*update)
(const Context<T>&, State<T>*) const) {
static_assert(std::is_base_of_v<LeafSystem<T>, MySystem>,
"Expected to be invoked from a LeafSystem-derived System.");
auto this_ptr = dynamic_cast<const MySystem*>(this);
DRAKE_DEMAND(this_ptr != nullptr);
DRAKE_DEMAND(update != nullptr);
DeclareInitializationEvent(UnrestrictedUpdateEvent<T>(
TriggerType::kInitialization,
[this_ptr, update](const Context<T>& context,
const UnrestrictedUpdateEvent<T>&, State<T>* x) {
// TODO(sherm1) Forward the return status.
(this_ptr->*update)(context,
&*x); // Ignore return status for now.
}));
}
/** (Advanced) Declares that a particular Event object should be dispatched at
initialization. This is the most general form for declaring initialization
events and most users should use one of the other methods in this group
instead.
@see DeclareInitializationPublishEvent()
@see DeclareInitializationDiscreteUpdateEvent()
@see DeclareInitializationUnrestrictedUpdate()
See @ref declare_initialization_events "Declare initialization events" for
more information.
Depending on the type of `event`, on initialization it will be passed to
the Publish, DiscreteUpdate, or UnrestrictedUpdate event dispatcher. If
the `event` object contains a handler function, Drake's default
dispatchers will invoke that handler. If not, then no further action is
taken. Thus an `event` with no handler has no effect unless its dispatcher
has been overridden. We strongly recommend that you _do not_ override the
dispatcher and instead _do_ supply a handler.
The given `event` object is deep-copied (cloned), and the copy is stored
internally so you do not need to keep the object around after this call.
@pre `event`'s associated trigger type must be TriggerType::kUnknown or
already set to TriggerType::kInitialization. */
template <typename EventType>
void DeclareInitializationEvent(const EventType& event) {
DRAKE_DEMAND(event.get_trigger_type() == TriggerType::kUnknown ||
event.get_trigger_type() == TriggerType::kInitialization);
event.AddToComposite(TriggerType::kInitialization, &initialization_events_);
}
//@}
// =========================================================================
/** @anchor declare_forced_events
@name Declare forced events
Forced events are those that are triggered through invocation of
System::Publish(const Context&),
System::CalcDiscreteVariableUpdates(const Context&, DiscreteValues<T>*),
or System::CalcUnrestrictedUpdate(const Context&, State<T>*),
rather than as a response to some computation-related event (e.g.,
the beginning of a period of time was reached, a trajectory advancing
step was performed, etc.) One useful application of a forced publish:
a process receives a network message and wants to trigger message
emissions in various systems embedded within a Diagram in response.
Template arguments to these methods are inferred from the argument lists.
and need not be specified explicitly.
@note It's rare that an event needs to be triggered by force. Please
consider per-step and periodic triggered events first.
@warning Simulator handles forced publish events at initialization
and on a per-step basis when its "publish at initialization" and
"publish every time step" options are set.
@see Simulator::set_publish_at_initialization()
@see Simulator::set_publish_every_time_step() */
//@{
/** Declares a function that is called whenever a user directly calls
Publish(const Context&). Multiple calls to
DeclareForcedPublishEvent() will cause multiple handlers to be called
upon a call to Publish(); these handlers which will be called with the
same const Context in arbitrary order. The handler should be a class
member function (method) with this signature:
@code
EventStatus MySystem::MyPublish(const Context<T>&) const;
@endcode
where `MySystem` is a class derived from `LeafSystem<T>` and the method
name is arbitrary.
See @ref declare_forced_events "Declare forced events" for more
information.
@pre `this` must be dynamic_cast-able to MySystem.
@pre `publish` must not be null. */
template <class MySystem>
void DeclareForcedPublishEvent(
EventStatus (MySystem::*publish)(const Context<T>&) const) {
static_assert(std::is_base_of_v<LeafSystem<T>, MySystem>,
"Expected to be invoked from a LeafSystem-derived System.");
auto this_ptr = dynamic_cast<const MySystem*>(this);
DRAKE_DEMAND(this_ptr != nullptr);
DRAKE_DEMAND(publish != nullptr);
// Instantiate the event.
PublishEvent<T> forced(
TriggerType::kForced,
[this_ptr, publish](const Context<T>& context, const PublishEvent<T>&) {
// TODO(sherm1) Forward the return status.
(this_ptr->*publish)(context); // Ignore return status for now.
});
// Add the event to the collection of forced publish events.
this->get_mutable_forced_publish_events().AddEvent(std::move(forced));
}
/** Declares a function that is called whenever a user directly calls
CalcDiscreteVariableUpdates(const Context&, DiscreteValues<T>*). Multiple
calls to DeclareForcedDiscreteUpdateEvent() will cause multiple handlers
to be called upon a call to CalcDiscreteVariableUpdates(); these handlers
which will be called with the same const Context in arbitrary order. The
handler should be a class member function (method) with this signature:
@code
EventStatus MySystem::MyDiscreteVariableUpdates(const Context<T>&,
DiscreteValues<T>*);
@endcode
where `MySystem` is a class derived from `LeafSystem<T>` and the method
name is arbitrary.
See @ref declare_forced_events "Declare forced events" for more
information.
@pre `this` must be dynamic_cast-able to MySystem.
@pre `update` must not be null. */
template <class MySystem>
void DeclareForcedDiscreteUpdateEvent(EventStatus
(MySystem::*update)(const Context<T>&, DiscreteValues<T>*) const) {
static_assert(std::is_base_of_v<LeafSystem<T>, MySystem>,
"Expected to be invoked from a LeafSystem-derived System.");
auto this_ptr = dynamic_cast<const MySystem*>(this);
DRAKE_DEMAND(this_ptr != nullptr);
DRAKE_DEMAND(update != nullptr);
// Instantiate the event.
DiscreteUpdateEvent<T> forced(
TriggerType::kForced,
[this_ptr, update](const Context<T>& context,
const DiscreteUpdateEvent<T>&,
DiscreteValues<T>* discrete_state) {
// TODO(sherm1) Forward the return status.
(this_ptr->*update)(
context, discrete_state); // Ignore return status for now.
});
// Add the event to the collection of forced discrete update events.
this->get_mutable_forced_discrete_update_events().AddEvent(