博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
大剧院自助签证_如果您的项目是《剧院》,请使用演员
阅读量:2517 次
发布时间:2019-05-11

本文共 26797 字,大约阅读时间需要 89 分钟。

大剧院自助签证

There is a story about an experience of using Actor Model in one interesting project of developing an automatic control system for a theatre. Below I'll tell my impressions, no more than that.

有一个故事讲述了在一个有趣的为剧院开发自动控制系统的项目中使用Actor Model的经历。 下面我将告诉我的印象,仅此而已。

Not so much time ago I participated in one exciting task: modernization of automatic control system (ACS) for batten hoists, but in fact it was a development of a new ACS.

不久前,我参加了一项激动人心的任务:板岩葫芦自动控制系统(ACS)的现代化,但实际上这是新ACS的发展。

A modern theatre (especially if it is a big one) is a very complex organization. There are many people, various mechanisms and systems. One of such systems is ACS for the handling of lifting and setting down the scenery. Modern performances, like operas and ballets, use more and more technical means year over year. The scenery is actively used by show's directors and even play its own important role. It was fascinating to discover what's happening behind the curtains because ordinary spectators can view only actions on the scene.

现代化的剧院(尤其是大型剧院)是一个非常复杂的组织。 有很多人,各种各样的机制和系统。 这样的系统之一是用于处理风景的升降的ACS。 现代表演,如歌剧和芭蕾舞剧,一年比一年使用越来越多的技术手段。 秀场导演积极利用风景,甚至发挥自己的重要作用。 发现幕后发生的一切真是令人着迷,因为普通观众只能看到现场的动作。

But this is a technical article, and I want to share my experience of using the Actor Model for writing a control system. And share my impressions of using one of the actor frameworks for C++: .

但这是一篇技术文章,我想分享一下我使用Actor模型编写控制系统的经验。 并分享我对使用C ++的框架之一的印象: 。

Why did we choose this framework? We have been looking at it for a long time. There are plenty of articles in Russian, and it has wonderful documentation and a lot of examples. The project looks like a mature one. A brief look at examples has shown that SObjectizer's developers use the same terms (states, timers, events, etc.) and we didn't expect big problems studying and using it. And yet another important factor: SObjectizer's team is helpful and always ready to help us. So we decided to try.

我们为什么选择这个框架? 我们已经研究了很长时间。 俄语中有很多文章,并且其中包含出色的文档和大量示例。 该项目看起来很成熟。 简要查看示例可以发现,SObjectizer的开发人员使用相同的术语(状态,计时器,事件等),并且我们并不期望研究和使用它会遇到大麻烦。 还有另一个重要因素:SObjectizer的团队很有帮助,随时准备为我们提供帮助。 因此,我们决定尝试。

