Apollo控制部分1-- ControlComponent组件介绍
Apollo控制部分1-- ControlComponent组件介绍
- 摘要
- 一、ControlComponent
- 1、启动文件解析
- 2、ControlComponent()组件函数解析
- 1)ControlComponent::ControlComponent() 构造函数
- 2)ControlComponent::Init() 初始化函数(执行一次)
- 3)ControlComponent::Proc() 初始化函数(执行间隔10ms,频率100Hz)
- 二、`⭐`详解
- `⭐1`:车辆状态信息获取器
- `⭐2`:参数文件载入
- (1)终端配置参数文件
- (2)程序配置参数文件
- `⭐3` local_view_解析
- 附表
- 附表1
@author:Wutong
@time:2023-03-05 15:46
摘要
本文介绍控制模块入口组件ControlComponent,文件位置为"modules/control/control_component.h"。本文未涉及到控制部分的核心算法,只是讲解Apollo控制模块的最外层包装处理部分,但是读懂这些代码对Apollo整个架构有帮助,能了解到Apollo一些参数载入方式、通用数据处理方式和数据封装方式。控制部分核心算法将在之后的更新中讲解。
ControlComponent的功能为载入参数,处理订阅话题,封装信息并将其传递给子模块处理;
子模块得到路径、底盘、定位、Pad信息计算得到控制量,之后ControlComponent会发布子模块的计算结果控制量信息。
一、ControlComponent
1、启动文件解析
control.launch
:launch文件功能为调用control.dag
<cyber><module><name>control</name><dag_conf>/apollo/modules/control/dag/control.dag</dag_conf><process_name>control</process_name></module>
</cyber>
control.dag
功能:
- 启动
ControlComponent
组件函数(就是启动其生成的动态链接库文件libcontrol_component.so) flag_file_path
参数文件载入(⭐2
中会详述Apollo载入参数的方式)- interval: 10(程序每10ms调用一次
Proc()
函数,细节参考附表一)
module_config {module_library : "/apollo/bazel-bin/modules/control/libcontrol_component.so"timer_components {class_name : "ControlComponent"config {name: "control"flag_file_path: "/apollo/modules/control/conf/control.conf"interval: 10}}
}
2、ControlComponent()组件函数解析
1)ControlComponent::ControlComponent() 构造函数
监视器注册,控制模块出现ERROR由监视器输出
2)ControlComponent::Init() 初始化函数(执行一次)
- 车辆位置信息,利用此指针获取车辆状态和位置信息(⭐1详解)
#include "modules/control/common/dependency_injector.h"// 定义共享指针,子程序可以使用指针获取车辆状态信息,如controller_agent_.Init(injector_, &control_conf_)
injector_ = std::make_shared<DependencyInjector>();// 函数使用,利用订阅的底盘信息和定位信息更新车辆状态信息
injector_->vehicle_state()->Update(local_view->localization(),local_view->chassis());
- 参数文件载入(⭐2详解)
- controller_agent_.Init(injector_, &control_conf_),初始化子程序
- 订阅/发布话题:订阅话题包括底盘信息、轨迹信息、定位信息和Pad信息;发布话题包括
local_view_
信息(⭐3详解)和控制命令信息。
其中,Pad信息包括驾驶模式{人工,自主驾驶等}和驾驶行为{停止,启动,} - 睡眠1s,等待定位、规划模块channel消息。
3)ControlComponent::Proc() 初始化函数(执行间隔10ms,频率100Hz)
-
发布/订阅回调函数调用
-
ProduceControlCommand()计算控制命令函数
- CheckInput(&local_view_);若输入数据没有问题,则更新车辆状态获取器信息
- CheckTimestamp(local_view_):检查数据时间戳是否有问题,监视某一模块是否太久未更新数据
- estop判定:根据输入数据判断是否需要紧急停车。若不需要紧急停车,调用子程序计算控制量
controller_agent_.ComputeControlCommand(&local_view_.localization(), &local_view_.chassis(),&local_view_.trajectory(), control_command);
- 设置车辆灯光信号(根据路径中的灯光信息)local_view_.trajectory().decision().vehicle_signal()
-
控制消息Header赋值、Latency时延记录
-
控制命令发送:control_cmd_writer_->Write(control_command);
二、⭐
详解
⭐1
:车辆状态信息获取器
功能:将定位数据和底盘数据信息整合成一个新的类,便于子程序调用。比如injector_->vehicle_state()->x()
就是从定位信息localization
得到的x位置,injector_->vehicle_state()->gear()
就是从底盘信息chassis
得到的档位信息。
举例(与下面代码注释结合阅读):
- 初始化:妈妈为厨房配备了钥匙,这个钥匙就是共享指针
injector_
,厨房就是vehicle_state()
,妈妈把钥匙给了我们,我们自己新配了一把钥匙,现在我们可以随意吃厨房里面的东西了。 - 车辆状态信息更新:妈妈买了水果
local_view->localization()
和蔬菜local_view->chassis()
,对买的东西洗洗涮涮之后injector_->vehicle_state()->Update();
。因为我们已有厨房的钥匙,所以可以随便吃里面的水果蔬菜。
#include "modules/control/common/dependency_injector.h"// 定义共享指针,厨房钥匙
injector_ = std::make_shared< DependencyInjector >();// 子程序可以使用指针获取车辆状态信息
// 妈妈把钥匙给了我们,我们自己新配了一把钥匙,现在我们可以随意吃厨房里面的东西了
controller_agent_.Init(injector_, &control_conf_)// 函数调用,利用订阅的底盘信息和定位信息更新车辆状态信息
// 妈妈洗好水果和蔬菜,我们通过之前的钥匙可以随意吃
injector_->vehicle_state()->Update(local_view->localization(),local_view->chassis());
class DependencyInjector
文件位置’‘modules/control/common/dependency_injector.h’’
举例:根据按照钥匙匹配厨房的过程,没有含金量,厨房内的操作才是重点
#pragma once
#include "modules/common/vehicle_state/vehicle_state_provider.h"namespace apollo {
namespace control {class DependencyInjector {public:DependencyInjector() = default;~DependencyInjector() = default;apollo::common::VehicleStateProvider* vehicle_state() {return &vehicle_state_;}private:apollo::common::VehicleStateProvider vehicle_state_;
};
} // namespace control
}
class VehicleStateProvider
文件位置:‘‘modules/common/vehicle_state/vehicle_state_provider.h’’
举例:厨房内操作,重点。Update()
函数处理定位和底盘信息,相当于厨房洗水果的过程。
class VehicleStateProvider {public:/* 利用车辆定位信息和车辆底盘信息更新车辆状态信息状态信息 = 定位信息 + 底盘信息定位信息:时间戳、位置信息 {x y z}、航向角 heading、角速度 angular_velocity、加速度 linear_acceleration、欧拉角 {roll yaw pitch}底盘信息:档位、车速、转向、驾驶模式{人工、完全自动驾驶、仅转向、仅油门刹车}*/ Status Update(const localization::LocalizationEstimate& localization,const canbus::Chassis& chassis);// 以当前位置和航向角为计算基准,假设速度、加速度、加速度信息不变// 函数功能:预测未来t时刻车辆位置信息math::Vec2d EstimateFuturePosition(const double t) const;// center of mass(COM) 车辆质心 // 定位数据的参照坐标系为后轴,函数通过质心和后轴相对位置计算质心位置math::Vec2d ComputeCOMPosition(const double rear_to_com_distance) const;
}
⭐2
:参数文件载入
控制模块所有使用到的参数信息都可以从下面四种方式之一得到:
- 终端配置参数文件
- 全局配置文件定义
- 控制模块配置文件定义
(此种载入方式需要重点掌握)
- 程序配置参数文件
- 全局参数
- 控制模块参数
(1)终端配置参数文件
首先,dag文件中命令flag_file_path: "/apollo/modules/control/conf/control.conf"
,所有参数从这里载入,内容如下:
control.conf
文件
--flagfile=/apollo/modules/common/data/global_flagfile.txt
--control_conf_file=/apollo/modules/control/conf/control_conf.pb.txt
--enable_speed_station_preview=false
--enable_interpolation_by_time=false
--use_preview_speed_for_table=false
--enable_gain_scheduler=true
--set_steer_limit=true
--enable_slope_offset=false
--enable_maximum_steer_rate_limit=false--state_transform_to_com_reverse=true
--state_transform_to_com_drive=true
--trajectory_transform_to_com_reverse=true
--trajectory_transform_to_com_drive=true
--enable_feedback_augment_on_high_speed=false
# --reverse_heading_vehicle_state=false
# --reverse_heading_control=false--query_time_nearest_point_only=false
--query_forward_time_point_only=false
# --use_control_submodules=true
- 全局配置文件定义:global_flagfile.txt
包括车辆参数配置信息、地图目录等全局信息
--vehicle_config_path=/apollo/modules/common/data/vehicle_param.pb.txt--log_dir=/apollo/data/log--use_navigation_mode=false--map_dir=/apollo/modules/map/data/sunnyvale_loop--use_sim_time=false--use_cyber_time=true--map_dir=/apollo/modules/map/data/sunnyvale--map_dir=/apollo/modules/map/data/sunnyvale_big_loop
- 控制模块配置文件定义:control_conf.pb.txt
主要是控制器参数配置信息,包括横向控制器、纵向控制器参数,其通过程序可载入配置文件话题消息
// FLAGS_control_conf_file参数为"/apollo/modules/control/conf/control_conf.pb.txt"
// control_conf_类型为:ControlConf control_conf_;其对应的是"modules/control/proto/control_conf.pb.h"
ACHECK(cyber::common::GetProtoFromFile(FLAGS_control_conf_file, &control_conf_))<< "Unable to load control conf file: " + FLAGS_control_conf_file;
分析"/apollo/modules/control/conf/control_conf.pb.txt"和"modules/control/proto/control_conf.pb"两个文件可以知道其中的参数内容都是一一对应的,Apollo通过调用GetProtoFromFile()
函数这样的方式载入参数信息
(2)程序配置参数文件
- 全局参数:modules/common/adapters/adapter_gflags.h
全局参数是指所有的Apollo程序均使用同样的参数,比如FLAGS_chassis_topic
就是指规划、控制等模块都使用"/apollo/canbus/chassis"这个参数; - 控制模块参数:modules/control/common/control_gflags.h
控制模块参数是仅控制模块使用的,比如chassis_pending_queue_size 缓冲序列大小
控制模块设为10,然而规划等其他模块可以设置20等其他数字。
代码实例:程序配置参数采用Google的gflags方法。定义时采用DECLARE_string(chassis_topic)、DECLARE_int32等声明变量;引用时通过添加FLAG_比如FLAGS_chassis_topic
引用变量。
cyber::ReaderConfig chassis_reader_config;chassis_reader_config.channel_name = FLAGS_chassis_topic;chassis_reader_config.pending_queue_size = FLAGS_chassis_pending_queue_size;chassis_reader_ =node_->CreateReader<Chassis>(chassis_reader_config, nullptr);ACHECK(chassis_reader_ != nullptr);
modules/common/adapters/adapter_gflags.h
#pragma once
#include "gflags/gflags.h"DECLARE_string(chassis_topic);
DEFINE_string(chassis_topic, "/apollo/canbus/chassis", "chassis topic name");
modules/control/common/control_gflags.h
#pragma once
#include "gflags/gflags.h"DECLARE_int32(chassis_pending_queue_size);
DEFINE_int32(chassis_pending_queue_size, 10, "Max chassis pending queue size");
⭐3
local_view_解析
消息类型定义:modules/control/proto/local_view.proto
可以发现,LocalView 包括了底盘、轨迹、定位和Pad所有的订阅信息,一是为了方便数据的记录,可以将控制模块接收的数据统统通过此话题输出;而是通过一个统一的类管理数据,计算控制命令时,直接将LocalView 赋值给子模块。
syntax = "proto2";package apollo.control;import "modules/common_msgs/chassis_msgs/chassis.proto";
import "modules/common_msgs/basic_msgs/header.proto";
import "modules/common_msgs/control_msgs/pad_msg.proto";
import "modules/common_msgs/localization_msgs/localization.proto";
import "modules/common_msgs/planning_msgs/planning.proto";message LocalView {optional apollo.common.Header header = 1;optional apollo.canbus.Chassis chassis = 2;optional apollo.planning.ADCTrajectory trajectory = 3;optional apollo.localization.LocalizationEstimate localization = 4;optional PadMessage pad_msg = 5;
}
附表
附表1
interval : 10
:Proc()
函数调用的时间间隔为10ms
module_config {module_library : "/apollo/bazel-bin/cyber/examples/timer_component_example/libtimer_component_example.so"timer_components {class_name : "TimerComponentSample"config {name : "timer"interval : 10}}
}
修改cyber/examples/timer_component_example/timer_component_example.cc文件,在Proc()
函数中输出函数执行时刻,验证interval为时间间隔
bool TimerComponentSample::Proc() {std::cout<<Clock::Now()<<std::endl;return true;
}
interval:10
、interval:100
、interval:1000
函数输出结果如下所示:
// interval:10
[timer ] 2023-03-02 17:48:44.938106762
[timer ] 2023-03-02 17:48:44.948118645
[timer ] 2023-03-02 17:48:44.958135355
[timer ] 2023-03-02 17:48:44.968064614
[timer ] 2023-03-02 17:48:44.978042423// interval:100
[timer ] 2023-03-02 17:49:14.709280940
[timer ] 2023-03-02 17:49:14.809260363
[timer ] 2023-03-02 17:49:14.909275953
[timer ] 2023-03-02 17:49:15.008942734
[timer ] 2023-03-02 17:49:15.109091507// interval:1000
[timer ] 2023-03-02 17:49:41.278162660
[timer ] 2023-03-02 17:49:42.277118315
[timer ] 2023-03-02 17:49:43.279148986
[timer ] 2023-03-02 17:49:44.279295854
[timer ] 2023-03-02 17:49:45.279386135
相关文章:

