def create_subscriber(ctx: ContextWrapper): face_names = Ros2SubProperty( "face_names", topic=ctx.conf(key=ROS2_FACE_TOPIC_CONFIG), msg_type=RecognizedFaces, always_signal_changed=False) rec_faces = PropertyBase(name="rec_faces", default_value={}, always_signal_changed=False, allow_pop=True, allow_push=True) ctx.push(subscriber_parent.id(), face_names) ctx.push(subscriber_parent.id(), rec_faces) @state(read=(face_names.id(), rec_faces.id()), write=(rec_faces.id(), raw_out.id())) def react_to_recognized_face(ctx: ContextWrapper): nonlocal face_names faces: RecognizedFaces = ctx[face_names.id()] rec_faces_dict: Dict = ctx[rec_faces.id()] phrases: List = ["Hey, aren't you, {}?!", "How are you doing, {}?!", "How are you, {}?!", "Whats up, {}?!", "Nice to see you, {}?!", "Looking great today, {}!", "Hello, {}!", "Hi, {}!", "Greetings, {}!", "Howdy, {}!", "Hey, {}!", "Greetings to {} over here!", "Hi there, {}!", "Gruse gott, {}!"] best_name_and_confidence = "", 0 for name_and_confidence in zip(faces.names, faces.confidence): logger.info(str(name_and_confidence[0])) if name_and_confidence[1] > best_name_and_confidence[1]: best_name_and_confidence = name_and_confidence if best_name_and_confidence[1] >= ctx.conf(key=FACE_CONFIDENCE_THRESHOLD): if best_name_and_confidence[0] not in rec_faces_dict.keys() or \ datetime.timestamp(datetime.now()) - rec_faces_dict.get(best_name_and_confidence[0]) > 300: rec_faces_dict.update({best_name_and_confidence[0]: datetime.timestamp(datetime.now())}) ctx[raw_out.id()] = phrases[randint(0, len(phrases) - 1)].format(best_name_and_confidence[0]) ctx[rec_faces.id()] = rec_faces_dict mod.add(react_to_recognized_face) ctx.add_state(react_to_recognized_face)
def add_prop(self, *, prop: PropertyBase) -> None: """ Add a property to this context. An error message will be generated, if a property with the same name has already been added previously. * `prop`: The property object that should be added. """ if prop.id() in self._properties: logger.error(f"Attempt to add property {prop.id()} twice!") return with self._lock: # register property self._properties[prop.id()] = prop # register all of the property's signals for signal in prop.signals(): self._add_sig(signal)
def push(self, parentpath: str, child: PropertyBase): """ Add a child to a property. Note: Child must not yet have a parent or children of itself. Write-access to parent is needed. * `parentpath`: Path of the parent that should receive the new child. * `child`: Parent-less, child-less property object to add. **Returns:** True if the push was successful, False otherwise """ if child.parent_path: logger.error( f"State {self.st.name} attempted to push child property {child.name} to parent {parentpath}, but it already has parent {child.parent_path}!" ) return False if parentpath in self.properties: if self.properties[parentpath].push(child): self.properties[child.id()] = PropertyWrapper( prop=child, ctx=self.ctx, spike_parents=self.spike_parents, allow_read=self.properties[parentpath].allow_read, allow_write=self.properties[parentpath].allow_write) self.ctx.add_prop(prop=child) return True else: logger.error( f'State {self.st.name} attempted to add child-property {child.name} to non-accessible parent {parentpath}!' ) return False
def rm_prop(self, *, prop: PropertyBase) -> None: """ Remove a property from this context. Generates error message, if the property was not added with add_prop() to the context previously * `prop`: The property to remove.object """ if prop.id() not in self._properties: logger.error(f"Attempt to remove unknown property {prop.id()}!") return # remove property from context self._properties.pop(prop.id()) states_to_remove: Set[State] = set() with self._lock: # remove all of the property's signals for signal in prop.signals(): self._rm_sig(signal) # remove all states that depend upon property for st in self._activations_per_state: if prop.id() in st.read_props + st.write_props: states_to_remove.add(st) for st in states_to_remove: self.rm_state(st=st)
def push(self, child: PropertyBase): """ Add a child to the property or to children of the property * `child`: Parent-less, child-less property object to add. Name of the child must be unique among existing children of this property. **Returns:** True if the push was successful, False otherwise """ if not self.allow_write: logger.error( f"Unauthorized push access in property-wrapper {self.prop.id()}!" ) return False if self.prop.push(child): self.ctx.emit(self.prop.pushed_signal(), parents=self.spike_parents, wipe=False, payload=child.id()) return True return False
ROS2_FACE_TOPIC_CONFIG = "ros2-node" FACE_CONFIDENCE_THRESHOLD = "min-confidence" CONFIG = { ROS2_FACE_TOPIC_CONFIG: "/roboy/cognition/vision/visible_face_names", FACE_CONFIDENCE_THRESHOLD: 0.85 } with Module(name="stalker", config=CONFIG) as mod: # Create a dummy parent, under which we can push the actual recognized faces topic, # once a context with a configuration is available. subscriber_parent = PropertyBase(name="face_names_parent") @state(cond=startup(), write=subscriber_parent.id()) def create_subscriber(ctx: ContextWrapper): face_names = Ros2SubProperty( "face_names", topic=ctx.conf(key=ROS2_FACE_TOPIC_CONFIG), msg_type=RecognizedFaces, always_signal_changed=False) rec_faces = PropertyBase(name="rec_faces", default_value={}, always_signal_changed=False, allow_pop=True, allow_push=True) ctx.push(subscriber_parent.id(), face_names)
def test_property(under_test_read_only: PropertyWrapper, default_property_base: PropertyBase): assert (default_property_base.id() == f"{DEFAULT_MODULE_NAME}:{DEFAULT_PROPERTY_NAME}") assert (not default_property_base._lock.locked()) assert (default_property_base.read() == DEFAULT_PROPERTY_VALUE)