我们在做什么? (What we're doing?)

Let's talk about the target of our project. The system of batten hoists has 62 battens (metal tubes). Each batten is as long as the whole stage. They are suspended on ropes in parallel with gaps of 30-40cm, starting from the front edge of the stage. Every batten can be raised or lowered. Some of them are used in a show for scenery. The scenery is fixed on batten and is moved up/down during the performance. The commands from operators initiate the movement. A system of "engine-rope-counterbalance" is similar to one used in elevators in residential buildings. Engines are placed outside of the stage, so the spectators don't see them. All engines are divided into 8 groups, and each group has 3 frequency converters (FC). At most three engines can be used at the same time in a group, each of them is connected to a separate FC. So we have a system of 62 engines and 24 FCs, and we have to control this system.

让我们谈谈我们项目的目标。 板条葫芦系统有62个板条(金属管)。 每个板条长达整个阶段。 从舞台的前边缘开始,它们以30-40cm的间隙平行悬挂在绳索上。 每个板条都可以升高或降低。 其中一些用于风景秀。 风景固定在板条上,并在演出中上下移动。 来自操作员的命令启动运动。 一种“引擎-绳索-平衡重”系统类似于在住宅建筑物的电梯中使用的系统。 引擎被放置在舞台之外,因此观众看不到它们。 所有引擎分为8组,每组具有3个变频器(FC)。 一组中最多可以同时使用三个引擎,每个引擎都连接到一个单独的FC。 因此,我们有一个包含62个引擎和24个FC的系统,我们必须控制该系统。

Our task was to develop a human-machine interface (HMI) for controlling this system and to implement control algorithms. The system includes three control stations. Two of them are placed just above the stage, and one is in the engine room (this station is used by an electrician on duty). There are also control blocks with controllers in the engine room. These controllers perform control commands, do pulse-width modulation (PWM), turn engines on or off, control the position of battens. Two control stations above the stage have displays, system units, and trackballs as pointing devices. The control stations are connected via Ethernet. Every control station is connected with control blocks by RS485 channel. Both stations above the stage can be used to control the system at the same time, but only one station can be active. The active station is selected by an operator; the second station will be passive; the passive station has its RS485 channel disabled.

我们的任务是开发用于控制该系统的人机界面(HMI)并实现控制算法。 该系统包括三个控制站。 其中两个放置在舞台的正上方,一个放置在机舱内(值班电工使用此站)。 机舱中还有带有控制器的控制块。 这些控制器执行控制命令,执行脉宽调制(PWM),打开或关闭引擎,控制板条的位置。 舞台上方的两个控制站具有显示器,系统单元和轨迹球作为指示设备。 控制站通过以太网连接。 每个控制站都通过RS485通道与控制块相连。 舞台上方的两个站都可用于同时控制系统,但是只能激活一个站。 活动电台由操作员选择; 第二站将是被动的; 无源站的RS485通道已禁用。

为什么是演员? (Why Actors?)

From the algorithms' point of view, the system is built on top of events. Data from sensors, operator's actions, expiration of timers… These all are examples of events. The Actor Model works well for such algorithms: actors handle incoming events and form some outgoing actions depending on their current state. These mechanics are available in SObjectizer just out of the box.

从算法的角度来看,该系统建立在事件之上。 来自传感器的数据,操作员的动作,计时器到期……这些都是事件的示例。 Actor模型适用于此类算法:Actor处理传入事件并根据其当前状态形成一些传出动作。 这些机制可以直接在SObjectizer中使用。

The basic principles for such systems are: actors interact via asynchronous messages, actors have states and switch from one state to another, only messages which are meaningful for the current state are handled.

这种系统的基本原理是:参与者通过异步消息进行交互,参与者具有状态并从一种状态切换到另一种状态,仅处理对于当前状态有意义的消息。

It's interesting that actors are decoupled from worker threads in SObjectizer. It means that you can implement and debug your actors first and only then decide what worker thread will be used for every actor. There are "Dispatchers" that implement various thread-related policies. For example, there is a dispatcher that provides a separate worker thread for each actor; there is a thread-pool dispatcher that provides a fixed-size pool of worker threads; there is a dispatcher that runs all actors on the same thread.

有趣的是,参与者在SObjectizer中与工作线程脱钩了。 这意味着您可以先实现和调试actor,然后再决定将哪个工作线程用于每个actor。 有些“调度程序”实现了各种与线程相关的策略。 例如,有一个调度程序为每个参与者提供一个单独的工作线程。 有一个线程池分派器,它提供固定大小的工作线程池; 有一个调度程序,它在同一线程上运行所有参与者。

The presence of dispatchers provides a very flexible way of tuning an actor system for our needs. We can group some actors to work on the same context. We can change the type of dispatcher by just a single line of code. SObjectizer's developers say that writing a custom dispatcher is not a complex task. But there was no need to write our own dispatcher in this project; everything we needed was found in SObjectizer.

调度程序的存在提供了一种非常灵活的方式来调整参与者系统以满足我们的需求。 我们可以将一些参与者分组以在相同的上下文中工作。 我们只需一行代码即可更改调度程序的类型。 SObjectizer的开发人员说,编写自定义调度程序并不复杂。 但是没有必要在这个项目中编写我们自己的调度程序。 我们所需的一切都在SObjectizer中找到。

Yet another interesting feature is cooperations of actors. A cooperation is a group of actors that can exist if and only if all actors have started successfully. Cooperation cannot be started if at least one of its actors has failed to start. It seems that there is an analogy between SObjectizer's cooperations and pods from Kubernetes, but it also seems that SObjectizer's cooperations have appeared earlier...

另一个有趣的特征是演员的合作。 合作是一组参与者,当且仅当所有参与者都已成功启动时,该参与者才能存在。 如果至少有一个参与者未能开始合作,则无法开始合作。 似乎SObjectizer的合作与Kubernetes的Pod之间有一个类比,但似乎SObjectizer的合作早已出现...

When an actor is created it is added to cooperation (cooperation can contain just one actor) and is bound to some dispatcher. It is easy to create cooperations and actors dynamically and SObjectizer's developers say that it is a rather cheap operation.

创建参与者后,它会添加到合作中(合作只能包含一个参与者)并绑定到某些调度程序。 动态创建合作关系和参与者很容易,SObjectizer的开发人员说这是一个相当便宜的操作。

All actors interact with each other via "message boxes" (mbox). It is yet another interesting and powerful SObjectizer's concept. It provides a flexible way of message processing.

所有演员都通过“消息框”(mbox)进行交互。 这是另一个有趣且功能强大的SObjectizer的概念。 它提供了一种灵活的消息处理方式。

At first, there can be more than one message receiver behind a mbox. It's quite helpful. For example, there can be a mbox that is used by sensors for publishing new data. Actors can create subscriptions for that mbox, and subscribed actors will receive the data they want. This allows working in a "Publish/Subscribe" fashion.

首先,一个mbox后面可以有多个消息接收者。 这很有帮助。 例如,可能有一个mbox供传感器用来发布新数据。 Actor可以为该mbox创建订阅,并且订阅的actor将收到他们想要的数据。 这允许以“发布/订阅”方式工作。

At second, the SObjectizer's developers have envisaged the possibility of custom mbox creation. It is relatively easy to create a custom mbox with special processing of incoming messages (like filtering or spreading between several subscribers based on the message's content).

