Apollo 应用与源码分析:Monitor监控-硬件监控-CAN监控

news2024/11/27 18:50:58

目录

基本概念

CAN Card

CAN - 原始套接字

ESD CAN 监控分析

Socket Can监控分析


基本概念

CAN Card

首先需要直到CAN的一些基本的概念。

CAN 是Controller Area Network 的缩写(以下称为CAN),是ISO国际标准化的串行通信协议。在汽车产业中,出于对安全性、舒适性、方便性、低功耗、低成本的要求,各种各样的电子控制系统被开发了出来。

CAN卡的CAN总线数据收发由CAN控制器和CAN收发器完成.这种接口的卡在汽车行业中应用广泛,而且在工业控制、机器人、医疗器械、传感器等领域发展迅速。

目前apollo都使用的德国esd的can卡 ESD CAN-PCIe/402-1,apollo1.0-1.5使用的此款can卡。

can卡会有自己的驱动,一般由设备厂商提供,所以这里的CAN监控,其中一个监控就是看这个can的驱动是不是可以输出正确的信号。

CAN - 原始套接字

我们的业务软件想要了解车端的设备状态就需要从can 上读取状态,这里主要使用的就是socket can,Socket CAN采用的即是原始套接字。该接口允许对较底层协议进行操作,如IP、ICMP等。原始套接字常用于检验新的协议实现或访问现有服务中配置的新设备。

套接字的工作流程如下:

先启动服务器,通过调用socket()函数建立一个套接字,然后调用bind()函数将该套接字和本地网络地址联系在一起,再调用listen()函数使套接字做好侦听的准备,并规定它的请求队列的长度,之后就调用accept()函数来接收连接。客户端在建立套接字之后就可调用 connect()和服务器建立连接。连接一旦建立,客户端和服务器之间就可以通过调用recv()/recvfrom()函数和send()/sendto函数来进行发收数据。最后,待数据传送结束后,双方调用close()函数关闭套接字。

参考Link:Linux SocketCAN 编程(C++,启用多线程接收)_地球被支点撬走啦的博客-CSDN博客_linux socketcan

所以apollo 的can 监控中另外一个监控就是针对链路的- can的socket 通信链路。


ESD CAN 监控分析

class EsdCanMonitor : public RecurrentRunner {
 public:
  EsdCanMonitor();
  void RunOnce(const double current_time) override;
};
void EsdCanMonitor::RunOnce(const double current_time) {
  Component* component = apollo::common::util::FindOrNull(
      *MonitorManager::Instance()->GetStatus()->mutable_components(),
      FLAGS_esdcan_component_name);
  if (component == nullptr) {
    // Canbus is not monitored in current mode, skip.
    return;
  }

  auto* status = component->mutable_other_status();
  status->clear_status();
  EsdCanTest(FLAGS_esdcan_id, status);
}

可以看到首先还是判断配置文件是否配置了这个内容,如果没有配置这个监控直接return。

然后就使用EsdCanTest 这个函数检查Can card 的状态,所以核心就在EsdCanTest。

NTCAN_RESULT EsdCanTest(const int can_id, NTCAN_HANDLE* handle) {
  NTCAN_RESULT ret = canOpen(can_id, 0, 1, 1, 0, 0, handle);
  if (ret == NTCAN_SUCCESS) {
    AINFO << "Successfully opened ESD-CAN device " << can_id;
  } else {
    AERROR << "Failed to open ESD-CAN device " << can_id << ", error: " << ret
           << " (" << StatusString(ret) << ")";
    return ret;
  }

  CAN_IF_STATUS if_status;
  ret = canStatus(*handle, &if_status);
  if (ret != NTCAN_SUCCESS) {
    AERROR << "Cannot get status of ESD-CAN, ret=" << ret << " ("
           << StatusString(ret) << ")";
    return ret;
  }

  NTCAN_BUS_STATISTIC stats;
  ret = canIoctl(*handle, NTCAN_IOCTL_GET_BUS_STATISTIC, &stats);
  if (ret != NTCAN_SUCCESS) {
    AERROR << "NTCAN_IOCTL_GET_BUS_STATISTIC failed for device with error: "
           << ret << " (" << StatusString(ret) << ")";
    return ret;
  }

  NTCAN_CTRL_STATE ctrl_state;
  ret = canIoctl(*handle, NTCAN_IOCTL_GET_CTRL_STATUS, &ctrl_state);
  if (ret != NTCAN_SUCCESS) {
    AERROR << "NTCAN_IOCTL_GET_CTRL_STATUS failed for device with error: "
           << ret << " (" << StatusString(ret) << ")";
    return ret;
  }

  NTCAN_BITRATE bitrate;
  ret = canIoctl(*handle, NTCAN_IOCTL_GET_BITRATE_DETAILS, &bitrate);
  if (ret != NTCAN_SUCCESS) {
    AERROR << "NTCAN_IOCTL_GET_BITRATE_ for device with error: " << ret << " ("
           << StatusString(ret) << ")";
    return ret;
  }
  return ret;
}