Apollo控制部分1-- ControlComponent组件介绍
Apollo控制部分1-- ControlComponent组件介绍摘要一、ControlComponent1、启动文件解析2、ControlComponent()组件函数解析1)ControlComponent::ControlComponent() 构造函数2)ControlComponent::Init() 初始化函数(执行一次)3&am…...

0626-0631韩顺平Java Buffered字节处理流 学习笔记
如何去构建字节流package com.hspedu.outputstream_;import java.io.*;/*** author abner* version 1.0*/ public class BufferedCopy02 {public static void main(String[] args) {String srcFilePath "D:\\Users\\Pictures\\Camera Roll\\Pierre-Auguste_Renoir,_Le_Mo…...

【网络】序列化和反序列化
🥁作者: 华丞臧. 📕专栏:【网络】 各位读者老爷如果觉得博主写的不错,请诸位多多支持(点赞收藏关注)。如果有错误的地方,欢迎在评论区指出。 推荐一款刷题网站 👉 LeetCode刷题网站 文章…...

【代码随想录训练营】【Day32】第八章|贪心算法|122.买卖股票的最佳时机II |55. 跳跃游戏|45.跳跃游戏II
买卖股票的最佳时机II 题目详细:LeetCode.122 买卖股票的最佳时机,怎么都能够想出来个思路,假如我们每天都能预知明天的股票是涨是降,那么贪心策略就是在涨之前买股票,在降的前一天卖掉,这就是买卖股票的…...

constexpr 和 常量表达式
👀👀常量表达式 常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。 字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。 那么是什么来就决定是不是常量表达式呢?一个对象是不是常量表达式主要…...

Vue响应式原理————Object.defineProperty()和proxy的用法分享
Vue框架一个比较核心的功能就是我们的数据是响应式的,这样我们在修改数据的时候,页面会自动帮我们更新,那么想要实现这个功能就要实现对一个数据的劫持,即在取值和设置值的同时我们能够检测到即数据劫持。vue2响应式的实现原理所依…...

CSDN 编程竞赛三十四期题解
竞赛总览 CSDN 编程竞赛三十四期:比赛详情 (csdn.net) 本期的题目和第三十一期竞赛的题目竟然高度重合,真不知道该写点什么了。 不过,上次那道测试数据有bug的题已经修复了,答题过程挺顺利的,没有遇到新的问题。 竞…...

C#教程06 运算符
文章目录 一、算术运算符加法运算符(+)减法运算符(-)乘法运算符(*)除法运算符(/)二、逻辑运算符与运算符(&&)或运算符(||)非运算符(!)三、比较运算符等于运算符(==)大于运算符(>)小于运算符(<)大于等于运算符(>=)小于等于运算符(<=…...

软测入门(六)pytest单元测试
pytest pytest是python的一种单元测试框架,同自带的unit test测试框架类似,但pytest更简洁高效。 单元测试: 测试 函数、类、方法能不能正常运行测试的结果是否符合我们的预期结果 安装 pip install -U pytest基本使用 通过pytest包使用…...

经典分类模型回顾5—DenseNet实现图像分类(matlab)
DenseNet,全称为Densely Connected Convolutional Networks,中文名为密集连接卷积网络,是由李沐等人在2017年提出的一种深度神经网络架构。 DenseNet旨在解决深度神经网络中的梯度消失问题和参数数量过多的问题,通过构建密集连接…...

基于flask+bootstrap+echarts+mysql的鱼村小馆订餐后台管理系统
📋 个人简介 💖 作者简介:大家好,我是阿牛,全栈领域优质创作者。😜📝 个人主页:馆主阿牛🔥🎉 支持我:点赞👍收藏⭐️留言Ὅ…...

Spark使用Log4j将日志发送到Kafka
文章目录自定义KafkaAppender修改log4j.properties配置启动命令配置添加参数启动之后可以在Kafka中查询发送数据时区问题-自定义实现JSONLayout解决自定义JSONLayout.java一键应用可能遇到的异常ClassNotFoundException: xxx.KafkaLog4jAppenderUnexpected problem occured dur…...

c++类与对象整理(上)
目录 1.类的引入 2.类的定义 3.类的访问限定符及封装 1)访问限定符 2)封装 4.类的作用域 5.类的实例化 6.类的对象大小的计算 1)类对象的存储方式 2)内存对齐和大小计算 编辑 7.类成员函数的this指针 1)…...