第二,SObjectizer的开发人员已经设想了创建自定义mbox的可能性。 创建具有特殊处理传入消息的自定义mbox相对容易(例如,基于消息的内容在多个订户之间进行过滤或传播)。

There is also a personal mbox for every actor and actors can pass a reference to that mbox in messages to other actors (that allows to reply directly to a specific actor).

每个演员都有一个个人mbox,演员可以在对其他演员的消息中传递对该mbox的引用(允许直接回复特定演员)。

In our project we split all controlled objects into eight groups (one group for every control box). Three worker threads were created for every group (it is because of only three engines can work at the same time). It allowed us to have independence between groups of engines. It also allowed to work asynchronously with engines inside each group.

在我们的项目中,我们将所有受控对象分为八组(每个控制盒一组)。 每个组都创建了三个工作线程(这是因为只有三个引擎可以同时工作)。 它使我们在引擎组之间具有独立性。 它还允许与每个组内的引擎异步工作。

It is necessary to mention that SObjectizer-5 has no mechanisms for interprocess or/and network interaction. This is a conscious decision of SObjectizer's developers; they wanted to make SObjectizer as lightweight as possible. Moreover, the transparent support for networking had existed in some previous versions of SObjectizer but was removed. It didn't bother us because a mechanism for the networking is highly dependent on a task, protocols used and other conditions. There is no single universal solution for all cases.

必须提及的是,SObjectizer-5没有用于进程间或/和/或网络交互的机制。 这是SObjectizer开发人员的有意识决定。 他们希望使SObjectizer尽可能轻巧。 而且,对网络的透明支持在SObjectizer的某些早期版本中已经存在,但已被删除。 它并没有打扰我们,因为网络的机制高度依赖于任务,使用的协议和其他条件。 没有针对所有情况的单一通用解决方案。

In our case, we used our old library for network- and interprocess communications. As a result, libuniset2 supports communications with sensors and control blocks, and SObjectizer supports actors and interactions between actors inside a single process.