void EsdCanTest(const int can_id, ComponentStatus* status) {
  NTCAN_HANDLE handle;
  const NTCAN_RESULT ret = EsdCanTest(can_id, &handle);
  canClose(handle);

  SummaryMonitor::EscalateStatus(
      ret == NTCAN_SUCCESS ? ComponentStatus::OK : ComponentStatus::ERROR,
      StatusString(ret), status);
}
#else
// USE_ESD_CAN is not set, do dummy check.
void EsdCanTest(const int can_id, ComponentStatus* status) {
  SummaryMonitor::EscalateStatus(ComponentStatus::ERROR,
                                 "USE_ESD_CAN is not defined during compiling",
                                 status);
}
#endif

这里可以看出,如果发现没有安装CAN 卡的话会直接报错,如果安装了,会调用,canopen打开一个can设备,然后使用canstatus、canIoctl去判断can设备现在的状态,并最终把状态ret进行返回。

如果ret 不为NTCAN_SUCCESS ,就报ERROR,反之就报OK。

Socket Can监控分析

class SocketCanMonitor : public RecurrentRunner {
 public:
  SocketCanMonitor();
  void RunOnce(const double current_time) override;
};

void SocketCanMonitor::RunOnce(const double current_time) {
  auto manager = MonitorManager::Instance();
  Component* component = apollo::common::util::FindOrNull(
      *manager->GetStatus()->mutable_components(),
      FLAGS_socket_can_component_name);
  if (component == nullptr) {
    // Canbus is not monitored in current mode, skip.
    return;
  }
  auto* status = component->mutable_other_status();
  status->clear_status();

  std::string message;
  const bool ret = SocketCanTest(&message);
  SummaryMonitor::EscalateStatus(
      ret ? ComponentStatus::OK : ComponentStatus::ERROR, message, status);
}

一样的套路,第一步检查socket can是不是被配置为监控对象,如果是的话就调用SocketCanTest,对socket can进行检查,并返回ret。

若ret为false就报ERROR故障,反之就报OK的状态。

bool SocketCanTest(std::string* message) {
  const int dev_handler = socket(PF_CAN, SOCK_RAW, CAN_RAW);
  if (dev_handler < 0) {
    *message = "Open can device failed";
    return false;
  }
  const bool ret = SocketCanHandlerTest(dev_handler, message);
  close(dev_handler);
  return ret;
}
  1. socket(PF_CAN, SOCK_RAW, CAN_RAW);就是创建一个can 原生socket
  2. 交给SocketCanHandlerTest做检查
// Test Socket CAN on an open handler.
bool SocketCanHandlerTest(const int dev_handler, std::string* message) {
  // init config and state
  // 1. set receive message_id filter, ie white list
  struct can_filter filter[1];
  filter[0].can_id = 0x000;
  filter[0].can_mask = CAN_SFF_MASK;

  int ret = setsockopt(dev_handler, SOL_CAN_RAW, CAN_RAW_FILTER, &filter,
                       sizeof(filter));
  if (ret < 0) {
    *message = "set message filter failed";
    return false;
  }

  // 2. enable reception of can frames.
  const int enable = 1;
  ret = setsockopt(dev_handler, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable,
                   sizeof(enable));
  if (ret < 0) {
    *message = "Enable reception of can frames failed";
    return false;
  }

  struct ifreq ifr;
  std::strncpy(ifr.ifr_name, "can0", IFNAMSIZ);
  if (ioctl(dev_handler, SIOCGIFINDEX, &ifr) < 0) {
    *message = "ioctl failed";
    return false;
  }

  // bind socket to network interface
  struct sockaddr_can addr;
  addr.can_family = AF_CAN;
  addr.can_ifindex = ifr.ifr_ifindex;
  ret = bind(dev_handler, reinterpret_cast<struct sockaddr*>(&addr),
             sizeof(addr));

  if (ret < 0) {
    *message = "bind socket can failed";
    return false;
  }

  return true;
}

 

  1. 设置过滤器,这里只接收标识符等于0x00的报文,如果设置失败就返回false,并传出异常日志
  2. 启动can帧的接收,如果启动失败就返回false,并传出异常日志
  3. 映射实际的can接口,如果失败就反馈false,并传出异常日志
  4. 把socket绑定到网络接口如果绑定失败就返回false,并传出异常日志
  5. 如果上述都成功就返回true

