Apollo控制部分1-- ControlComponent组件介绍

news2024/12/23 17:26:26

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. 车辆位置信息,利用此指针获取车辆状态和位置信息(⭐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());
  1. 参数文件载入(⭐2详解)
  2. controller_agent_.Init(injector_, &control_conf_),初始化子程序
  3. 订阅/发布话题:订阅话题包括底盘信息、轨迹信息、定位信息和Pad信息;发布话题包括local_view_信息(⭐3详解)和控制命令信息。
    其中,Pad信息包括驾驶模式{人工,自主驾驶等}和驾驶行为{停止,启动,}
  4. 睡眠1s,等待定位、规划模块channel消息。

3)ControlComponent::Proc() 初始化函数(执行间隔10ms,频率100Hz)

  1. 发布/订阅回调函数调用

  2. 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()
  3. 控制消息Header赋值、Latency时延记录

  4. 控制命令发送:control_cmd_writer_->Write(control_command);

二、详解

⭐1:车辆状态信息获取器

功能:将定位数据和底盘数据信息整合成一个新的类,便于子程序调用。比如injector_->vehicle_state()->x()就是从定位信息localization得到的x位置,injector_->vehicle_state()->gear()就是从底盘信息chassis得到的档位信息。
举例(与下面代码注释结合阅读):

  1. 初始化:妈妈为厨房配备了钥匙,这个钥匙就是共享指针injector_ ,厨房就是vehicle_state(),妈妈把钥匙给了我们,我们自己新配了一把钥匙,现在我们可以随意吃厨房里面的东西了。
  2. 车辆状态信息更新:妈妈买了水果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. 全局配置文件定义
    2. 控制模块配置文件定义(此种载入方式需要重点掌握)
  • 程序配置参数文件
    1. 全局参数
    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
  1. 全局配置文件定义: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
  1. 控制模块配置文件定义: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 : 10Proc()函数调用的时间间隔为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:10interval:100interval: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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/389508.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分享四个前端Web3D动画库在Threejs中使用的动画库以及优缺点附地址

Threejs中可以使用以下几种动画库&#xff1a;Tween.js&#xff1a;Tween.js是一个简单的缓动库&#xff0c;可以用于在three.js中创建简单的动画效果。它可以控制数值、颜色、矢量等数据类型&#xff0c;并提供了多种缓动函数&#xff0c;例如线性、弹簧、强化、缓冲等等。区别…

Linux性能学习(2.3):内存_为什么分配的内存比申请的内存大16个字节

文章目录1 验证申请不同内存&#xff0c;系统分配机制1.1 代码1.2 测试1.3 结论2 为什么会多分配内存3 为什么会有4字节不可使用参考资料&#xff1a;https://www.gnu.org/software/libc/ 在上一篇文章中&#xff0c;探讨了Linux系统对进程以及线程的内存分配问题&#xff0c;…

流程图简介

一、流程与流程图1. 什么是流程具体来说&#xff0c;流程是一项活动或一系列连续有规律的事项或行为进行的程序。流程有6个要素&#xff0c;分别是&#xff1a;资源、过程、结构、结果、对象和价值。一个流程会把这些基本要素串联起来&#xff0c;例如流程中资源的输入、流程中…

gprof2dot perf

什么是gprof2dot 这是一个用于将许多探查器的输出转换为点图Python脚本。 使用需要安装的依赖 Python: known to work with version 2.7 and 3.3; it will most likely not work with earlier releases.Graphviz: tested with version 2.26.3, but should work fine with ot…

【C++】类和对象补充知识点

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;C的学习之路 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录前言一、再谈构造函数1.1 构造函数体赋…

逻辑电路代数运算(上)

逻辑代数L是一个封闭的代数系统&#xff0c;由一个逻辑变量集K&#xff0c;常量0和1&#xff0c;以及与或非三种基本运算构成。 参与逻辑运算的变量叫逻辑变量&#xff0c;用字母A&#xff0c;B……表示。每个变量的取值非0 即1。 0、1不表示数的大小&#xff0c;而是代表两种不…

三天吃透Java基础八股文

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址&#xff1a;https://github.com/…

Asp.net core api swagger显示中文注释

在你的 Web API 项目中使用 Swagger 的.NET Core 封装 Swashbuckle 可以帮助你创建良好的文档和帮助页面&#xff0c;Swagger (OpenAPI) 是一个与语言无关的规范&#xff0c;用于描述 REST API。 它使计算机和用户无需直接访问源代码即可了解 REST API 的功能1、OpenAPI 与 Swa…

IP定位离线库有什么作用?

