class Roby::StateSpace
Implementation of the state representation at runtime.
It gives access to three views to the state:
* the current values are directly accessible from this state object * the last known value is stored in last_known.path.to.value * the state model is stored in model.path.to.value * the current data source for a state variable is stored in data_sources.path.to.value
Public Class Methods
Roby::StateField::new
# File lib/roby/state/state_model.rb, line 230 def initialize(model = nil) @exported_fields = nil super(model) end
Public Instance Methods
Implementation of marshalling with Ruby's Marshal
Only the fields that can be marshalled will be saved. Any other field will silently be ignored.
Which fields get marshalled can be controlled with export_all
, export_none
and export
. The default is to marshal all fields.
# File lib/roby/state/state_model.rb, line 280 def _dump(lvl = -1) if !@exported_fields super else marshalled_members = @exported_fields.map do |name| value = @members[name] [name, Marshal.dump(value)] rescue nil end marshalled_members.compact! Marshal.dump([marshalled_members, @aliases]) end end
Returns an event which emits when the given state is reached. For now, the following state variables are available:
t
-
time as a Time object
See TimePointEvent
# File lib/roby/state/events.rb, line 90 def at(options) options = validate_options options, t: nil if time = options[:t] trigger_when { Time.now >= time } end end
# File lib/roby/state/state_model.rb, line 268 def create_subfield(name) model = if self.model then self.model.get(name) end StateField.new(model, self, name) end
# File lib/roby/state/state_model.rb, line 293 def deep_copy exported_fields, @exported_fields = @exported_fields, Set.new Marshal.load(Marshal.dump(self)) ensure @exported_fields = exported_fields end
Declares that only the given names should be marshalled, instead of marshalling every field. It is cumulative, i.e. if multiple calls to export
follow each other then the fields get added to the list of exported fields instead of replacing it.
If export_all
has been called, a call to export
cancels it.
See also export_none
and export_all
# File lib/roby/state/state_model.rb, line 263 def export(*names) @exported_fields ||= Set.new @exported_fields.merge names.map { |n| n.to_s }.to_set end
Declares that all the state fields should be marshalled. This is the default
It cancels any list of fields exported with export
See also export_none
and export
# File lib/roby/state/state_model.rb, line 251 def export_all @exported_fields = nil end
Declares that no state fields should be marshalled. The default is to export everything
It cancels any list of fields exported with export
See also export_all
and export
# File lib/roby/state/state_model.rb, line 241 def export_none @exported_fields = Set.new end
Create an event which will be emitted everytime some state parameters vary more than the given deltas. The following state parameters are available:
t
-
time in seconds
d
-
distance in meters
yaw
-
heading in radians
For instance:
Roby.state.on_delta d: 10, t: 20
will emit everytime the robot moves more than 10 meters AND more than 20 seconds have elapsed.
If more than once specification is given, the resulting event is combined with the & operator. This can be changed by setting the :or option to 'true'.
Roby.state.on_delta d: 10, t: 20, or: true
See DeltaEvent
and its subclasses.
# File lib/roby/state/events.rb, line 23 def on_delta(spec) or_aggregate = spec.delete(:or) events = spec.map do |name, value| unless klass = DeltaEvent.event_types[name] raise "unknown delta type #{name}. Known types are #{DeltaEvent.event_types.keys}" end ev = klass.new ev.threshold = value ev end if events.size > 1 result = if or_aggregate then OrGenerator.new else AndGenerator.new end result.on { |ev| result.reset } def result.or(spec); DeltaEvent.or(spec, self) end events.each { |ev| result << ev } result else events.first end end
Installs a condition at which the event should be reset
# File lib/roby/state/events.rb, line 76 def reset_when(event, state_name = nil, &block) reset_event = trigger_when(state_name, &block) reset_event.add_causal_link event reset_event.armed = !event.armed? event.on { |ev| reset_event.reset } reset_event.on { |ev| event.reset } reset_event end
# File lib/roby/state/state_model.rb, line 301 def simulation?; Roby.app.simulation? end
# File lib/roby/state/state_model.rb, line 300 def testing?; Roby.app.testing? end
Returns a state event that emits the first time the block returns true
The block is given the value of the specified state value state_name
. For instance, with
event = State.position.trigger_when(:x) do |value| value > 23 end
event
will be emitted once if the X value of the position gets greater than 23. One can also specify a reset condition with
State.position.reset_when(event, :x) do |value| value < 20 end
# File lib/roby/state/events.rb, line 66 def trigger_when(*state_path, &block) if !block_given? raise ArgumentError, "#trigger_when expects a block" end state_path.map!(&:to_s) StateConditionEvent.new(self, state_path, block) end