参考link:can口通信详解_时费的博客-CSDN博客_can口

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

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

相关文章

Elastic Stack 环境配置与框架简介

目录 简介 什么是Elastic Stack Elasticasearch Logstash Kibana Beats 框架图 下载 配置 一、安装java环境 启动 Elasticsearch Kibana FileBeat Logstash 测验 简介 什么是Elastic Stack Elastic Stack缩写为elk&#xff0c;它由三个软件组成&#xff1a;E…

唯品会:高利润,慢增长?

配图来自Canva可画 近日&#xff0c;阿里、京东等互联网大厂纷纷发布了新一季度的财报&#xff0c;从其财报不难看出&#xff0c;国内头部电商平台已经告别了一路狂奔的时代&#xff0c;开始愈发稳健起来。唯品会虽然在体量和规模上都还不能和这两家巨头相比&#xff0c;但自其…

36、Java——吃货联盟订餐系统(JDBC+MySQL+Apache DBUtils)

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;Java案例分…

关于物联网你需要知道的一切

如果你想要一个更像 wiki &#xff08;维基百科&#xff09;的定义「什么是物联网&#xff1f;」&#xff0c;我们可以将其视为连接到 Internet 的全球对象网络&#xff0c;这些对象能够在没有人为干预的情况下&#xff0c;相互交互和交换数据。符合这一的一般定义的解决方案&a…

Java项目:基于jsp+sevlet+mysql日记系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 本项目主要功能有&#xff1a; 写日记 查看日记 日记删除 日记修改 日记类别添加 日记类别修改 日记类别删除 个人信息查看 个人信息修改 分页…

java刷题day 05

一. 单选题&#xff1a; 解析&#xff1a; 5 >> 2 相当于 5除于2两次&#xff0c;等于1>>> 表示无符号右移&#xff0c;高位用 0 填充&#xff0c;0001右移两位 0000&#xff0c;所以选A解析&#xff1a;作对这道题的关键是要理解Java的值传递&#xff0c;关于值…

婚纱租赁系统毕业设计,婚纱租赁管理系统设计与实现,论文毕设作品参考

功能清单 【后台管理员功能】 广告管理&#xff1a;设置小程序首页轮播图广告和链接 留言列表&#xff1a;所有用户留言信息列表&#xff0c;支持删除 会员列表&#xff1a;查看所有注册会员信息&#xff0c;支持删除 资讯分类&#xff1a;录入、修改、查看、删除资讯分类 录入…

【Milvus的以文搜图】

0. 介绍 以文搜图指的是&#xff0c;根据文本描述&#xff0c;从图像数据库中检索与文本内容相似的图像数据并返回。通过在CSDN中搜索以文搜图&#xff0c;找到了如下两篇文章&#xff1a; 从零到一&#xff0c;教你搭建「以文搜图」搜索服务&#xff08;一&#xff09;_Zill…

Linux “挂载” 的概念

0、前言 截至到写这个稿子&#xff0c;始终对挂载的概念有点模糊&#xff0c;到底是硬盘挂载到目录&#xff1f;还是目录挂载到硬盘呢&#xff1f;今天终于从《鸟哥的Linux私房菜》中推断出了答案&#xff0c;而且也恍然大悟地理解了之前书中一句晦涩难懂的话。 1、挂载的概念…

基于Web的Markdown编辑器HedgeDoc

什么是 HedgeDoc &#xff1f; HedgeDoc 是一个开源的、基于 web 的、自托管的、协作的markdown编辑器。您可以使用它轻松地在笔记、图形甚至演示文稿上进行实时协作。用户需要做的就是将你的笔记链接分享给同事&#xff0c;他们就可以开始使用了。 不想自己搭建可以试试官方的…

