如何为机器人应用程序/嵌入式系统进行 python 转换 [英] How to python transitions for robotic applications / embedded systems

查看:27
本文介绍了如何为机器人应用程序/嵌入式系统进行 python 转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在考虑使用转换为机器人应用程序构建状态机.我以前曾将 simulink stateflow 用于此类任务.在这里,可以定期调用状态机并评估当前活动状态,以查看是否可以进行退出转换到新状态,否则保持当前状态(每次轮询可以进行一次转换).带着这种心态,我正在尝试一个带有过渡的初始玩具示例,看看我是否能掌握它,但我觉得我需要以不同的方式思考这个解决方案.

I'm looking at using transitions to build state machines for robotic applications. I've previously used simulink stateflow for this kind of task. Here, the state machine can be called periodically and the currently active state is evaluated in order to see if an exit transition can be made to a new state otherwise the current state is maintained (one transition can be made per poll). With this mindset I am attempting an initial toy example with transitions to see if I can get to grips with it but I get the feeling I need to think about this solution differently.

我想到的玩具示例是那些机场自动护照闸机之一,其中相机以 Z 轴平移以匹配用户的面部高度.这是我的(希望自我描述)尝试:

The toy example I thought of is one of those airport automatic passport gates, where the camera translates in Z to match the face height of the user. Here is my (hopefully self describing) attempt:

from transitions import Machine
from time import sleep, time
from random import choice

class Passport_cam_sm(object):

    def __init__(self):

        self.face_ok = False
        self.height_ok = False

states = ['move2face', 'validate_face', 'open_gate']

transitions = [
    {'trigger': 'at_face', 'source': 'move2face', 'dest': 'validate_face', 'conditions': 'height_ok'},
    {'trigger': 'face_valid', 'source': 'validate_face', 'dest': 'open_gate', 'conditions': 'face_valid'},
    {'trigger': 'face_invalid', 'source': 'validate_face', 'dest': 'move2face'},
]

class Passport_cam(object):

    def __init__(self, terminate_time_s=10, time_step_s=1):

        self.model = Passport_cam_sm()
        self.machine = Machine(model=self.model, states=states, transitions=transitions, initial='move2face', send_event=True)
        self.running = True
        self.init_time = time()
        self.terminate_time_s = terminate_time_s
        self.time_step_s = time_step_s
        self.face_pos_z = 5
        self.camera_pos_z = 0
        self.error_z = 888

    def run(self):
        '''
        main program loop
        :return: 
        '''

        while self.running and not self.main_timeout():

            self.machine.face_ok = self.face_ok()
            self.machine.height_ok = self.height_ok()
            print ('At state ' + self.model.state) #, ' camera height (', self.error_z ,') ok is ', self.machine.height_ok, ' face check is ', self.machine.face_ok)
            # todo - poll latest state here? (self.model.state)
            self.camera_dynamics()
            sleep(1)

    def face_ok(self):
        '''
        very robust method for determining if the face is valid...
        :return: 
        '''
        return choice([True, False])

    def height_ok(self, tol=0.5):
        '''
        Checks if the face height is OK to do comparison.
        :return: 
        '''
        if abs(self.error_z) < tol:
            return True
        else:
            return False

    def camera_dynamics(self, max_displacement=1):
        '''
        Moves camera height towards face height at a maximum of "max_displacement" per function call 
        :return: 
        '''
        self.error_z = self.camera_pos_z - self.face_pos_z
        threshold_error = (min(max(self.error_z, -max_displacement), max_displacement))
        self.camera_pos_z = self.camera_pos_z - threshold_error
        print ('Camera height error is: {0}'.format(self.error_z))

    def main_timeout(self):
        if time() > self.init_time + self.terminate_time_s:
            return True
        else:
            return False

pc = Passport_cam()
pc.run()

我期望找到的是在代码的待办事项"部分轮询最后一个状态的某种方式,以检查任何退出条件现在是否有效.有没有办法做到这一点?重新进入当前状态应该没问题,但我想某种期间"方法是理想的.

What I expected to find is some way of polling the last state at the 'todo' part in the code to check if any exit conditions are now valid. Is there a way to do this? Re-entering the current state should be OK but I guess some kind of "during" method would be ideal.

否则有没有更好的方法来构建此类项目和/或是否有类似的示例项目?

Otherwise is there a better way to structure this kind of project and/or are the any example projects like this?

推荐答案

欢迎使用 Stack Overflow.我建议宁可轮询"一个过渡,然后等到它成功进行.成功执行后,转换将返回 True,如果 a) 准备失败,b) 条件未满足或 c) 在进入状态或 d 过程中出现故障,则返回 False) 在处理 after 事件期间发生的问题.我缩小了您的示例代码的范围,以说明如何使用它来检查 faceheight 是否已成功检索:

Welcome to Stack Overflow. I'd suggest to rather 'poll' a transition and wait until it has been conducted successfully. A transition will return True when it has been conducted successfully and False if a) preparations failed, b) conditions were not met or c) something failed during entering the state or d)issues happening during the processing of after events. I narrowed down your example code to illustrate how this can be used to check whether face and height had been retrieved successfully:

from transitions import Machine
from time import sleep
from random import choice

