0%

apollo canbus study

canbus

底层can

CanClient是底层can的抽象类,表示某一种can设备的接口

1
2
3
4
5
6
7
8
class CanClient {
virtual bool Init(const CANCardParameter &parameter) = 0;
virtual apollo::common::ErrorCode Start() = 0;
virtual apollo::common::ErrorCode Send(const std::vector<CanFrame> &frames,
int32_t *const frame_num) = 0;
virtual apollo::common::ErrorCode Receive(std::vector<CanFrame> *const frames,
int32_t *const frame_num) = 0;
}

can client由工厂模式创建,不同参数指定不同 can client

1
2
3
auto can_factory = CanClientFactory::Instance();
can_factory->RegisterCanClients();
can_client_ = can_factory->CreateCANClient(canbus_conf_.can_card_parameter());

以socket为例

1
class SocketCanClientRaw : public CanClient

继承了CanClient,实现了其中的虚函数,主要就是调用linux原生的socket api

底盘数据抽象

不同车辆底盘数据、协议不同,使用了vehicle factory来创建不同车辆的 factory

1
2
3
4
VehicleFactory vehicle_factory;
vehicle_factory.RegisterVehicleFactory();
auto vehicle_object =
vehicle_factory.CreateVehicle(canbus_conf_.vehicle_parameter());

每一个车型的factory拥有自己的 controller 和 message manager

1
2
message_manager_ = vehicle_object->CreateMessageManager();
vehicle_controller_ = vehicle_object->CreateVehicleController();

其中controller似乎用于填pb等等事情的

message_manager则用于管理各个信号的decode与encode

以”ch vehicle”为例子,

工厂类:

1
class ChVehicleFactory : public AbstractVehicleFactory

controller类:

1
class ChController final : public VehicleController

message manager类:

1
class ChMessageManager : public MessageManager<::apollo::canbus::ChassisDetail>

先看下message manager的构造:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ChMessageManager::ChMessageManager() {
// Control Messages
AddSendProtocolData<Brakecommand111, true>();
AddSendProtocolData<Controlcommand115, true>();
AddSendProtocolData<Gearcommand114, true>();
AddSendProtocolData<Steercommand112, true>();
AddSendProtocolData<Throttlecommand110, true>();
AddSendProtocolData<Turnsignalcommand113, true>();

// Report Messages
AddRecvProtocolData<Brakestatus511, true>();
AddRecvProtocolData<Ecustatus1515, true>();
AddRecvProtocolData<Ecustatus2516, true>();
AddRecvProtocolData<Ecustatus3517, true>();
AddRecvProtocolData<Gearstatus514, true>();
AddRecvProtocolData<Steerstatus512, true>();
AddRecvProtocolData<Throttlestatus510, true>();
AddRecvProtocolData<Turnsignalstatus513, true>();
}

可以看到message manager中添加了该vehicle的各个收发信号

Brakestatus511信号为例

1
2
class Brakestatus511 : public ::apollo::drivers::canbus::ProtocolData<
::apollo::canbus::ChassisDetail>

实现了 parse函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Brakestatus511::Parse(const std::uint8_t* bytes, int32_t length,
ChassisDetail* chassis) const {
chassis->mutable_ch()->mutable_brake_status__511()->set_brake_pedal_en_sts(
brake_pedal_en_sts(bytes, length));
chassis->mutable_ch()->mutable_brake_status__511()->set_brake_pedal_sts(
brake_pedal_sts(bytes, length));
chassis->mutable_ch()->mutable_brake_status__511()->set_brake_err(
brake_err(bytes, length));
chassis->mutable_ch()->mutable_brake_status__511()->set_emergency_btn_env(
emergency_btn_env(bytes, length));
chassis->mutable_ch()->mutable_brake_status__511()->set_front_bump_env(
front_bump_env(bytes, length));
chassis->mutable_ch()->mutable_brake_status__511()->set_back_bump_env(
back_bump_env(bytes, length));
chassis->mutable_ch()->mutable_brake_status__511()->set_overspd_env(
overspd_env(bytes, length));
chassis->mutable_check_response()->set_is_esp_online(
brake_pedal_en_sts(bytes, length) == 1);
}

某个信号的解析如下,这里就是从can frame中按照dbc定义的信号格式解析了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// config detail: {'description': 'brake pedal enable bit(Status)', 'enum': {0:
// 'BRAKE_PEDAL_EN_STS_DISABLE', 1: 'BRAKE_PEDAL_EN_STS_ENABLE', 2:
// 'BRAKE_PEDAL_EN_STS_TAKEOVER'}, 'precision': 1.0, 'len': 8, 'name':
// 'brake_pedal_en_sts', 'is_signed_var': False, 'offset': 0.0,
// 'physical_range': '[0|1]', 'bit': 0, 'type': 'enum', 'order': 'intel',
// 'physical_unit': ''}
Brake_status__511::Brake_pedal_en_stsType Brakestatus511::brake_pedal_en_sts(
const std::uint8_t* bytes, int32_t length) const {
Byte t0(bytes + 0);
int32_t x = t0.get_byte(0, 8);
Brake_status__511::Brake_pedal_en_stsType ret =
static_cast<Brake_status__511::Brake_pedal_en_stsType>(x);
return ret;
}

再来看看controller类的实现,有一个重要函数

1
2
3
4
5
/**
* @brief calculate and return the chassis.
* @returns a copy of chassis. Use copy here to avoid multi-thread issues.
*/
Chassis chassis() override;

主要做的事情就是从message_manager中获得sensor data,然后填到自己的Chassis chassis_;变量中并返回,后面可以看到sensor data其实是前面parse函数填的内容

1
2
ChassisDetail chassis_detail;
message_manager_->GetSensorData(&chassis_detail);

总结一下,单以接收can信号为例,几个关键点

一种车型对应一个factory,该facotry会产生controller和message manager对象

其中 message manager封装了车身信号的decode和encode函数

controller则负责从message manager中获取解析后的数据,并存到Chassis chassis_(这是一个pb 结构体),然后提供API给外部使用

真正的报文接收处理流程

can报文的接收处理由CanReceiver类管理

CanReceiver由can_client和message manager初始化

并维护一个接收线程

1
2
template <typename SensorType>
void CanReceiver<SensorType>::RecvThreadFunc()

在这个线程loop中

使用can_client类的接口接收can frame,这里实际就会调用到socket api

1
can_client_->Receive(&buf, &frame_num)

使用message manager 解析刚刚收到的can frame,这里实际就会调用到对应message manager中的信号解析函数

1
pt_manager_->Parse(uid, data, len); //以Brakestatus511信号为例就是上面贴出来的parse函数了

在这步parse之后,数据已经填到sensor data了

数据的发布

CanBusComponent类:

1
2
3
4
5
6
void CanbusComponent::PublishChassis() {
Chassis chassis = vehicle_controller_->chassis();
common::util::FillHeader(node_->Name(), &chassis);
chassis_writer_->Write(chassis);
ADEBUG << chassis.ShortDebugString();
}

从controller中调用chassis接口,得到chassis数据,然后就使用protobuf writer发布出去了