《从0开始搭建实现apollo9.0》系列三 CANBUS模块解读

news2024/11/16 10:18:46

二、CANBUS代码

1、canbus模块的软件架构如下:

在这里插入图片描述
主要输入输出
输入:apollo::control::ControlCommand | 控制指令 输出: /apollo/chassis | apollo::canbus::Chassis | 车辆底盘信息接口数据,包括车辆速度、方向盘转角、档位、底盘状态等信息 |
| /apollo/chassis_detail | apollo::${Vehicle_Type} | 车辆底盘详细信息,展示发送和接收底盘报文解析数据 |
其中canbus文件夹是canbus模块的主程序入口,构造函数为周期触发的函数,周期执行。

class CanbusComponent final : public apollo::cyber::TimerComponent {

构造函数后进入init函数

bool CanbusComponent::Init() {
    AINFO << "CanbusComponent init: ";
    // 加载配置文件
    if (!GetProtoConfig(&canbus_conf_)) {
        AERROR << "Unable to load canbus conf file: " << ConfigFilePath();
        return false;
    }
    AINFO << "The canbus conf file is loaded: " << FLAGS_canbus_conf_file;
    ADEBUG << "Canbus_conf:" << canbus_conf_.ShortDebugString();
    //加载车辆类型
    if (!apollo::cyber::common::PathExists(FLAGS_load_vehicle_library)) {
        AERROR << FLAGS_load_vehicle_library << " No such vehicle library";
        return false;
    }
    AINFO << "Load the vehicle factory library: " << FLAGS_load_vehicle_library;

    ClassLoader loader(FLAGS_load_vehicle_library);
    auto vehicle_object = loader.CreateClassObj<AbstractVehicleFactory>(FLAGS_load_vehicle_class_name);
    if (!vehicle_object) {
        AERROR << "Failed to create the vehicle factory: " << FLAGS_load_vehicle_class_name;
        return false;
    }
    AINFO << "Successfully create vehicle factory: " << FLAGS_load_vehicle_class_name;

    vehicle_object_ = vehicle_object;
    if (!vehicle_object_->Init(&canbus_conf_)) {
        AERROR << "Fail to init vehicle factory.";
        return false;
    }
    AINFO << "Vehicle factory is successfully initialized.";

    // cyber::ReaderConfig guardian_cmd_reader_config;
    // guardian_cmd_reader_config.channel_name = FLAGS_guardian_topic;
    // guardian_cmd_reader_config.pending_queue_size = FLAGS_guardian_cmd_pending_queue_size;

    cyber::ReaderConfig control_cmd_reader_config;
    control_cmd_reader_config.channel_name = FLAGS_control_command_topic;
    control_cmd_reader_config.pending_queue_size = FLAGS_control_cmd_pending_queue_size;

    cyber::ReaderConfig chassis_cmd_reader_config;
    chassis_cmd_reader_config.channel_name = FLAGS_chassis_command_topic;
    chassis_cmd_reader_config.pending_queue_size = FLAGS_control_cmd_pending_queue_size;

    // if (FLAGS_receive_guardian) {
    //     guardian_cmd_reader_ = node_->CreateReader<GuardianCommand>(
    //             guardian_cmd_reader_config, [this](const std::shared_ptr<GuardianCommand> &cmd) {
    //                 ADEBUG << "Received guardian data: run canbus callback.";
    //                 OnGuardianCommand(*cmd);
    //             });
    // } else
    {     
        //订阅topic
        control_command_reader_ = node_->CreateReader<ControlCommand>(
                control_cmd_reader_config, [this](const std::shared_ptr<ControlCommand> &cmd) {
                    ADEBUG << "Received control data: run canbus callback.";
                    OnControlCommand(*cmd);
                });
        chassis_command_reader_ = node_->CreateReader<ChassisCommand>(
                chassis_cmd_reader_config, [this](const std::shared_ptr<ChassisCommand> &cmd) {
                    ADEBUG << "Received control data: run canbus callback.";
                    OnChassisCommand(*cmd);
                });
    }
    // 发布topic
    chassis_writer_ = node_->CreateWriter<Chassis>(FLAGS_chassis_topic);

    if (!vehicle_object_->Start()) {
        AERROR << "Fail to start canclient, cansender, canreceiver, canclient, "
                  "vehicle controller.";
        Clear();
        return false;
    }
    AINFO << "Start canclient cansender, canreceiver, canclient, vehicle "
             "controller successfully.";

    monitor_logger_buffer_.INFO("Canbus is started.");

    return true;
}

收到控制指令后调用回调函数,将控制指令中的油门、刹车、档位、灯光等指令,转换成对应的报文下发至底盘。vehicle_object_为实例化车辆类型。

void CanbusComponent::OnControlCommand(const ControlCommand &control_command) {
    int64_t current_timestamp = Time::Now().ToMicrosecond();
    // if command coming too soon, just ignore it.
    if (current_timestamp - last_timestamp_ < FLAGS_min_cmd_interval * 1000) {
        ADEBUG << "Control command comes too soon. Ignore.\n Required "
                  "FLAGS_min_cmd_interval["
               << FLAGS_min_cmd_interval << "], actual time interval[" << current_timestamp - last_timestamp_ << "].";
        return;
    }

    last_timestamp_ = current_timestamp;
    ADEBUG << "Control_sequence_number:" << control_command.header().sequence_num() << ", Time_of_delay:"
           << current_timestamp - static_cast<int64_t>(control_command.header().timestamp_sec() * 1e6)
           << " micro seconds";

    vehicle_object_->UpdateCommand(&control_command);
}

回调函数跳转至所选车型的内部更新控制指令。

void GemVehicleFactory::UpdateCommand(
    const apollo::control::ControlCommand *control_command) {
  if (vehicle_controller_->Update(*control_command) != ErrorCode::OK) {
    AERROR << "Failed to process callback function OnControlCommand because "
              "vehicle_controller_->Update error.";
    return;
  }
  can_sender_.Update();
}

更新控制指令,赋值自动驾驶模式,并对对加速度、减速度、档位等进行赋值。

ErrorCode VehicleController<SensorType>::Update(const ControlCommand &control_command) {
    if (!is_initialized_) {
        AERROR << "Controller is not initialized.";
        return ErrorCode::CANBUS_ERROR;
    }

    // Execute action to transform driving mode
    AINFO << " control_command.has_pad_msg() " << control_command.has_pad_msg();
    AINFO << " control_command.pad_msg().has_action() " << control_command.pad_msg().has_action();
    if (control_command.has_pad_msg() && control_command.pad_msg().has_action()) {
        AINFO << "Canbus received pad msg: " << control_command.pad_msg().ShortDebugString();
        if (control_command.pad_msg().action() == control::DrivingAction::VIN_REQ) {
            if (!VerifyID()) {
                AINFO << "Response vid failed, please request again.";
            } else {
                AINFO << "Response vid success!";
            }
        } else {
            Chassis::DrivingMode mode = Chassis::COMPLETE_MANUAL;
            switch (control_command.pad_msg().action()) {
            case control::DrivingAction::START: {
                mode = Chassis::COMPLETE_AUTO_DRIVE;
                break;
            }
            case control::DrivingAction::RESET: {
                break;
            }
            default: {
                AERROR << "No response for this action.";
                break;
            }
            }
            auto error_code = SetDrivingMode(mode);
            if (error_code != ErrorCode::OK) {
                AERROR << "Failed to set driving mode.";
            } else {
                AINFO << "Set driving mode success.";
            }
        }
    }
    if (driving_mode() == Chassis::COMPLETE_AUTO_DRIVE || driving_mode() == Chassis::AUTO_SPEED_ONLY) {
        Gear(control_command.gear_location());
        Throttle(control_command.throttle());
        Acceleration(control_command.acceleration());
        Brake(control_command.brake());
        SetEpbBreak(control_command);
        SetLimits();
    }
    if (driving_mode() == Chassis::COMPLETE_AUTO_DRIVE || driving_mode() == Chassis::AUTO_STEER_ONLY) {
        const double steering_rate_threshold = 1.0;
        Steer(control_command.steering_target());
    }
    if ((driving_mode() == Chassis::COMPLETE_AUTO_DRIVE || driving_mode() == Chassis::AUTO_SPEED_ONLY
         || driving_mode() == Chassis::AUTO_STEER_ONLY)
        && control_command.has_signal()) {
        HandleVehicleSignal(ProcessCommandChange(control_command.signal(), &last_control_command_));
    }
    return ErrorCode::OK;
}

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

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

相关文章

Vue Html中插入本地视频(Video 标签)

在 Vue 中插入本地视频可以通过使用标签来实现。你可以将视频文件放在你的项目中的合适位置&#xff08;比如assets文件夹&#xff09;&#xff0c;然后在 Vue 组件中引用这个视频文件。html同理 首先&#xff0c;在你的 Vue 项目中的assets文件夹下放入你的视频文件&#xff…

兼容性比较好的浏览器推荐(2023手机浏览器排名)

浏览器在我们日常工作生活占据着重要的位置。浏览器是电脑的必备软件&#xff0c;也是手机端不可缺少的软件之一。如果你想要下载浏览器&#xff0c;却不知道哪个浏览器最好用&#xff0c;那么就看看本篇文章。下文给大家推荐2023年最热门、好用的手机浏览器&#xff0c;排行不…

计算机网络【网络安全】

计算机网络——网络安全 一、网络安全问题概述 网络安全威胁 网络安全面临两大类威胁&#xff0c;被动攻击和主动攻击 被动攻击 指攻击者从网络上窃听他人的通信内容&#xff0c;通常把这类攻击称为截获。 主动攻击 篡改 攻击者故意篡改网络上传送的报文 恶意程序 拒绝服…

java实现图片转pdf,并通过流的方式进行下载(前后端分离)

首先需要导入相关依赖&#xff0c;由于具体依赖本人也不是记得很清楚了&#xff0c;所以简短的说一下。 iText&#xff1a;PDF 操作库&#xff0c;用于创建和操作 PDF 文件。可通过 Maven 或 Gradle 引入 iText 依赖。 MultipartFile&#xff1a;Spring 框架中处理文件上传的类…

day08_分类品牌管理商品规格管理商品管理

文章目录 1 分类品牌管理1.1 菜单添加1.2 表结构介绍1.3 页面制作1.4 品牌列表加载1.4.1 后端接口BrandControllerBrandServiceBrandMapperBrandMapper.xml 1.4.2 前端对接brand.jscategoryBrand.vue 1.5 分类数据加载1.6 列表查询1.6.1 需求说明1.6.2 后端接口需求分析Categor…

软考基础知识2

1.DMA控制方式&#xff1a;直接内存存取。数据在内存与I/O设备间直接成块传送&#xff0c;不需要CPU的任何干涉&#xff0c;由DMA硬件直接执行完成。 例题&#xff1a; 2.程序计数器总是存下一个指令的地址。 例题&#xff1a; 3.可靠度的计算&#xff1a; 例题&#xff1a…

低碳策略全都有!EI论文:计及电转气协同的含碳捕集与垃圾焚烧虚拟电厂优化调度程序代码!

适用平台&#xff1a;MatlabYalmipCplex 参考文献&#xff1a;《计及电转气协同的含碳捕集与垃圾焚烧虚拟电厂优化调度》-电网技术 程序建立了碳交易市场下的计及电转气协同的含碳捕集与垃圾焚烧虚拟电厂优化调度模型&#xff0c;鉴于该模型具有高维非线性特点&#xff0c;求…

蓝桥杯算法题汇总

一.线性表&#xff1a;链式 例题&#xff1a;旋转链表 二.栈&#xff1a; 例题&#xff1a;行星碰撞问题 三.队列 三.数组和矩阵 例题&#xff1a;

亿道信息轻工业三防EM-T195,零售、制造、仓储一网打尽

厚度仅10.5mm&#xff0c;重量仅0.65千克的EM-T195&#xff0c;其紧凑而纤薄的设计为以往加固型平板带来了全新的轻薄概念。尽管设计时尚、轻薄&#xff0c;但经过军用认证的强固性仍然能够承受所有具有挑战性的环境条件。随身携带无负担的轻便性加上抗震功能使其成为餐厅、酒店…

Spring Initializer环境问题

1.基于jdk8与本地 环境准备 1)下载jdk8并安装 2&#xff09;下载maven 3.6.3并解压放入D盘maven目录下&#xff0c;去掉外层 设置阿里源 打开settings.xml,在mirrors标签之内增加&#xff0c;注意粘贴后</id>中的/有可能被删掉&#xff0c;要自己补上 <mirror>&l…