IP离线是什么意思&#xff1f;我们以丢失手机为例来寻找它&#xff0c;现在手机都有IP定位功能&#xff0c;只要手机开通了IP定位&#xff0c;就能找到手机。iPhone定位显示离线一般是iPhone手机关机了或者iPhone手机中“查找我的iPhone”功能关闭了。如果手机在手中的话可以打…

【Spark】Spark的DataFrame向Impala写入数据异常及源码解析

背景 事情是这样的&#xff0c;当前业务有一个场景: 从业务库的Mysql抽取数据到Hive 由于运行环境的网络限制&#xff0c;当前选择的方案&#xff1a; 使用spark抽取业务库的数据表&#xff0c;然后利用impala jdbc数据灌输到hive。&#xff08;没有spark on hive 的条件&…

cmd命令教程

小提示&#xff1a; 在本文中&#xff0c;我将向您展示可以在 Windows 命令行上使用的 40 个命令 温馨提示&#xff1a;在本教程中学习使用适用于 Windows 10 和 CMD 网络命令的最常见基本 CMD 命令及其语法和示例 文章目录为什么命令提示符有用一、cmd是什么&#xff1f;如何在…

AcWing 4868. 数字替换(DFS + 剪枝优化)

AcWing 4868. 数字替换&#xff08;DFS 剪枝优化&#xff09;一、问题二、思路三、代码一、问题 二、思路 题目中要求变换次数最小&#xff0c;其实第一印象应该是贪心&#xff0c;即我们每一次都去成各位中最大的那个数字。但是这个想法很容易推翻。因为你这次乘了一个最大的…

gdb/git的基本使用

热爱编程的你&#xff0c;一定经常徘徊在写bug和改bug之间&#xff0c;调试器也一定是你随影而行的伙伴&#xff0c;离开了它你应该会寝食难安吧&#xff01; 目录 gdb的使用 断点操作 运行调试 观察数据 Git的使用 仓库的创建和拉取 .gitignore “三板斧” 常用指令 gd…

CV——day82 读论文:遥感目标检测的改进注意力特征融合SSD (AF-SSD)方法

遥感目标检测的改进注意力特征融合SSD 方法I. INTRODUCTIONII. RELATED WORKB. 特征融合C.注意力机制III. PROPOSED METHODA. 特性融合模块——**FFM**B.双路径注意模块——DAMC. 多尺度接受域——MRFIV. EXPERIMENTSA. Data Sets and TrainingV. CONCLUSIONAttention and Feat…

mac安装开发工具:clipy、iterm2、go、brew、mysql、redis、wget等

wget brew install wget clipy Releases Clipy/Clipy GitHub 环境变量 ~下有三个文件 .zshrc .zprofile .bash_profile > cat .zshrc export PATH$PATH:/usr/local/mysql/bin> cat .zprofile eval "$(/opt/homebrew/bin/brew shellenv)"> cat .bas…

[1.3.2]计算机系统概述——中断和异常

文章目录第一章 计算机系统概述中断和异常&#xff08;一&#xff09;中断的作用&#xff08;二&#xff09;中断的类型&#xff08;三&#xff09;中断机制的基本原理小结第一章 计算机系统概述 中断和异常 中断的作用中断的类型 内中断&#xff08;也称“异常”&#xff09;…

29- 迁移学习 (TensorFlow系列) (深度学习)

知识要点 迁移学习: 使用别人预训练模型参数时&#xff0c;要注意别人的预处理方式。 常见的迁移学习方式&#xff1a; 载入权重后训练所有参数.载入权重后只训练最后几层参数.载入权重后在原网络基础上再添加一层全连接层&#xff0c;仅训练最后一个全连接层.训练数据是 10_m…

滚蛋吧,正则表达式!

大家好&#xff0c;我是良许。 不知道大家有没有被正则表达式支配过的恐惧&#xff1f;看着一行火星文一样的表达式&#xff0c;虽然每一个字符都认识&#xff0c;但放在一起直接就让人蒙圈了~ 你是不是也有这样的操作&#xff0c;比如你需要使用「电子邮箱正则表达式」&…

面试之String、StringBuffer、StringBuilder区别

String、StringBuffer、StringBuilder区别 (1)是否可变 string对象不可变&#xff1b; StringBuffer、StringBuilder继承自AbstractStringBuilder类&#xff0c;实现原理都基于可修改的char数组&#xff0c;默认大小为16 (2)线程安全性 string中的对象不可变&#xff0c;可…

Java中String类intern()详解

1、背景在开发过程中很多朋友&#xff0c;由于不会正确使用intern()&#xff0c;导致开发的程序&#xff0c;执行效率比较差。同时最近发现一道非常有意思的关于intern()的面试题&#xff0c;这道面试题还是有不小的难度&#xff0c;相信很多朋友看到以后也不知道怎么解答&…