为 Arduino 生成代码(Crossroads)¶
在本示例中,我们将在 Arduino 兼容板上使用 Engee Automata 库在 Engee 中开发一个模型,以控制一个十字路口的两个车辆交通灯和一个行人交通灯。
本案例研究的目的是为一个交叉路口建立一个控制模型,该交叉路口由两股车流和一股人流组成,分别由两个三段式交通灯和一个两段式交通灯控制。路段切换算法将根据时序图进行定义。控制算法将通过几个模块Chart
来实现,输入信号的消除和输出信号的生成将通过模块C-Function
来实现。
在控制程序算法中,可以选择运行或待机模式,模式的切换由目标设备输入的离散信号实现。
本演示使用 Amperka 的 Iskra Neo 控制器。如下图所示,受控电路由无线电元件(LED、按钮触点、电阻和连接线)在无焊面包板上组装而成。电路模拟交通灯的运行:两个三段式汽车交通灯和一个两段式行人交通灯。
用于打开/关闭待机模式的输入信号通过按钮触点与 Arduino 电路板的数字触点 4 连接。交通信号灯路段开关的输出信号由数字触点 8 - 13 输出到相应颜色的 LED 上。行人交通灯开关的输出信号由数字触点 6、7 发出。为确保电路的正确运行,还使用了限流电阻(330 欧姆)和收缩电阻(10 千欧)。电路由 Arduino 电路板本身供电。
要实施的算法将根据下图的时序图再现十字路口交通灯的运行情况。
三股车流(两辆机动车和一名行人)受到异步控制。同时,交通许可(绿灯)每次只针对一个流向,持续时间为 10 秒。车辆通行许可结束后,绿灯部分的闪烁将被打开。交通信号灯从允许信号灯转为禁止信号灯(红灯)时,黄灯部分开启 5 秒钟,反之,红灯和黄灯部分同时开启 5 秒钟。
交通信号灯的两种状态描述了占空比:
- 车辆交通灯的黄色部分开启 1 秒,行人交通灯的黄色部分关闭;
- 在 1 秒钟内,汽车和行人交通灯的所有部分都关闭。
控制算法分为几个功能部分--计数器操作在Common_Counter
模块中再现,汽车交通灯控制信号light
的形成在Traffic_Lights
模块中再现,行人交通灯控制信号cross
的形成在Crosswalk
模块中再现。
向模型传输模式选择信号的是程序块Digital Input
,向 Arduino 串行端口输出信息的是程序块To Serial
,向 Arduino 数字引脚输出汽车和行人交通灯代码的分别是程序块Digital_Output_1
和Digital_Output_2
。
向串行端口输出结构化数据时,使用矢量形成块DataMux
。
在Common_Counter
程序块的状态图中,状态Counter
以及转换2
和3
用于重现 54 秒后复位的递增计数器的运行。状态Service
和转换1
用于在设置交叉点睡眠模式时将计数器重置为"-1 "值。
根据块Traffic_Lights
状态图中计数器变量cntr
的值,选择编码交通灯路段状态的变量lights
的值。在这种情况下,除ninth
和tenth
之外的所有状态都将再现运行模式下各部分的切换顺序。
程序块Traffic_Lights
的状态图如下图所示。
反过来,根据Crosswalk
块中lights
变量的值,选择编码行人交通灯状态的cross
变量的值。
块Crosswalk
的状态图如下图所示。
信号表在每个程序块状态图Chart
的设置中定义。输出变量的初始值:
- 块
Common_Counter
, 变量mode = 0
;
- 块
Traffic_Lights
, 变量light = 33
;
- 块
Crosswalk
, 变量cross = 2
。
根据获得的模型数据,我们绘制出计数器变量counter
、汽车交通灯traffic_lights
和行人交通灯crosswalk_lights
的编码状态。
图中显示了变量的变化。模型中的计算周期设定为 1 秒。交通灯和行人交通灯traffic_lights
和crosswalk_lights
各段状态变量的变化值和持续时间与时间图相对应
为了将开发的模型传输到目标设备,让我们来生成 C 代码:
[ Info: Generated code and artifacts: /user/start/examples/codegen/arduino_crossroad/arduino_crossroad_code
插件文件已在指定目录arduino_crossroad_code
中生成。此外,在演示示例的目录arduino_crossroad
中还有一个预先编写的 Arduino 草图,该目录的名称为arduino_crossroad.ino
。在该草图中,连接了代码生成过程中获得的头文件,初始化了全局变量,定义了模型计算循环,并调用了模型计算函数。代码注释中对草图进行了详细描述。
要在 Arduino 上执行代码,请下载arduino_crossroad
目录,并将草图arduino_crossroad.ino
从 Arduino IDE 加载到目标设备上。
成功编译并将草图加载到目标设备后,调试板的数字输出将产生信号,打开交通灯部分(面包板上的 LED 灯)。为确保模型正常工作,让我们打开 Arduino IDE 中的串行端口监控器。
可以看出,To Serial
程序块中规定的报文以 1 秒的周期按要求的格式输出到串行端口。
当按下按钮触点时,十字路口的交通灯切换到待机模式,并向串行端口输出以下信息:
所需的信息以 1 秒的周期输出到串行端口。因此,待机模式下的交叉操作也是正确的,这证明了模型和代码的性能。
在本演示中,我们为 Arduino 兼容平台开发了一个十字路口模型,其中有两个三段式车辆交通灯和一个两段式行人交通灯。控制算法是利用无限自动机库重新创建的。该模型再现了交通灯在两种模式下的运行,不仅确保了路段的切换,还确保了路段的闪烁。该算法已在目标设备上进行了测试,生成的代码不仅能控制 LED 部分,还能向串行端口发送有关当前模式、三个交通灯的点亮部分以及当前运行时间的信息。
{"id": "6e56e111-f6e8-451a-be42-0a61ebba7765", "data": [{"showlegend": true, "mode": "lines", "xaxis": "x", "colorbar": {"title": {"text": ""}}, "name": "Счётчик", "zmin": null, "yaxis": "y", "legendgroup": "Счётчик", "zmax": null, "line": {"color": "rgba(0, 154, 250, 1.000)", "shape": "linear", "dash": "solid", "width": 2}, "y": [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15], "type": "scatter", "x": [0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99, 100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108, 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125], "zaxis": null, "z": null, "metadata": {"shouldEnableSmartZoom": false, "smartZoomParams": {"minCount": 25000, "maxCount": 251, "currentCount": 251}}}, {"showlegend": true, "mode": "lines", "xaxis": "x", "colorbar": {"title": {"text": ""}}, "name": "Код светофоров", "zmin": null, "yaxis": "y", "legendgroup": "Код светофоров", "zmax": null, "line": {"color": "rgba(227, 111, 71, 1.000)", "shape": "linear", "dash": "solid", "width": 2}, "y": [33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 32, 32, 33, 33, 32, 32, 33, 33, 32, 32, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 4, 4, 12, 12, 4, 4, 12, 12, 4, 4, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 32, 32, 33, 33, 32, 32, 33, 33, 32, 32, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 4, 4, 12, 12, 4, 4, 12, 12, 4, 4, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 32, 32, 33, 33, 32, 32, 33, 33, 32, 32, 34], "type": "scatter", "x": [0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99, 100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108, 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125], "zaxis": null, "z": null, "metadata": {"shouldEnableSmartZoom": false, "smartZoomParams": {"minCount": 25000, "maxCount": 251, "currentCount": 251}}}], "config": {"showlegend": true, "xaxis": {"showticklabels": true, "gridwidth": 0.5, "range": [-3.75, 128.75], "domain": [0.041102848255079226, 0.9956255468066492], "mirror": false, "tickangle": 0, "showline": true, "zeroline": false, "tickfont": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "zerolinecolor": "rgba(0, 0, 0, 1)", "anchor": "y", "visible": true, "ticks": "inside", "tickmode": "array", "linecolor": "rgba(0, 0, 0, 1)", "showgrid": true, "title": {"text": "Время, сек", "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}}, "gridcolor": "rgba(0, 0, 0, 0.1)", "tickcolor": "rgb(0, 0, 0)", "type": "linear"}, "paper_bgcolor": "rgba(255, 255, 255, 1.000)", "annotations": [], "height": 300, "margin": {"l": 0, "b": 20, "r": 0, "t": 20}, "plot_bgcolor": "rgba(255, 255, 255, 1.000)", "yaxis": {"showticklabels": true, "gridwidth": 0.5, "range": [-1.620000000000001, 55.620000000000005], "domain": [0.10108632254301551, 0.9868766404199475], "mirror": false, "tickangle": 0, "showline": true, "zeroline": false, "tickfont": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "zerolinecolor": "rgba(0, 0, 0, 1)", "anchor": "x", "visible": true, "ticks": "inside", "tickmode": "array", "linecolor": "rgba(0, 0, 0, 1)", "showgrid": true, "title": {"text": "Значения", "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}}, "gridcolor": "rgba(0, 0, 0, 0.1)", "tickcolor": "rgb(0, 0, 0)", "type": "linear"}, "legend": {"yanchor": "top", "xanchor": "left", "bordercolor": "rgba(0, 0, 0, 1)", "bgcolor": "rgba(255, 255, 255, 1.000)", "borderwidth": 1, "tracegroupgap": 0, "y": 1, "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "title": {"font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}, "text": ""}, "traceorder": "normal", "x": 0.07}, "width": 634.984375}}
{"id": "e4d62de9-6c41-4de5-ae18-8a2d2516ea52", "data": [{"showlegend": true, "mode": "lines", "xaxis": "x", "colorbar": {"title": {"text": ""}}, "name": "Код пешеходный светофор", "zmin": null, "yaxis": "y", "legendgroup": "Код пешеходный светофор", "zmax": null, "line": {"color": "rgba(0, 128, 0, 1.000)", "shape": "linear", "dash": "solid", "width": 2}, "y": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], "type": "scatter", "x": [0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99, 100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108, 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125], "zaxis": null, "z": null, "metadata": {"shouldEnableSmartZoom": false, "smartZoomParams": {"minCount": 25000, "maxCount": 251, "currentCount": 251}}}], "config": {"showlegend": true, "xaxis": {"tickangle": 0, "showline": true, "gridcolor": "rgba(0, 0, 0, 0.1)", "showticklabels": false, "gridwidth": 0.5, "visible": true, "ticks": "inside", "range": [-3.75, 128.75], "domain": [0.03122630504520268, 0.9956255468066492], "linecolor": "rgba(0, 0, 0, 1)", "showgrid": false, "zeroline": false, "type": "linear", "title": {"text": "Время, сек"}, "zerolinecolor": "rgba(0, 0, 0, 1)", "mirror": false, "anchor": "y"}, "paper_bgcolor": "rgba(255, 255, 255, 1.000)", "annotations": [], "height": 300, "margin": {"l": 0, "b": 20, "r": 0, "t": 20}, "plot_bgcolor": "rgba(255, 255, 255, 1.000)", "yaxis": {"showticklabels": true, "gridwidth": 0.5, "range": [0, 3], "domain": [0.06404928550597848, 0.9868766404199475], "mirror": false, "tickangle": 0, "showline": true, "zeroline": false, "tickfont": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "zerolinecolor": "rgba(0, 0, 0, 1)", "anchor": "x", "visible": true, "ticks": "inside", "tickmode": "array", "linecolor": "rgba(0, 0, 0, 1)", "showgrid": true, "title": {"text": "Значения", "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}}, "gridcolor": "rgba(0, 0, 0, 0.1)", "tickcolor": "rgb(0, 0, 0)", "type": "linear"}, "legend": {"yanchor": "top", "xanchor": "left", "bordercolor": "rgba(0, 0, 0, 1)", "bgcolor": "rgba(255, 255, 255, 1.000)", "borderwidth": 1, "tracegroupgap": 0, "y": 1, "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "title": {"font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}, "text": ""}, "traceorder": "normal", "x": 0.07}, "width": 634.984375}}