敏捷开发模型:一种灵活、协作和持续的软件开发方法

敏捷开发模型&#xff1a;一种灵活、协作和持续的软件开发方法 引言 在软件开发领域&#xff0c;随着市场需求的不断变化和技术的迅速发展&#xff0c;传统的瀑布模型逐渐暴露出其局限性。为了应对这些挑战&#xff0c;敏捷开发模型应运而生。敏捷开发模型强调灵活、协作和持…

Java基于springboot的厨艺交流平台的设计与实现代码

摘 要 使用旧方法对厨艺交流信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在厨艺交流信息的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误不能及时纠正等问题。 这次开发的厨艺交流平台功…

华为HCIP Datacom H12-821 卷4

1.单选题 下面哪些策略或工具不能够应用于 OSPF: A、access-list B、prefix-list C、route- Policy D、as-path filter 正确答案&#xff1a; D 解析&#xff1a; as-path-filter命令用来创建AS路径过滤器&#xff0c;OSPF属于IGP协议&#xff0c;不涉及到AS号。 2.单选题…

AI时代,我们需要什么能力?

AI 时代&#xff0c;一定会重构很多行业&#xff0c;也会重构人民的生活工作方式&#xff0c;那么 AI 时代&#xff0c;我们需要培养什么能力呢&#xff1f; 我们应该去做那些 AI 做不了的事情&#xff01;让 AI 成为我们的工具&#xff0c;助力我们更高效的解决问题&#xff…