在本例中,我们使用旧的库进行网络和进程间通信。 结果,libuniset2支持与传感器和控制块的通信,而SObjectizer支持参与者和单个流程中参与者之间的交互。

As I said earlier there are 62 engines. Every engine can be connected to a FC (frequency converter); a destination coordinate can be specified for the corresponding batten; the speed of the batten's movement can also be specified. And as an addition to that, every engine has the following states:

正如我之前说的,有62个引擎。 每个引擎都可以连接到FC(变频器)。 可以为相应的板条指定目标坐标; 也可以指定条板运动的速度。 除此之外,每个引擎都具有以下状态:

  • ready to work;

    准备好工作了;
  • connected;

    连接的;
  • working;

    加工;
  • malfunction;

    故障;
  • connecting (a transition state);

    连接(过渡状态);
  • disconnecting (a transition state);

    断开连接(过渡状态);

Each engine is represented in the system by an actor that implements transition between states, handling data from sensors and issuing commands. It's not hard to create an actor in SObjectizer: just inherit your class from so_5::agent_t type. The first argument of actor's constructor should be of type context_t, all other arguments can be defined as a developer wants.

系统中的每个引擎都由一个参与者来表示,该参与者实现状态之间的转换,处理来自传感器的数据并发出命令。 在SObjectizer中创建actor并不难:只需从so_5::agent_t类型继承您的类。 actor的构造函数的第一个参数应为context_t类型,所有其他参数都可以根据开发人员的需要进行定义。

class Drive_A:    public so_5::agent_t{    public:       Drive_A( context_t ctx, ... );...}

I won't show the detailed description of classes and methods because it's not a tutorial. I just want to show how easy it all can be done in SObjectizer (in a few lines literally). Let me remind you that SObjectizer has excellent and many examples.

我不会显示类和方法的详细说明,因为它不是教程。 我只想显示在SObjectizer中完成所有操作的难易程度(从字面上看几行)。 让我提醒您,SObjectizer具有出色的和许多示例。

演员的“状态”是什么? 我们在说啥啊? (What is the "state" of an actor? What are we talking about?)

Usage of states and transition between them is a "native topic" for control systems. This concept it very good for event handling. This concept is supported in SObjectizer at the API level. States are declared inside the actor's class:

状态的使用和状态之间的转换是控制系统的“本地主题”。 这个概念对于事件处理非常有用。 SObjectizer在API级别支持此概念。 在演员的类中声明状态:

class Drive_A final:        public so_5::agent_t{    public:       Drive_A( context_t ctx, ... );       virtual ~Drive_A();       // состояния       state_t st_base {this};       state_t st_disabled{ initial_substate_of{st_base}, "disabled" };       state_t st_preinit{ substate_of{st_base}, "preinit" };       state_t st_off{ substate_of{st_base}, "off" };       state_t st_connecting{ substate_of{st_base}, "connecting" };       state_t st_disconnecting{ substate_of{st_base}, "disconnecting" };       state_t st_connected{ substate_of{st_base}, "connected" };...}

and then event-handlers are defined for every state. Sometimes it is necessary to do something upon entering or exiting a state. This is also supported in SObjectizer through on_enter/on_exit handlers. It seems that SObjectizer's developers have background in the development of control systems.

然后为每个状态定义事件处理程序。 有时在进入或退出状态时有必要做一些事情。 SObjectizer中的on_enter / on_exit处理程序也支持此功能。 似乎SObjectizer的开发人员具有控制系统开发的背景。

事件处理程序 (Event handlers)

An event handler is a place where your application logic is implemented. As I said earlier, a subscription is created for a particular mbox and a specific state. If an actor has no explicitly specified states it is in a special "default_state".

事件处理程序是实现应用程序逻辑的地方。 如前所述,将为特定的mbox和特定的状态创建订阅。 如果演员没有明确指定的状态,则它处于特殊的“ default_state”。

Different handlers can be defined for the same event in different states. If you don't define a handler for some event, then this event will be ignored (an actor won’t know about it).

可以为处于不同状态的同一事件定义不同的处理程序。 如果您未为某个事件定义处理程序,则该事件将被忽略(演员不知道该事件)。

There is a simple syntax to define event handlers. You specify a method, and there is no need to specify additional types or template parameters. For example:

有一种简单的语法可以定义事件处理程序。 您指定一种方法,而无需指定其他类型或模板参数。 例如:

so_subscribe(drv->so_mbox())    .in(st_base)    .event( &Drive_A::on_get_info )    .event( &Drive_A::on_control )    .event( &Drive_A::off_control );

It's an example of subscription on events from a specific mbox in the st_base state. It is worth mentioning that st_base is a base state for some other states and that subscription will be inherited by derived states. This approach allows to get rid of copy-and-paste for similar event handlers in different states. But the inherited event handler can be redefined for a particular state or an event can be completely disabled ("suppressed").

这是在st_base状态下从特定mbox订阅事件的示例。 值得一提的是,st_base是其他某些状态的基本状态,并且订阅将由派生状态继承。 这种方法可以消除处于不同状态的类似事件处理程序的复制和粘贴。 但是可以为特定状态重新定义继承的事件处理程序,也可以完全禁用事件(“抑制”)。

Another way to define event handlers is using lambda functions. It's a very convenient way because event handlers often contain just a line or two of code: a send of something to somewhere or a state change:

定义事件处理程序的另一种方法是使用lambda函数。 这是一种非常方便的方法,因为事件处理程序通常只包含一两行代码:将某物发送到某个地方或状态发生变化:

so_subscribe(drv->so_mbox())    .in(st_disconnecting)    .event([this](const msg_disconnected_t& m)    {        ...        st_off.activate();    })    .event([this]( const msg_failure_t& m )    {        ...        st_protection.activate();    });

That syntax looks complex at the beginning, but it becomes familiar just after a couple of days of active coding and you even start to like it. It is because the whole logic of some actor can be concise and placed in one screen. In the example shown above, there are transitions from st_disconnected to st_off or st_protection. This code is easy to read.

该语法在开始时看起来很复杂,但是经过两天的主动编码后,它变得熟悉起来,您甚至开始喜欢它。 这是因为某些演员的整个逻辑可以简明扼要并放在一个屏幕中。 在上面显示的示例中,存在从st_disconnected到st_off或st_protection的过渡。 此代码易于阅读。

BTW, for straightforward cases, where just a state transition is necessary, there is a special syntax:

顺便说一句,对于简单的情况,仅需要状态转换,有一种特殊的语法:

auto mbox = drv->so_mbox();st_off    .just_switch_to
(mbox, st_connected) .just_switch_to
(mbox, st_protection) .just_switch_to
(mbox, st_protection) .just_switch_to
(mbox, st_on);

控制 (The Control)

How is the control organized? As mentioned above there are two control stations for controlling the movement of battens. Every control station has a display, a pointing device (trackball) and speed setter (and we don't count a computer inside the station and some additional accessories).

控件如何组织? 如上所述,有两个控制站用于控制板条的运动。 每个控制站都有一个显示器,一个指示设备(跟踪球)和速度设定器(而且我们不算控制台内的计算机和一些其他附件)。

There are two control modes: manual and "scenario mode". "Scenario mode" will be discussed later, and now let’s talk about the manual mode. In this mode, an operator selects a batten, prepares it for movement (connects the engine to a FC), sets the target mark for the batten, and when the speed is set above zero, the batten starts to move.

有两种控制模式:手动和“场景模式”。 稍后将讨论“场景模式”,现在让我们谈谈手动模式。 在此模式下,操作员选择一个板条,准备进行移动(将引擎连接到FC),设置板条的目标标记,并且当速度设置为零以上时,板条开始移动。

The speed setter is a physical accessory in the form of a "potentiometer with a handle", but there is also a virtual one shown on the station's display. The more it is turned, the higher is the movement speed. The maximum speed is limited at 1.5 meters per second. The speed setter is one for all battens. It means that all selected battens move at the same speed. Battens can move in opposite directions (it depends on the operator's selection). It's apparent that it is hard for a human to control more than a few battens. Because of that only small groups of battens are handled in the manual mode. Operators can control battens from two control stations at the same time. So there is a separate speed setter for each station.

速度设定器是“带手柄电位器”形式的物理附件,但在站的显示屏上也显示了虚拟附件。 转得越多,移动速度就越高。 最大速度限制为每秒1.5米。 速度设定器是所有板条之一。 这意味着所有选定的板条都以相同的速度移动。 条板可以朝相反的方向移动(取决于操作员的选择)。 显然,对于一个人来说,控制几个板条是很困难的。 因此,在手动模式下只能处理少量的板条。 操作员可以同时从两个控制站控制板条。 因此,每个站都有一个单独的速度设定器。

From the implementation's point of view, there is no specific logic in the manual mode. A "connect engine" command goes from the graphical interface, is transformed into a corresponding message to an actor, and then is being handled by that actor. The actor goes from "off" state to "connecting", and then to "connected" state. Similar things happen with commands for positioning a batten and setting the movement speed. All these commands are passed to an actor in the form of messages. But it is worth mentioning that "graphical interface" and "control process" are separate processes and libuniset2 is used for IPC.

从实现的角度来看,手动模式下没有特定的逻辑。 “连接引擎”命令从图形界面发出,转换为相应的消息后发送给参与者,然后由该参与者处理。 角色从“关闭”状态变为“正在连接”,然后变为“已连接”状态。 用于定位板条和设置移动速度的命令也会发生类似的情况。 所有这些命令都以消息的形式传递给参与者。 但是值得一提的是,“图形界面”和“控制过程”是独立的过程,并且libuniset2用于IPC。

场景模式(又有演员吗?) (The Scenario mode (are there Actors again?))

In practice, the manual mode is used only for very simple cases or during rehearsals. The main control mode is "scenario mode". In that mode, every batten is moved to a specific position with particular speed according to scenario settings. Two simple commands are available to an operator in that mode:

实际上,手动模式仅用于非常简单的情况或排练期间。 主控制模式为“场景模式”。 在这种模式下,每个板条都根据场景设置以特定的速度移动到特定的位置。 在该模式下,操作员可以使用两个简单的命令:

  • prepare (a group of engines is being connected to FC);

    准备(一组引擎正在连接到FC);
  • go (movement of the group starts).

    前进(开始移动组)。

The whole scenario is split into "agendas". An "agenda" describes a single movement of a group of battens. It means that an "agenda" includes some battens and contains target destinations and speeds for them. In reality, a scenario consists of acts, acts consist of pictures, picture consist of agendas, and agenda consist of targets for battens. But from the control's point of view, that doesn't matter, because only agendas contain the precise parameters of the batten's movement.

整个场景分为“ agendas”。 “议程”描述一组板条的单个运动。 这意味着“议程”包括一些板条,并包含目标位置和速度。 实际上,场景由行为组成,行为由图片组成,图片由议程组成,而议程由板条目标组成。 但是从控件的角度来看,这并不重要,因为仅议程包含板条运动的精确参数。

The Actor Model fits that case perfectly. We have developed a "scenario player" that spawns a group of special actors and starts them. We have developed two types of actors: executor actors (they control the movement of battens) and coordinator actors (they distribute tasks between executors). Executors are created on demand: when there are no free executors, a new executor will be created. Coordinator manages the pool of available executors. As a result, the control roughly looks like this:

演员模型非常适合这种情况。 我们开发了一个“场景播放器”,可以生成一组特殊演员并将其启动。 我们开发了两种类型的角色:执行者角色(它们控制木条的移动)和协调者角色(它们在执行者之间分配任务)。 执行程序是按需创建的:没有免费的执行程序时,将创建一个新的执行程序。 协调器管理可用执行器池。 结果,该控件大致如下所示:

  • an operator loads a scenario;

    操作员加载场景;
  • "scrolls" it until the required agenda;

    “滚动”它直到所需的议程;
  • presses the "prepare" button at the appropriate time. At that moment a message is sent to a coordinator. This message contains data for every batten from the agenda;