Docker学习(十九)什么是镜像的元数据?
在 Docker 中,镜像的元数据是指与镜像相关的所有信息,包括镜像的名称和标签、作者、描述、创建日期、环境变量、命令等。这些信息都是通过 Dockerfile 或命令行创建和指定的。 镜像的元数据被存储在 Docker Registry 中,并在使用 docker pull…...

Python如何获取弹幕?给你介绍两种方式
前言 弹幕可以给观众一种“实时互动”的错觉,虽然不同弹幕的发送时间有所区别,但是其只会在视频中特定的一个时间点出现,因此在相同时刻发送的弹幕基本上也具有相同的主题,在参与评论时就会有与其他观众同时评论的错觉。 在国内…...

JAVA- AOP 面向切面编程 Aspect切面工具类 记录特定方法执行时的入参、执行时间、返参等内容
背景:JAVA项目,使用AOP对指定函数进行切面。能够记录特定方法执行时的入参、执行时间、返参结果等内容。 文章目录1、自定义注解类1.1 Target1.2 Retention2、Aspect切面工具2.1 JointPoint2.2 Pointcut2.3 切面中的相关注解3、同一个类里调用AOP4、其他…...

「史上最全的 TCG 规范解读」TCG 规范架构概述(下)
可信计算组织(Ttrusted Computing Group,TCG)是一个非盈利的工业标准组织,它的宗旨是加强不同计算机平台上计算环境的安全性。TCG 于 2003 年春成立,并采纳了由可信计算平台联盟(the Trusted Computing Platform Allia…...

GDScript 导出变量 (4.0)
概述 导出变量的功能在3.x版本中也是有的,但是4.0版本对其进行了语法上的改进。 导出变量在日常的游戏制作中提供节点的自定义参数化调节功能时非常有用,除此之外还用于自定义资源。 本文是(Bilibili巽星石)在4.0官方文档《GDScr…...

JAVA知识点全面总结6:泛型反射和注解
六.JAVA知识点全面总结6泛型反射和注解 1.什么是泛型?可以用在哪里? 2.泛型擦除机制是什么?为什么擦除? 3.通配符是什么?作用是什么? 未更新 1.注解是什么?有什么用? 2.注解的自定义和实…...

死代码删除(DCE,Dead Code Elimination)和激进的死代码删除(ADCE,Aggressive DCE)
死代码删除(DCE,Dead Code Elimination)和激进的死代码删除(ADCE,Aggressive DCE)死代码删除(DCE,Dead Code Elimination)DCE简介DCE基本算法激进的死代码删除࿰…...

询问new bing关于android开发的15个问题(前景、未来、发展方向)
前言:new bing是基于chat-gpt的新搜索工具,可以采用对话方式进行问题搜索,经过排队等候终于可以使用new bing,询问了目前我最关心的关于android开发几个问题 文章目录1.如何学好android开发?2.android开发能做什么?3.…...

【C++】初识类和对象
🏖️作者:malloc不出对象 ⛺专栏:C的学习之路 👦个人简介:一名双非本科院校大二在读的科班编程菜鸟,努力编程只为赶上各位大佬的步伐🙈🙈 目录前言一、面向过程和面向对象初步认识二…...

EPICS S7nodave手册
第一章:介绍 本手册分为6章(不算次介绍部分)。第一章介绍s7nodave用于EPICS的设备支持的概念和特新。第二章描述启动一个使用s7nodave的IOC项目所需要的几步。第三章描述s7nodave支持的IOC shell命令。之后,第四章解释s7nodave支持的各种记录类型。最后…...

2023最新版本RabbitMQ的持久化和简单使用
上节讲了 RabbitMQ下载安装教程 , 本节主要介绍RabbitMQ的持久化和简单使用。 一、RabbitMQ消息持久化 当处理一个比较耗时得任务的时候,也许想知道消费者(consumers)是否运行到一半就挂掉。在当前的代码中,当RabbitM…...

函数式编程
函数式编程(一) 文章目录函数式编程(一)1. 前言1.1 概念2. Lambda 表达式2.1 概述2.2 基本的格式2.3 触发条件2.4 Lambda表达式2.4.1 无参无返回值2.4.2 有参无返回值2.4.3 无参数有返回值2.4.4 有参有返回值【重点】2.4.4.1 比较…...

【Java 类】001-访问修饰符、命名规范
【Java 类】001-访问修饰符、命名规范 文章目录【Java 类】001-访问修饰符、命名规范一、访问修饰符概述1、是什么2、作用作用问题3、访问修饰符有哪些4、作用对象二、访问修饰符使用演示1、类访问修饰符演示第一步:创建 Dog 类:public第二步:…...

【C++】命名空间
🏖️作者:malloc不出对象 ⛺专栏:C的学习之路 👦个人简介:一名双非本科院校大二在读的科班编程菜鸟,努力编程只为赶上各位大佬的步伐🙈🙈 目录前言一、命名空间产生的背景二、命名空…...

【AutoSAR】【MCAL】Dio
一、结构 二、功能介绍 DIO(数字输入输出)驱动模块主要是对端口(Port),通道(Channel)和通道组(ChannelGroup)进行读写操作。 通道(Channel)&…...

瑞吉外卖——day2
目录 一、新增员工 二、查询分页数据 三、启用、禁用员工账户、编辑员工信息 一、新增员工 点击左上角新增员工 页面如下: 我们随便填数据 ,点击保存,请求的地址如下 返回前端可以看到请求方式为Post 在employeeController中编写对应的代…...

了解java
#常见编程语言介绍 C语言 C语言 java语言 javaScript语言 PHP语言 python语言Object-C和Swift语言 C# (c sharp)语言 Kotlin语言 Go语言 Basic语言 #JAVA的发展 起源于1991年SUN公司GREEN项目,1996年JDK1.0正式发布 后被Oracle公司收购&…...