ROS SMACH个人学习记录


本文仅为个人学习记录,结论正确性待考究。欢迎大家讨论

SMACH

关于抢占

抢占需要在并发容器里面实现,并发容器里面包含多个状态,我们分成两类:抢占状态与被抢占状态
抢占的实现原理:

  1. 定义子状态结束回调函数,该函数在并发容器里面的任何状态结束时候都会调用
def child_cb(outcome_map):
    rospy.loginfo('excute child call back')
    return True
  1. 在并发容器里面增加子状态结束回调函数调用(看最后一行)
sm_con = smach.Concurrence(outcomes=['outcome4','preempted'],
                                   default_outcome='outcome4',
                                   outcome_map={'preempted':{ 'FOO':'outcome1','BAR':'preempted'},
                                                'outcome4':{'BAR':'outcome2'}},
                                    child_termination_cb = child_cb)
  1. 在被抢占状态里定义抢占响应(excute后面四行)
# define state Bar
class Bar(smach.State):
    def __init__(self):
        smach.State.__init__(self, outcomes=['outcome2','preempted'])
    def execute(self, userdata):
        rospy.loginfo('Executing state BAR')
        if self.preempt_requested():
            self.service_preempt()
            return 'preempted'
        rospy.sleep(50)
        return 'outcome2'
  1. 在代码的后面增加handlerset_preempt_handler(你的状态机名)

全部代码:

#!/usr/bin/env python3

# 在并发状态机里面测试状态抢占功能

import rospy
import smach
import smach_ros
from smach_ros import ServiceState, SimpleActionState, IntrospectionServer,set_preempt_handler, MonitorState


# define state Foo
class Foo(smach.State):
    def __init__(self):
        smach.State.__init__(self, outcomes=['outcome1'])
        self.counter = 0

    def execute(self, userdata):
        rospy.loginfo('Executing state FOO')
        rospy.sleep(1)
        return 'outcome1'



# define state Bar
class Bar(smach.State):
    def __init__(self):
        smach.State.__init__(self, outcomes=['outcome2','preempted'])

    def execute(self, userdata):
        rospy.loginfo('Executing state BAR')
        if self.preempt_requested():
            self.service_preempt()
            return 'preempted'
        # n=1
        # while n<50:
        #     rospy.sleep(1)
        #     rospy.loginfo('Do something')
        #     n+=1
        # Check for preempt
        rospy.sleep(50)
        return 'outcome2'
        


# define state Bas
class Bas(smach.State):
    def __init__(self):
        smach.State.__init__(self, outcomes=['outcome3'])

    def execute(self, userdata):
        rospy.loginfo('Executing state BAS')
        return 'outcome3'


def child_cb(outcome_map):
    rospy.loginfo('excute child call back')
    return True


def main():
    rospy.init_node('smach_example_state_machine')

    # Create the top level SMACH state machine
    sm_top = smach.StateMachine(outcomes=['outcome6'])
    
    # Open the container
    with sm_top:

        smach.StateMachine.add('BAS', Bas(),
                               transitions={'outcome3':'CON'})

        # Create the sub SMACH state machine
        sm_con = smach.Concurrence(outcomes=['outcome4','preempted'],
                                   default_outcome='outcome4',
                                   outcome_map={'preempted':{ 'FOO':'outcome1','BAR':'preempted'},
                                                'outcome4':{'BAR':'outcome2'}},
                                    child_termination_cb = child_cb)

        # Open the container
        with sm_con:
            # Add states to the container
            smach.Concurrence.add('FOO', Foo())
            smach.Concurrence.add('BAR', Bar())

        smach.StateMachine.add('CON', sm_con,
                               transitions={'outcome4':'CON',
                                            'preempted':'outcome6'})
    # Create and start the introspection server
    sis = smach_ros.IntrospectionServer('server_name', sm_top, '/SM_ROOT')
    sis.start()

    # sm_top.request_preempt()
    set_preempt_handler(sm_top)
    outcome = sm_top.execute()

    # Wait for ctrl-c to stop the application
    rospy.spin()
    sis.stop()

if __name__ == '__main__':
    main()

该例子跑出来的效果:
能够完成Foo对Bar的抢占,不抢占的话会反复在CON和Bar状态里循环,但是Foo要等Bar执行完毕才去抢占。

一些Tips

  1. 状态切换太快node会死掉
  2. 各个容器可以不定义结果,但建议最好要定义结果(这里的结果表示为在SMACH viewer里面的红色块),子容器与父容器通过该结果联系。子容器可以结果通向父容器或者重新回到自己状态的开始,父容器不能通向到子容器里面(待验证)
  3. 子容器与父容器的连线结果等于子容器的红色块结果
  4. 并发容器里面嵌套状态机时,如果里面的状态机里面状态阻塞为得到红色快结果,Ctrl C会报错:Concurrent state ‘xxx’ returned no outcome on termination.
  5. 抢占在并发容器里面实现,状态1要抢占状态2必须要等到状态2执行完???(无action的情况下)
  6. Monitor提供消息与状态的交互(monitor call back return true时状态输出invalid,并结束monitor状态,否则monitor状态一直阻塞)
  7. 并发容器下只能并行执行多个单状态,如果需要在其中一个状态下再增加状态,需要打包。即对并发容器呈现出来只有多个单状态的并行。举个例子:

在这里插入图片描述
这样是不行的
必须把状态2和状态3打包成一个整体,打包在sm_sub1里面
在这里插入图片描述

  1. 待补充

SMACH缺点

  1. 基于Tips7带来的问题:并发容器里的子状态是嵌套的状态机时,如何定义抢占响应。对于各个状态我们可以在里面定义def excute,状态机咋搞?
  2. 基于Tips5似乎即便没有缺点1,该抢占也不是真正意义上的抢占???
  3. SMACH viewer node 经常动不动崩溃

个人的结论

层级数目超过教程例子的状态机就不建议参考使用SMACH,在确定要使用SMACH的情况下,建议在状态机设计时尽可能贴近SMACH教程的架构。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ROS深度强化学习是指将深度强化学习算法应用于ROS(机器人操作系统)平台上的任务中。在ROS中,可以使用不同的强化学习算法进行机器人的自主学习和决策。一些常见的强化学习算法包括DQN、DDPG、PPO和SAC。这些算法可以用于训练机器人在特定任务中进行决策,如避障、路径规划和目标导航等。 为了在ROS中进行深度强化学习,您需要做以下几个步骤: 1. 下载并安装ROS和相关依赖库,以及强化学习算法所需的库(如PyTorch、TensorFlow等)。 2. 创建ROS工作空间,并在其中安装相关软件包和代码。 3. 配置强化学习任务的参数和环境,例如定义机器人的传感器数据和动作空间。 4. 编写训练代码,包括强化学习算法的实现和机器人与环境的交互逻辑。 5. 运行训练代码,观察机器人在任务中的表现,不断优化算法和参数,直到获得满意的结果。 在使用ROS深度强化学习时,您可能需要修改一些代码和参数来适应特定的任务和机器人平台。例如,您可能需要更改路径代码以适应自己的路径,或者根据任务需求修改训练参数和环境配置文件。 至于启动代码的方式,可以使用终端命令"roslaunch"来启动训练节点和相关配置文件。例如,在终端中输入"roslaunch my_turtlebot2_training start_training.launch"即可启动训练过程。 对于每个训练任务,通常会有一个关联的配置文件,其中包含了该任务所需的参数。您可以在ROS包中创建一个名为"config"的文件夹,并在其中创建一个名为"my_turtlebot2_maze_params.yaml"的配置文件,用于指定任务的参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值