    在适当的时间按下“准备”按钮。 在那一刻,消息被发送给协调员。 此消息包含议程中每个板条的数据;
  • the coordinator reviews its pool of executors and distributes tasks between free executors (new executors are created, if needed);

    协调员审查其执行者库,并在免费执行者之间分配任务(如果需要,可以创建新的执行者);
  • each executor receives a task and performs preparation actions (connects an engine to a FC, then waits for "go" command);

    每个执行者接收一个任务并执行准备动作(将引擎连接到FC,然后等待“执行”命令);
  • the operator presses the "go" button at the appropriate moment;

    操作员在适当的时候按下“开始”按钮;
  • the "go" command goes to the coordinator, and it distributes the command between all executors that are currently in use.

    “ go”命令进入协调器,并在当前使用的所有执行器之间分配该命令。

There are some additional parameters in agendas. Like "start the movement only after N seconds delay" or "start the movement only after an additional command from an operator". Because of that, the list of states for an executor is quite long: "ready for the next command", "ready for movement", "delay of the movement", "awaiting operator command", "moving", "completed", "failure".

议程中还有一些其他参数。 类似于“仅在延迟N秒后才开始运动”或“仅在操作员发出附加命令后才开始运动”。 因此,执行者的状态列表很长:“准备下一个命令”,“准备移动”,“移动延迟”,“正在等待操作员命令”,“正在移动”,“已完成”, “失败”。

When a batten has successfully reached the target mark (or there is a failure) the executor reports to the coordinator about task completion. Coordinator replies with a command to turn the engine off (if the batten does not participate in the agenda anymore) or sends a new task to the executor. The executor either turns the engine off and switches to "waiting" state or starts processing the new command.

当板条成功达到目标标记(或有故障)时,执行者向协调员报告任务完成情况。 协调器回复命令以关闭引擎(如果木条不再参与议程)或将新任务发送给执行者。 执行程序要么关闭引擎,然后切换到“等待”状态,要么开始处理新命令。

Because SObjectizer has a quite thoughtful and convenient API for working with states, the implementation code turned out to be quite concise. For example, a delay before movement is described by just a line of code:

由于SObjectizer具有用于处理状态的相当周到且方便的API,因此实现代码非常简洁。 例如,仅通过一行代码来描述移动之前的延迟:

st_delay.time_limit( std::chrono::milliseconds{target->delay()}, st_moving );st_delay.activate();...

The time_limit method specifies the amount of time to stay in the state and which state should be activated then (st_moving in that example).

time_limit方法指定停留在状态中的时间量,然后应激活哪个状态(在该示例中为st_moving )。

保护演员 (Protection actors)

Certainly, failures can occur. There are requirements to correctly handle these failures. Actors are used for such tasks too. Let's look at some examples:

当然,可能会发生故障。 要求正确处理这些故障。 演员也用于此类任务。 让我们看一些例子:

  • overcurrent protection;

    过流保护;
  • protection from sensor's malfunction;

    防止传感器故障;
  • protection from movement in the opposite direction (it can happen if there is something wrong with sensors or actuators);

    防止反方向运动(如果传感器或执行器出现故障,可能会发生这种情况);
  • protection from spontaneous movement (without a command);

    防止自发移动(无命令);
  • command execution control (the movement of a batten should be checked).