基于有偏距离权值双线性插值原理(Weighted bilinear with warping)的图像超分辨重构研究-附Matlab程序

⭕⭕ 目 录 ⭕⭕✳️ 一、图像超分辨率重构原理✳️ 二、双线性插值重构理论与实验分析✳️ 2.1 双线性插值理论与实验验证✳️ 2.2 有偏距离双线性插值重构理论与实验验证✳️ 2.3 权重双线性插值理论与实验验证✳️ 2.4 有偏距离权值双线性插值理论与实验验证✳️ 三、参考文…

frps内网穿透

1 原理讲解 frp工作原理 服务端运行&#xff0c;监听一个主端口&#xff0c;等待客户端的连接&#xff1b; 客户端连接到服务端的主端口&#xff0c;同时告诉服务端要监听的端口和转发类型&#xff1b;服务端fork新的进程监听客户端指定的端口&#xff1b; 外网用户连接到客户…

2012-2020中国地区银行多指标数据

1、数据来源&#xff1a;bankscope 2、时间跨度&#xff1a;2012-2020-3季度 3、区域范围&#xff1a;中国 4、指标说明&#xff1a; 包含以下数据&#xff1a; 资产负债表&#xff0c;利润表&#xff0c;流动性表&#xff0c;资本充足率表&#xff0c;财务比率 global s…

java 高级面试题(借鉴)

谈谈ConcurrentHashMap的扩容机制 1.7版本 1. 1.7版本的ConcurrentHashMap是基于Segment分段实现的 2. 每个Segment相对于⼀个⼩型的HashMap 3. 每个Segment内部会进⾏扩容&#xff0c;和HashMap的扩容逻辑类似 4. 先⽣成新的数组&#xff0c;然后转移元素到新数组中 5. 扩容的…

vue3 antd项目实战——table表格(一文带你快速实现后台管理系统最常用的table表格)

零基础filter实现最简单的table表格知识调用核心干货下期预告关键字模糊查找&#xff08;纯前端&#xff09;关键字模糊查找&#xff08;前后交互&#xff09;知识调用 功能实现可能要用到的知识&#xff1a;vue3ant design vuets实战【ant-design-vue组件库引入】vue3项目实战…

超纯水如何除硼,除硼树脂技术分析

硼在超纯水中对晶圆厂的产品良品率的影响&#xff0c;那超纯水深度除硼的方式有哪些呢&#xff0c;在现今新型的微电子、太阳能等行业中&#xff0c;对超纯水的要求越来越高&#xff0c;对超纯水设备中PPb的硼和硅要求达到PPb级。但硼和硅属于弱电离元素&#xff0c;在水中不易…

泛型类的认识 - (了解数据结构的基础)

文章目录前言1. 为什么使用泛型类&#xff1f;2. 泛型类介绍总结前言 本篇通过介绍为什么使用泛型类&#xff0c;什么是泛型类&#xff0c;进一步为以后数据结构的学习打下基础。如有错误&#xff0c;请在评论区指正&#xff0c;让我们一起交流&#xff0c;共同进步&#xff0…

【强化学习论文合集】IJCAI-2021 强化学习论文

强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一,用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现特定目标的问题。 本专栏整理了近几年国际顶级会议中,涉及强化学习(Rein…

户外运动耳机推荐、这几款性能超强的户外运动耳机不可错过

在户外跑步的时候&#xff0c;也有不少朋友会选择戴上耳机&#xff0c;用音乐来”调味“&#xff0c;让跑步的过程不那么枯燥乏味。凡事有利就有弊&#xff0c;跑步时听音乐也如此&#xff0c;它的弊端之一是可能会有安全隐患。如果跑步时耳机音量开得太大&#xff0c;可能会忽…

JAVA-GUI工具的编写-----简易框架篇

好久没写东西了&#xff0c;毕竟一个屁民没那么多东西写的&#xff0c;来来回回就老三样&#xff0c;扯犊子的也不想写&#xff0c;今天给大家来个都感兴趣的-------如何编写自己的GUI工具&#xff1f; 当然了&#xff0c;IDEA怎么去破解&#xff0c;这里就不多比比&#xff0c…