Skip to content

Commit

Permalink
Revert "fix: removed empty files and translated Chinese to English (#…
Browse files Browse the repository at this point in the history
…1063)"

This reverts commit 7d119a5.
  • Loading branch information
PabloVD committed Apr 19, 2024
1 parent 7d119a5 commit 648e751
Show file tree
Hide file tree
Showing 33 changed files with 154 additions and 70 deletions.
57 changes: 57 additions & 0 deletions srunner/osc2/README_zh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# 模块介绍

## 一、Antlr4简介
Antlr4是一款强大的语法分析器生成工具。给出一门预言的语法,Antlr4能够为该语法生成语法分析器,并自动建立语法分析树。通过遍历此树,并在所需的结构处触发回调函数来实现更多功能。为此,Antlr4提供了自动生成语法分析树遍历器:监听器(listener)或者访问器(visitor)。此外,Antlr4还提供了错误报告和错误功能,并且可以通过实现Antlr4提供的接口来定制错误消息。更多介绍请参考[Antlr官网](https://www.antlr.org/)

### 构建语法分析树

```
antlr4 -Dlanguage=Python3 Example.g4
```
执行此命令后,会生成多个文件,需要了解以下几个文件

- ExampleParser.py:该文件包含一个语法分析器,用于识别‘Example语法’。
- ExampleListener.py:该文件包含了一个以监听器方式遍历语法分析树的遍历器——ExampleListener类。使用监听器遍历语法分析树时,会触发该监听器的回调方法。该类定义了一系列的回调方法,并为这些方法提供默认的空实现,使用时用户只需对需要的方法进行覆盖。
- Example.tokens:Antlr会为语法文件中定义的每个词法符号定义一个对应的数字,该文件用于存储它们之间的对应关系。

### 遍历语法分析树
Antlr提供了两种机制来访问语法解析树,分别是监听器(listener)或者访问器(visitor)。两者最大的区别在于,监听器方法会在访问语法解析树子结点的过程中被自动调用,而访问器方法必须显示调用visit方法来访问子结点,如果没有调用那么子树将不会被访问。

#### listener

ExampleListener类对应Antlr4生成的listener,用户构造自己的访问器时需要继承该类,实现所需的方法。listener会为每个子结点生成一个enterxxx()方法和exitxxx()方法,进入一个结点时会调用enterxxx()方法,当遍历完该结点的所有子节点,从结点退出时,会调用该结点对应的exitxxx()方法。


#### visitor
Antlr4默认生成listener,通过添加-visitor参数指定生成visitor。

```
antlr4 -Dlanguage=Python3 -visitor Example.g4
```


## 二、error_manager模块
Antlr4能够检查并报告输入文件中的词法和语法错误,默认情况下将错误信息送至standard error。为了方便定位和解决错误,项目对错误消息进行定制。
- 监听错误:可以通过实现ErrorListener接口来改变消息的内容和输出目标。项目实现了ErrorListener接口,构建自己的错误监听器,从而将错误信息标准化。下图为项目对ANTLR4错误监听器的扩展
![输入图片说明](developer_documentationimage.png)
- 输出错误信息:使用python的logging模块输出错误信息。


为使自定义的错误管理模块生效,需要在对输入文件进行解析之前,将默认的错误监听器移除,增加自定义的错误监听器。

```
lexer/parser.removeErrorListener()
lexer/parser.addErrorListener(OscErrorListener)
```

## 三、ast_manager模块
ast_manager模块用于创建抽象语法树。包括ast结点定义和ast构建。
- ast结点定义:Node类是所有ast结点的基类,该类定义了1)结点对应的源码的位置信息;2)结点所在的作用域;3)子结点。其它结点均直接或间接继承该结点。
- ast构建:通过遍历Antlr4生成的语法解析树来构建ast。使用listener遍历语法解析树,在回调函数中创建ast结点,并将结点添加到抽象语法树上。

## 四、symbol_manager模块
符号管理模块来记录符号的定义和追踪符号的使用情况,确保符号在使用之前被定义,并且在符号的作用域之内被使用。
- 符号类定义:Symbol类是所有符号的基类,该类定义了符号的基本信息,例如名称和类别,其它符号类在Symbol类的基础上进行扩展。
- 作用域:通过遍历语法解析树,将符号作用域创建为树的结构,在此基础上实现OpenScenario2.0的继承和扩展特性。


1 change: 1 addition & 0 deletions srunner/osc2/symbol_manager/scenario_symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def __init__(self, QualifiedBehaviorSymbol):