class Passport_cam_sm(object):

    def __init__(self):
        self._face_okay = False
        self._height_okay = False

    def face_ok(self, even_data):
        self._face_okay = choice([True, False])
        return self._face_okay

    def height_ok(self, even_data):
        # tol = even_data.kwargs.pop('tol', 0.5)
        self._height_okay =  choice([True, False])
        return self._height_okay

states = ['move2face', 'validate_face', 'open_gate']

transitions = [
    {'trigger': 'at_face', 'source': 'move2face', 'dest': 'validate_face',
     'conditions': ['height_ok', 'face_ok']},
    {'trigger': 'face_valid', 'source': 'validate_face', 'dest': 'open_gate', 
     'conditions': 'face_valid'},
    {'trigger': 'face_invalid', 'source': 'validate_face', 'dest': 'move2face'},
]


class Passport_cam(object):

    def __init__(self):

        self.model = Passport_cam_sm()
        self.machine = Machine(model=self.model, states=states, transitions=transitions,
                               initial='move2face', send_event=True)
        self.running = True

    def run(self):
        while self.running:
            print('At state ' + self.model.state)
            # model.at_face will only return True when both conditions are met
            while not self.model.at_face():
                print('Checking ...') 
                sleep(1)
            print('Face and height are okay!')
            self.camera_dynamics()
            sleep(1)

    def camera_dynamics(self):
        print("Processing...")
        self.running = False


pc = Passport_cam()
pc.run()
print('Done')

我添加了两个检查 (face/height_ok) 作为有效过渡的条件.如果您想先分配它们并且只在 conditions 中检查它们的值,您可以使用 transitions 关键字 prepare.prepare 中的函数/方法将在 conditions 之前执行并且不需要布尔返回值.当您指定 send_event=True 时,所有回调都应该期待该事件.这就是 face/height_ok 需要上面使用的签名的原因.传递给触发事件的参数(例如 model.at_face(tol=0.5))将分配给 event_data.argsevent_data.kwargs.

I added both checks (face/height_ok) to be conditions for a valid transition. In case you want to assign them first and only check their values in conditions you could make use of the transitions keyword prepare. Functions/methods in prepare will be executed before conditions and do not require a boolean return value. When you specify send_event=True, all callbacks should expect that event. This is why face/height_ok require the signature used above. Arguments passed to the trigger event (e.g. model.at_face(tol=0.5)) will be assigned to event_data.args or event_data.kwargs.

请注意,我已将您的条件检查分配给模型.字符串总是被假定为模型方法的名称.如果您想从其他地方分配函数/方法,您可以传递对这些函数的引用而不是字符串.另请注意,这仅在立即处理事件时才有效.transitions 支持排队事件处理(将 queued=True 传递给 Machine 构造函数),这在事件可能触发其他事件时派上用场.当 queued=True 事件 ALWAYS 返回 true 时.

Note that I assigned your conditions check to the model. Strings are always assumed to be names of model methods. In case you want to assign functions/methods from somewhere else you can pass references to these functions instead of strings. Also note that this will only work when events are processed instantly. transitions supports queued event processing (passing queued=True to the Machine constructor) which comes in handy when events might trigger other events. When queued=True events will ALWAYS return true.

如何以不可知的方式进行投票?

状态机的一个核心特性是能够根据其当前状态调整其行为.同样的事件可能会导致不同的结果.如果您希望您的机器不断轮询而不是对事件做出反应,您可以定义由同一事件触发的所有转换:

A central feature of a state machine is the ability to adapt its behaviour based on its current state. The same event may result in different results. If you want your machine to constantly poll rather than react to events you can define all transitions to be triggered by the same event:

  transitions = [ 
      {'trigger': 'check', 'source': 'move2face', 'dest': 'validate_face',
     'conditions': ['height_ok', 'face_ok']},
      {'trigger': 'check', 'source': 'validate_face', 'dest': 'open_gate', 
     'conditions': 'face_valid'}, # (1)
      {'trigger': 'check', 'source': 'validate_face', 'dest': 'move2face'}, # (2)
  ]
  ...
  # class Passport_cam
  def run(self):
        while self.running:
            print('At state ' + self.model.state)
            while not self.model.check():
                sleep(1)

循环可以简化为只调用model.check.通过这种方式,可以在不需要更改轮询循环的情况下引入转换、检查和状态.

The loop can be simplified to just call model.check. This way transitions, checks and states can be introduced without the need to change the polling loop.

转换按添加顺序执行.这意味着 (1) 和 (2) 形成规则 In state 'validate_face' 如果 'face_valid' 则转到 'open_gate',否则转到 'move2face' .源状态与当前状态不同的转换不必检查,也不会导致太多开销.

Transitions are executed in the order they were added. This means that (1) and (2) form the rule In state 'validate_face' go to 'open_gate' if 'face_valid', otherwise go to 'move2face' . Transitions with a source state different from the current state do not have to be checked and do not result in much overhead.

最重要的是与框架无关的机器状态和转换的总体设计.如果条件检查变得臃肿,请考虑将状态拆分为更小的功能更具体的状态.您还可以拆分过渡配置和/或将您的模型组合成多个专用模型.

What matters the most is the general design of the machine's states and transitions which is framework independent. If condition checks get bloated, consider splitting states up into smaller functionally more specific states. You can also split transition configurations and/or compose your model out of several specialised models.

这篇关于如何为机器人应用程序/嵌入式系统进行 python 转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