CanbusComponent主程序分析
CanbusComponent::Init
CanbusComponent::Init
是程序的入口函数,其功能是完成CanbusComponent
的初始化。
首先通过GetProtoConfig
获得配置文件信息,并保存到canbus_conf_
当中。默认的配置文件modules/canbus/conf/canbus_conf.pb.txt
内容为:
vehicle_parameter {
brand: LINCOLN_MKZ
max_enable_fail_attempt: 5
driving_mode: COMPLETE_AUTO_DRIVE
}
can_card_parameter {
brand: HERMES_CAN
type: PCI_CARD
channel_id: CHANNEL_ID_ZERO
num_ports: 8
interface: NATIVE
}
enable_debug_mode: false
enable_receiver_log: false
enable_sender_log: false
通过工厂模式,根据can_card_parameter
参数创建指定类型的CanClient
can_client_ = can_factory->CreateCANClient(canbus_conf_.can_card_parameter());
根据vehicle_parameter
参数创建指定车型的抽象工厂std::unique_ptr<apollo::canbus::AbstractVehicleFactory
,并根据该工厂创建该车型的MessageManager
和VehicleController
auto vehicle_object =
vehicle_factory.CreateVehicle(canbus_conf_.vehicle_parameter());
...
message_manager_ = vehicle_object->CreateMessageManager();
....
vehicle_controller_ = vehicle_object->CreateVehicleController();
可以看出,使用工厂模式,可以实现程序的松耦合,通过配置文件的参数可以创建的基类接口不同的派生类对象。
当以上对象初始化完成后,会创建该车型需要的所有协议类对象,同时初始化CanReceiver
和CanSender
,并且会在CanSender的容器当中添加所有需要发送的can报文。
根据命令行参数receive_guardian
,可以选择是否开启守护进程,从而订阅不同的话题,命令行参数可以在modules/canbus/conf/canbus.conf
中定义。
最后会调用CanClient
、CanReceiver
、CanSender
和VehicleController
的Start
方法,会打开can端口,分别创建三个线程:
CanReceiver
的线程会不断接收一定数目的can报文,并根据该报文的协议将其解析为消息类型,存储在MessageManager
的数据成员sensor_data_
当中CanSender
的线程,会以各can报文规定的间隔,不断循环发送容器当中保存的所有的can报文VehicleController
线程会当can_sender_开启,执行发送can帧的线程时,以一定的频率,根据自动驾驶模式不断根据底盘反馈消息,检查底盘模块是否正常,若连续出错的次数超出了阈值,则进入紧急模式
CanbusComponent::Proc
该函数会以一定的频率由Cyber_RT调用,该函数会调用chassis
方法,返回在MessageManager
的变量sensor_data_
中存储的当前时刻从底层接收的类型为Chassis
的消息,其类型在modules/canbus/proto/chassis.proto
中定义,然后发送给指定的话题。
另外,可根据命令行参数enable_chassis_detail_pub
选择是否发送ChassisDetail
消息类型至相关话题。
CanbusComponent::OnControlCommand
CanbusComponent::OnControlCommand
是订阅者的回调函数,根据形参列表当中的控制消息ControlCommand
,通过VehicleController
更新所有发送协议的物理量,并通过CanSender
更新所有发送can报文的数据
向车辆底层发送数据
在CanSender
线程当中,所有发送can报文会会不断循环发送给can底层,而发送can报文的更新是根据订阅相关话题得到的控制消息ControlCommand
,通过回调函数CanbusComponent::OnControlCommand
完成的。
首先,向车辆底层发送的消息类型为ControlCommand
,通过订阅者订阅相关话题得到。
然后会调用回调函数CanbusComponent::OnControlCommand
,在其中,方法VehicleController::Update
会根据控制消息类型ControlCommand
更新所有发送协议的物理量,物理量更新完毕后,会调用CanSender<SensorType>::Update
,根据各个can报文的协议的物理量,根据协议更新所有发送can报文的数据。
自动驾驶模式COMPLETE_AUTO_DRIVE
是通过控制消息当中的control_command.pad_msg().action()
控制的,当其为control::DrivingAction::START
时,会打开自动驾驶模式。需要主要的是,在打开自动驾驶模式时,canbus模块会在CheckResponse
函数中,根据底盘反馈信息检查相关模块的工作情况。
该回调函数调用完成后,所有向车辆底层发送的can报文的数据会根据ControlCommand
完成更新。
从车辆底层获取数据
在CanReceiver
线程当中,不断通过CanClient
从底层接收指定数目的can报文,并通过MessageManager
,根据该报文的协议ID将所有接收到的can报文解析为ChassisDetail
消息类型,存储在MessageManager
的sensor_data_
当中,因此sensor_data_
反映了当前时刻从底层获得的底盘数据ChassisDetail
。
在CanbusComponent::Proc
当中,通过调用chassis
函数,根据MessageManager
的sensor_data_
当中存储的当前时刻从底层获得的底盘数据ChassisDetail
,得到底盘消息类型Chassis
,并将其通过发布者发布给相关的话题