def is_key_found(self, sym):
if isinstance(sym, ScenarioInhertsSymbol):
# 对于继承不做重复性检查,同时停止递归
return False
if sym.name in self.symbols and sym.name:
return True
Expand Down
Empty file added srunner/osc2_dm/environment.py
Empty file.
Empty file.
Empty file added srunner/osc2_dm/osc_action.py
Empty file.
Empty file added srunner/osc2_dm/osc_actor.py
Empty file.
Empty file.
60 changes: 35 additions & 25 deletions srunner/scenarioconfigs/README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
This document introduces the functions and usage methods of the three modules config, scenario and data bridge
本文档对config, scenario, data_bridge三个模块的功能及使用方法进行介绍

**1. config**
**一、config模块**

- Code:srunner/scenarioconfigs/osc2_scenario_configuration.py
概述:

- Function: Parses the osc2 scenario description file, generates type objects in the standard library based on the type and constraint parameters, and sets parameters, for example, ego and npc related to vehicles and path related to paths
- 对应代码:srunner/scenarioconfigs/osc2_scenario_configuration.py

Usage:
- 功能:解析osc2场景描述文件,根据类型和约束的参数配置,生成标准库里相关类型对象,并设置参数。例如,描述车辆相关的类型对象ego和npc,描述路径相关的类型对象path

(1) Import the corresponding files in the scenario runner.py and osc2 Scenario.py files
使用方法:

(1) 在scenario_runner.py和osc2_scenario.py文件中导入对应文件

```
from srunner.scenarioconfigs.osc2_scenario_configuration import OSC2ScenarioConfiguration
```

(2) In the scenario runner. Py files run osc2 (self) function to initialize the OSC2ScenarioConfiguration
(2) 在scenario_runner.py文件的_run_osc2(self)函数中对OSC2ScenarioConfiguration进行初始化
```
# self._args.osc2: The input scene file name string
# self.client: The client that connects to the carla simulator
# self._args.osc2表示输入的场景文件名称字符串
# self.client表示与carla模拟器建立连接的客户端
config = OSC2ScenarioConfiguration(self._args.osc2, self.client)
```

(3)OSC2Scenario is initialized in the load and run scenario(self, config) function of the scenario runner.py file with config as input
(3)在scenario_runner.py文件的_load_and_run_scenario(self, config)函数中,config作为输入,对OSC2Scenario进行初始化

```
scenario = OSC2Scenario(world=self.world,
Expand All @@ -30,22 +32,24 @@ scenario = OSC2Scenario(world=self.world,
osc2_file=self._args.osc2,
timeout=100000)
```
**2. scenario**
**二、scenario模块**

概述:

- Code:/srunner/scenarios/osc2_scenario.py
- 对应代码:/srunner/scenarios/osc2_scenario.py

- Function:The behavior tree corresponding to the osc2 scene description file is created based on the standard library objects obtained by parsing the osc2 scene description file, the abstract syntax tree, and the symbol table (the latter two are from the syntax parsing phase)
- 功能:根据解析osc2场景描述文件所获得的标准库对象,抽象语法树和符号表(后两者来自语法解析阶段),建立osc2场景描述文件所对应的行为树

Usage:
使用方法:

(1) Import the corresponding file in the scenario runner.py file
(1) 在scenario_runner.py文件中导入对应文件

```
from srunner.scenarios.osc2_scenario import OSC2Scenario
```


(2) OSC2Scenario is initialized in the load and run scenario(self, config) functions of scenario runner.py file
(2) 在scenario_runner.py文件的_load_and_run_scenario(self, config)函数中,对OSC2Scenario进行初始化

```
scenario = OSC2Scenario(world=self.world,
Expand All @@ -56,28 +60,30 @@ scenario = OSC2Scenario(world=self.world,
```


(3) The behavior tree established by osc2_scenario.py is used as input, and in the _Load_AND_RUN_SCENARIO (interfig) function of the SCENARIO_Runner.py file, loads the execution scene, and records the driving trajectory of the main car EGO
(3) 以osc2_scenario.py所建立的行为树作为输入,在scenario_runner.py文件的_load_and_run_scenario(self, config)函数中,加载执行场景,并记录主车ego的行车轨迹

```
# Load scenario and run it
# self.manager is an instantiated object of the SCENARIOMANAGER class. In real -time regulation of the operation of the scene in the Crala simulator
# self.manager是ScenarioManager类的实例化对象,对crala模拟器中场景的运行进行实时调控
self.manager.load_scenario(scenario, self.agent_instance)
self.manager.data_bridge = DataBridge(self.world)
self.manager.run_scenario()
self.manager.data_bridge.end_trace()
```
`from srunner.scenariomanager.scenario_manager import ScenarioManager`

**3. data_bridge**
**三、data_bridge模块**

- Function:The purpose is to extract the data of each frame when the scene is executed, write it into the trace.json file, and use the trace data file of the main vehicle in the scene as the input of the traffic regulation assertion for judgment
概述:

Usage:
- 功能:旨在提取场景执行时,每一帧的数据,将其写入trace.json文件中。将主车在场景中的轨迹数据文件trace.json作为交规断言的输入,进行判断。

(1) Import the DataBridge module in the scenario runner.py file
使用方法:

(1) 在scenario_runner.py文件中导入DataBridge模块
`from data_bridge import DataBridge`

(2) Initialization is done in the load and run scenario(self, config) functions of the ScenarioRunner class in the scenario runner.py file
(2) 在scenario_runner.py文件中ScenarioRunner类的_load_and_run_scenario(self, config)函数中进行初始化

```
# Load scenario and run it
Expand All @@ -86,9 +92,10 @@ self.manager.data_bridge = DataBridge(self.world)
self.manager.run_scenario()
```

(3) srunner/scenariomanager/scenario_manager.py -> run_scenario(self)
(3) 在srunner/scenariomanager/scenario_manager.py文件的run_scenario(self)函数中,

```
# update_ego_vehicle_start()函数根据主车ego提供的数据进行初始化
self.data_bridge.update_ego_vehicle_start(self.ego_vehicles[0])
while self._running:
Expand All @@ -100,11 +107,14 @@ if snapshot:
timestamp = snapshot.timestamp
if timestamp:
self._tick_scenario(timestamp)
# self.data_bridge.update_trace()函数对carla world每个trick所提供的信息进行处理,从而获得交规断言所需要的轨迹数据。
self.data_bridge.update_trace()
```

(4) scenario_runner.py -> ScenarioRunner -> _load_and_run_scenario(self, config)
(4) 在scenario_runner.py文件中ScenarioRunner类的_load_and_run_scenario(self, config)函数中:
```
# end_trace()函数在场景执行结束时,对轨迹数据进行更新并写入到trace.json文件中。
self.manager.data_bridge.end_trace()
```

14 changes: 5 additions & 9 deletions srunner/scenarioconfigs/osc2_scenario_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,11 @@
from srunner.osc2_dm.physical_object import *
from srunner.osc2_dm.physical_types import Physical, Range

# 标准库
from srunner.osc2_stdlib.path import Path