    命令执行控制(应检查板条的移动)。

We can see that all those case are self-sufficient, but they should be controlled together, at the same time. It means that any failure can happen. But every check has its logic: sometimes it is necessary to check a timeout, sometimes it is required to analyze some previous values from a sensor. Because of that, protection is implemented in the form of small actors. These actors are added to cooperation to the main actor that implements control logic. This approach allows for easy addition of new protection cases: just add yet another protector actor to the cooperation. The code of such actor is usually concise and easy to understand, because it implements only one function.

我们可以看到所有这些情况都是自给自足的,但是应该同时对它们进行控制。 这意味着任何故障都可能发生。 但是每次检查都有其逻辑:有时需要检查超时,有时需要分析传感器中的某些先前值。 因此,保护​​以小参与者的形式实施。 将这些参与者添加到实现控制逻辑的主要参与者的协作中。 这种方法可以轻松添加新的保护案例:只需在合作中添加另一个保护角色即可。 这种参与者的代码通常简洁明了,因为它仅实现一个功能。

Protector actors also have several states. Usually, they are turned on when an engine is turned on or when a batten starts its movement. When a protector detects a failure/malfunction it publishes a notification (with protection code and some additional details inside). The main actor reacts to that notification and performs necessary actions (like turning the engine off and switching to protected state).

保护者角色也有几种状态。 通常,它们在引擎开启或板条开始运动时会开启。 当保护程序检测到故障/功能故障时,它将发布通知(其中包含保护代码和一些其他详细信息)。 主参与者对该通知做出React并执行必要的操作(例如关闭引擎并切换到保护状态)。

结论... (As the conclusion...)

...this article is not a breakthrough of course. The Actor Model is being used in multiple different systems for a quite long time. But it was my first experience of using the Actor Model for building an automatic control system in a rather small project. And this experience turned out to be quite successful. I hope I’ve shown that actors are a good fit for control algorithms: there are places for actors literally everywhere.

...当然不是突破。 Actor模型在多种不同的系统中使用了很长时间。 但这是我第一次使用Actor模型在一个很小的项目中构建自动控制系统的经验。 事实证明,这种经验非常成功。 我希望我已经证明角色很适合控制算法:角色无处不在。

had implemented something similar in previous projects (I mean states, message exchange, management of worker threads, and so on), but it wasn't a unified approach. By using SObjectizer we got a small, lightweight tool that solves a lot of problems. We no longer need to (explicitly) use low-level synchronization mechanisms (like mutexes), there is no manual thread management, no more handwritten statecharts. All these are provided by the framework, logically connected and expressed in the form of convenient API, but you don't lose the control on details. So it was an exciting experience. If you are still in doubt, then I recommend you to take a look at the Actor Model and in particular. It leaves positive emotions.

在先前的项目中已经实现了类似的功能(我的意思是状态,消息交换,工作线程管理等),但这不是统一的方法。 通过使用SObjectizer,我们得到了一个小型,轻便的工具,可以解决许多问题。 我们不再需要(明确地)使用低级同步机制(例如互斥体),不再需要手动进行线程管理,也不再需要手写状态图了。 所有这些都是由框架提供的,在逻辑上连接并以便捷的API形式表示,但是您不会失去对细节的控制。 因此,这是一次令人兴奋的经历。 如果仍然有疑问,建议您特别看一下Actor模型和 。 它留下了积极的情绪。

The Actor Model really works! Especially in the theatre.

演员模型真的有效! 特别是在剧院。

Original article in

原文

翻译自:

大剧院自助签证

转载地址:http://gebwd.baihongyu.com/

你可能感兴趣的文章
uclibc,eglibc,glibc之间的区别和联系【转】
查看>>
Java魔法堂:找外援的利器——Runtime.exec详解
查看>>
mysql数据库存放路径
查看>>
TestNG(五)常用元素的操作
查看>>
解决 Visual Studio 点击添加引用无反应的问题
查看>>
通过镜像下载Android系统源码
查看>>
python字符串格式化 %操作符 {}操作符---总结
查看>>
windows 不能在 本地计算机 启动 Apache
查看>>
iOS开发报duplicate symbols for architecture x86_64错误的问题
查看>>
Chap-6 6.4.2 堆和栈
查看>>
【Java学习笔记之九】java二维数组及其多维数组的内存应用拓展延伸
查看>>
C# MySql 连接
查看>>
POJ 1740
查看>>
MySQL性能优化方法一:缓存参数优化
查看>>
NodeJS+Express+MongoDB 简单实现数据录入及回显展示【Study笔记】
查看>>
div+css教程网站建设门户网站和电子商务网站CSS样式表
查看>>
sk_buff Structure
查看>>
oracle的级联更新、删除
查看>>
多浏览器开发需要注意的问题之一
查看>>
Maven配置
查看>>