信息系统项目管理师--项目管理概述

开展项⽬是为了通过可交付成果达成⽬标。⽬标是所指向的结果、要取得的战略地位、要达到的⽬的、要获得的成果、要⽣产的产品或者要提供的服务。 可交付成果形成的独特并可验证的产品、成果或服务。可交付成果可能是有形的&#xff0c;也可能是⽆形的。产⽣⼀个或多个可交付成…

openGauss学习笔记-232 openGauss性能调优-系统调优-资源负载管理-资源管理准备-资源规划

文章目录 openGauss学习笔记-232 openGauss性能调优-系统调优-资源负载管理-资源管理准备-资源规划 openGauss学习笔记-232 openGauss性能调优-系统调优-资源负载管理-资源管理准备-资源规划 完成资源负载管理功能配置前&#xff0c;需要先根据业务模型完成租户资源的规划。业…

矩阵爆破逆向之条件断点的妙用

不知道你是否使用过IDA的条件断点呢&#xff1f;在IDA进阶使用中&#xff0c;它的很多功能都有大作用&#xff0c;比如&#xff1a;ida-trace来跟踪调用流程。同时IDA的断点功能也十分强大&#xff0c;配合IDA-python的输出语句能够大杀特杀&#xff01; 那么本文就介绍一下这…

gpt生成器,批量gpt文章生成器

GPT&#xff08;生成式预训练模型&#xff09;生成器软件在当今的数字化时代扮演着越来越重要的角色&#xff0c;它们通过人工智能技术&#xff0c;可以自动生成各种类型的文章内容&#xff0c;为用户提供了无限的创作可能性。本文将介绍6款不同的GPT生成器软件&#xff0c;并介…

NX二次开发:ListingWindow窗口的应用

一、概述 在NX二次开发的学习中&#xff0c;浏览博客时发现看到[社恐猫]和[王牌飞行员_里海]这两篇博客中写道有关信息窗口内容的打印和将窗口内容保存为txt,个人人为在二次开发项目很有必要&#xff0c;因此做以下记录。 ListingWindow信息窗口发送信息四种位置类型 设置Listi…

LVGL常用部件使用总结之图片部件

图片部件可用于显示图片&#xff0c;图片源可以是 C 语言数组格式的文件、二进制的.bin 文件以及图标字体。值得注意的是&#xff0c;图片部件要显示 BMP、JPEG 等格式的图片&#xff0c;则必须经过解码。 图片部件的组成部分仅有一个&#xff1a;主体&#xff08;LV_PART_MAIN…