<<<<<<< HEAD
# pylint: disable=line-too-long
from srunner.scenarioconfigs.scenario_configuration import ScenarioConfiguration
=======
'''
Parses the osc2 scenario description file, generates type objects in the standard
library based on the type and keep constraint parameters, and sets parameters
>>>>>>> fd07c11... fix: removed empty files and translated Chinese to English

# pylint: enable=line-too-long
from srunner.scenariomanager.carla_data_provider import CarlaDataProvider
Expand Down Expand Up @@ -62,6 +57,7 @@ def __init__(self, filename, client):
self.unit_dict = {}
self.physical_dict = {}
self.weather = carla.WeatherParameters()
# 默认为白天
self.weather.sun_azimuth_angle = 45
self.weather.sun_altitude_angle = 70

Expand Down Expand Up @@ -106,6 +102,8 @@ def visit_global_parameter_declaration(
vehicle_class = getattr(vehicles, para_type)
v_ins = vehicle_class()

# TODO: 车辆配置参数解析和设置,需要解析keep语句
# 车辆rolename=变量名
v_ins.set_name(para_name)
if para_name == "ego_vehicle":
self.father_ins.add_ego_vehicles(v_ins)
Expand Down Expand Up @@ -141,6 +139,7 @@ def visit_scenario_declaration(self, node: ast_node.ScenarioDeclaration):
self.visit_do_directive(child)

def visit_do_directive(self, node: ast_node.DoDirective):
# 场景设置信息不会出现在场景的行为描述部分
pass

def visit_parameter_declaration(self, node: ast_node.ParameterDeclaration):
Expand All @@ -163,10 +162,7 @@ def visit_parameter_declaration(self, node: ast_node.ParameterDeclaration):
vehicle_class = getattr(vehicles, para_type)
v_ins = vehicle_class()

<<<<<<< HEAD
# TODO: Analyzing and setting vehicle configuration parameters requires parsing the keep statement
=======
>>>>>>> fd07c11... fix: removed empty files and translated Chinese to English
v_ins.set_name(para_name)
if para_name == OSC2Helper.ego_name:
self.father_ins.add_ego_vehicles(v_ins)
Expand Down
2 changes: 2 additions & 0 deletions srunner/scenariomanager/scenarioatomics/atomic_behaviors.py
Original file line number Diff line number Diff line change
Expand Up @@ -1685,10 +1685,12 @@ def update(self):
print(f'finish change speed!! current speed={curr_speed} km/h')
else:
if curr_speed < self._target_velocity:
# 加速
self._control.throttle = 1
self._control.brake = 0
print(f'current speed={curr_speed} km/h, target speed={self._target_velocity} km/h, accelerate!!! ')
else:
# 减速
self._control.throttle = 0
self._control.brake = 1
print('decelerate!!!')
Expand Down
2 changes: 1 addition & 1 deletion srunner/scenarios/osc2_scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ def visit_behavior_invocation(self, node: ast_node.BehaviorInvocation):
# scenario_declaration_node = self.father_ins.scenario_declaration.get(behavior_invocation_name)
scenario_declaration_node_scope = scenario_declaration_node.get_scope()
arguments = self.visit_children(node)
# Stores the value of the argument before the invoked scenario was overwritten, a: time=None
# Stores the value of the argument before the invoked scenario was overwritten, 如a: time=None
# keyword_args = {}
if isinstance(arguments, List):
for arg in arguments:
Expand Down
2 changes: 1 addition & 1 deletion tests/result
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
################################
# undefined actorName
# 未定义actorName
################################

actor Path
Expand Down
2 changes: 2 additions & 0 deletions tests/run_testcase/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ def main(self, input_stream):
listener = ParseTreeWalker()
ast_builder = ASTBuilder()
listener.walk(ast_builder, tree)
# 清空import信息
import_msg.clear_msg()
# 返回收集到的日志信息
return log_msg.get_log_msg()

def testcase(self, str):
Expand Down
12 changes: 7 additions & 5 deletions tests/test-ast-listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@

import graphviz

# node:node of the tree
# nodes:number the nodes in traversal order and line them with numbers
# pindex:id of the parent node
# g:graphviz
# node:入参,树的节点
# nodes:入参,按遍历的顺序给节点编号,用编号给节点连线
# pindex:父节点的编号
# g:graphviz的图对象
def render_ast(node, nodes, pindex, g):
if not isinstance(node, Tuple):
name = str(node)
Expand All @@ -39,7 +39,7 @@ def render_ast(node, nodes, pindex, g):
g.node(str(index), name)
if index != pindex:
# g.edge(str(index), str(pindex))
g.edge(str(pindex), str(index))
g.edge(str(pindex), str(index)) # 边是从父到子,要不会出现倒立的树
if isinstance(node, ast_node.AST):
for i in range(0, node.get_child_count()):
render_ast(node.get_child(i), nodes, index, g)
Expand Down Expand Up @@ -143,6 +143,7 @@ def main(input_stream):

if __name__ == '__main__':
error_file_list = []
# 如果测试的为文件夹
if os.path.isdir(sys.argv[1]):
filepath = sys.argv[1]
files = os.listdir(filepath)
Expand All @@ -160,6 +161,7 @@ def main(input_stream):
for error_file in error_file_list:
LOG_INFO(error_file)

# 如果测试的为单个文件
elif os.path.isfile(sys.argv[1]):
new_file, import_msg = Preprocess(sys.argv[1]).import_process()
input_stream = FileStream(new_file, encoding='utf-8')
Expand Down
17 changes: 11 additions & 6 deletions tests/test-ast-visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
from srunner.osc2.osc_preprocess.pre_process import ImportFile, Preprocess
import graphviz

# node:node of the tree
# nodes:number the nodes in traversal order and line them with numbers
# pindex:id of the parent node
# g:graphviz
# node:入参,树的节点
# nodes:入参,按遍历的顺序给节点编号,用编号给节点连线
# pindex:父节点的编号
# g:graphviz的图对象
def render_ast(node, nodes, pindex, g):
if not isinstance(node, Tuple):
name = str(node)
Expand All @@ -38,7 +38,7 @@ def render_ast(node, nodes, pindex, g):
g.node(str(index), name)
if index != pindex:
# g.edge(str(index), str(pindex))
g.edge(str(pindex), str(index))
g.edge(str(pindex), str(index)) # 边是从父到子,要不会出现倒立的树
if isinstance(node, ast_node.AST):
for i in range(0, node.get_child_count()):
render_ast(node.get_child(i), nodes, index, g)
Expand Down Expand Up @@ -162,9 +162,11 @@ def main(input_stream):


if __name__ == '__main__':
print("执行预处理")
error_file_list = []
# 如果测试的为文件夹
if not os.path.exists(sys.argv[1]):
print("File path error")
print("文件路径错误!")
if os.path.isdir(sys.argv[1]):
filepath = sys.argv[1]
files = os.listdir(filepath)
Expand All @@ -182,7 +184,10 @@ def main(input_stream):
for error_file in error_file_list:
LOG_INFO(error_file)

# 如果测试的为单个文件
elif os.path.isfile(sys.argv[1]):
print("执行预处理")
# 预处理,展开import,返回file类型对象和存储预处理信息的对象
new_file, import_msg = Preprocess(sys.argv[1]).import_process()
input_stream = FileStream(new_file, encoding='utf-8')
if main(input_stream)>0:
Expand Down
Loading

0 comments on commit 648e751

Please sign in to comment.