Class: Roby::StateSpace

Inherits:
StateField show all
Defined in:
lib/roby/state/state_model.rb,
lib/roby/state/events.rb

Overview

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

Constant Summary

Constants inherited from OpenStruct

OpenStruct::FORBIDDEN_NAMES, OpenStruct::FORBIDDEN_NAMES_RX, OpenStruct::NOT_OVERRIDABLE, OpenStruct::NOT_OVERRIDABLE_RX

Instance Attribute Summary

Attributes inherited from StateField

#data_sources, #last_known, #model

Attributes inherited from OpenStruct

#__parent_name, #__parent_struct, #model

Instance Method Summary collapse

Methods inherited from StateField

#__get, #attach, #create_model, #install_type_checking_filter, #link_to, #method_missing, #read, #to_s

Methods inherited from OpenStruct

#__get, #__merge, #__parent, #__root, #__root?, _load, #alias, #alias?, #attach, #attach_child, #attach_model, #attach_to, #attached?, #clear, #clear_model, #create_model, #delete, #detached!, #each_member, #empty?, #filter, #freeze, #get, #global_filter, #has_method?, #link_to, #member?, #method_missing, #new_model, #on_change, #path, #pretty_print, #respond_to_missing?, #set, #stable!, #stable?, #to_hash, #update, #updated

Constructor Details

#initialize(model = nil) ⇒ StateSpace

Returns a new instance of StateSpace.



237
238
239
240
# File 'lib/roby/state/state_model.rb', line 237

def initialize(model = nil)
    @exported_fields = nil
    super(model)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Roby::StateField

Instance Method Details

#_dump(lvl = -1)) ⇒ Object

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.



287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/roby/state/state_model.rb', line 287

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

#at(options) ⇒ Object

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



95
96
97
98
99
100
# File 'lib/roby/state/events.rb', line 95

def at(options)
    options = validate_options options, t: nil
    if time = options[:t]
        trigger_when { Time.now >= time }
    end
end

#create_subfield(name) ⇒ Object



275
276
277
278
# File 'lib/roby/state/state_model.rb', line 275

def create_subfield(name)
    model = self.model&.get(name)
    StateField.new(model, self, name)
end

#deep_copyObject



300
301
302
303
304
305
# File 'lib/roby/state/state_model.rb', line 300

def deep_copy
    exported_fields, @exported_fields = @exported_fields, Set.new
    Marshal.load(Marshal.dump(self))
ensure
    @exported_fields = exported_fields
end

#export(*names) ⇒ Object

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



270
271
272
273
# File 'lib/roby/state/state_model.rb', line 270

def export(*names)
    @exported_fields ||= Set.new
    @exported_fields.merge names.map(&:to_s).to_set
end

#export_allObject

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



258
259
260
# File 'lib/roby/state/state_model.rb', line 258

def export_all
    @exported_fields = nil
end

#export_noneObject

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



248
249
250
# File 'lib/roby/state/state_model.rb', line 248

def export_none
    @exported_fields = Set.new
end

#on_delta(spec) ⇒ Object

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.



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
# File 'lib/roby/state/events.rb', line 25

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

#reset_when(event, state_name = nil, &block) ⇒ Object

Installs a condition at which the event should be reset



81
82
83
84
85
86
87
88
# File 'lib/roby/state/events.rb', line 81

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

#simulation?Boolean

Returns:

  • (Boolean)


311
312
313
# File 'lib/roby/state/state_model.rb', line 311

def simulation?
    Roby.app.simulation?
end

#testing?Boolean

Returns:

  • (Boolean)


307
308
309
# File 'lib/roby/state/state_model.rb', line 307

def testing?
    Roby.app.testing?
end

#trigger_when(*state_path, &block) ⇒ Object

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


71
72
73
74
75
76
77
78
# File 'lib/roby/state/events.rb', line 71

def trigger_when(*state_path, &block)
    unless block_given?
        raise ArgumentError, "#trigger_when expects a block"
    end

    state_path.map!(&:to_s)
    StateConditionEvent.new(self, state_path, block)
end