上接20201217文档中的内容,也就是这篇博客:https://www.cnblogs.com/shenqiren/p/14151072.html 。
强调一下,这里主要集中在第三部分的内容,其内容为如何修改我手头的现有DBC文件以及如何配适xx_controller.cc中的具体代码,关于devkit_controller.cc的解析可以看我之前的一篇文章:https://www.cnblogs.com/shenqiren/p/14070235.html 。
目录
配适代码合入Apollo内
按照技术文档中的指示,接下来就是复制粘贴的工作了。
### 2. 适配代码合入apollo文件内
下面以添加ge3车型为例,将该代码添加至apollo内:
可以用下面这个条指令来移动文件夹,最好是在容器内,因为output/文件夹是被保护的。
(1)
将`apollo/modules/tools/gen_vehicle_protocol/output/proto` 文件夹内`ge3.proto`文件拷贝至`apollo/modules/canbus/proto` 文件夹内,并在该文件夹内修改chassis_detail.proto,在该文件头部添加头文件`import "modules/canbus/proto/ge3.proto"`
import "modules/canbus/proto/tsy.proto"; //参照技术文档的修改
这一步还是比较简单的,按照技术文档的描述就可以实现。
optional Neolix_edu neolix_edu = 26;
// Reserve fields for other vehicles
optional Tsy tsy = 27; //根据技术文档添加底盘信息。
optional apollo.common.VehicleID vehicle_id = 101;
PS:【这里有一个知识点,如何理解每个enum下面的optional呢?optional在C++中是定义了一个集成了T模板和bool类型的关键字,用它来声明的量如果没有初始化的话,就不能有效使用,因为bool的标志会是false,表示没有初始化;如果以模板T初始化了之后,bool会为true,这样声明的变量就可以使用了。参考博客:https://blog.csdn.net/leapmotion/article/details/108046138和https://blog.csdn.net/zzhongcy/article/details/87623430 】
在`message ChassisDetail{}` 结构体内的最后一行添加要增加的新车型变量定义: `Ge3 ge3 = 21`;
在`pollo/modules/canbus/proto`目录的`BUILD`文件内添加上述新`proto`的依赖:`"ge3.proto"`;
这一步遇到问题了,根据技术文档中的图片来看,我们并没有找到他添加的代码位置,所以只好按照devkit的代码来添加一个只有name和src的proto_library。
上面这张是官方给的图片。
下面这是我自己修改的代码,不一定好用,后续可能要修改。
package(default_visibility = ["//visibility:public"])
proto_library(
name = "tsy_proto",
srcs = ["tsy.proto"],
)
##参考技术文档并没有找到合适的proto_library叫做canbus_proto_lib
cc_proto_library(
name = "devkit_cc_proto",
deps = [
":devkit_proto",
],
)
(2)
将`apollo/modules/tools/gen_vehicle_protocol/output/vehicle/` 内的ge3文件夹拷贝至`apollo/modules/canbus/vehicle/` 文件夹下;
实现新的车辆控制逻辑
实现新的车辆控制逻辑,在`apollo/modules/canbus/vehicle/ge3/ge3_controller.cc` 文件编写控制逻辑代码,主要包含将解析的底盘反馈报文的信息,通过`chassis`和`chassis_detail`广播出车辆底盘信息。`chassis`主要包括获取底盘的车速、轮速、发动机转速、踏板反馈、转角反馈等信息, `chassis_detail`是每一帧报文的实际信息,这一部分编写的代码如下所示:
从这里开始,我们将和技术文档中对照,一点一点地修改tsy.controller.cc的内容,下面的主要格式将是一段技术文档的代码,一段我自己修改的代码。
先要注意一点,这个在我上一篇博文提到过,就是需要修改DBC中的transmitter,所以这里的sender part后面的内容是不对的。
- ErrorCode TsyController::Init(
- const VehicleParameter& params,
- CanSender<::apollo::canbus::ChassisDetail> *const can_sender,
- MessageManager<::apollo::canbus::ChassisDetail> *const message_manager) {
- if (is_initialized_) {
- AINFO << "TsyController has already been initiated.";
- return ErrorCode::CANBUS_ERROR;
- }
- params_.CopyFrom(params);
- if (!params_.has_driving_mode()) {
- AERROR << "Vehicle conf pb not set driving_mode.";
- return ErrorCode::CANBUS_ERROR;
- }
- if (can_sender == nullptr) {
- return ErrorCode::CANBUS_ERROR;
- }
- can_sender_ = can_sender;
- if (message_manager == nullptr) {
- AERROR << "protocol manager is null.";
- return ErrorCode::CANBUS_ERROR;
- }
- message_manager_ = message_manager;
- // sender part
- vcu_dbsf_request_154_ = dynamic_cast<Vcudbsfrequest154*>
- (message_manager_->GetMutableProtocolDataById(Vcudbsfrequest154::ID));
- if (vcu_dbsf_request_154_ == nullptr) {
- AERROR << "Vcudbsfrequest154 does not exist in the TsyMessageManager!";
- return ErrorCode::CANBUS_ERROR;
- }
- vcu_epsf_control_request_469_ = dynamic_cast<Vcuepsfcontrolrequest469*>
- (message_manager_->GetMutableProtocolDataById(Vcuepsfcontrolrequest469::ID));
- if (vcu_epsf_control_request_469_ == nullptr) {
- AERROR << "Vcuepsfcontrolrequest469 does not exist in the TsyMessageManager!";
- return ErrorCode::CANBUS_ERROR;
- }
- vcu_epsr_control_request_101_ = dynamic_cast<Vcuepsrcontrolrequest101*>
- (message_manager_->GetMutableProtocolDataById(Vcuepsrcontrolrequest101::ID));
- if (vcu_epsr_control_request_101_ == nullptr) {
- AERROR << "Vcuepsrcontrolrequest101 does not exist in the TsyMessageManager!";
- return ErrorCode::CANBUS_ERROR;
- }
- vcu_vehicle_diagnosis_301_ = dynamic_cast<Vcuvehiclediagnosis301*>
- (message_manager_->GetMutableProtocolDataById(Vcuvehiclediagnosis301::ID));
- if (vcu_vehicle_diagnosis_301_ == nullptr) {
- AERROR << "Vcuvehiclediagnosis301 does not exist in the TsyMessageManager!";
- return ErrorCode::CANBUS_ERROR;
- }
- vcu_vehicle_status_1_303_ = dynamic_cast<Vcuvehiclestatus1303*>
- (message_manager_->GetMutableProtocolDataById(Vcuvehiclestatus1303::ID));
- if (vcu_vehicle_status_1_303_ == nullptr) {
- AERROR << "Vcuvehiclestatus1303 does not exist in the TsyMessageManager!";
- return ErrorCode::CANBUS_ERROR;
- }
- can_sender_->AddMessage(Vcudbsfrequest154::ID, vcu_dbsf_request_154_, false);
- can_sender_->AddMessage(Vcuepsfcontrolrequest469::ID, vcu_epsf_control_request_469_, false);
- can_sender_->AddMessage(Vcuepsrcontrolrequest101::ID, vcu_epsr_control_request_101_, false);
- can_sender_->AddMessage(Vcuvehiclediagnosis301::ID, vcu_vehicle_diagnosis_301_, false);
- can_sender_->AddMessage(Vcuvehiclestatus1303::ID, vcu_vehicle_status_1_303_, false);
- // need sleep to ensure all messages received
- AINFO << "TsyController is initialized.";
- is_initialized_ = true;
- return ErrorCode::OK;
- }
点火开关
// 3
chassis_.set_engine_started(true);
// check if there is not ge3, no chassis detail can be retrieved and return
if (!chassis_detail.has_ge3()) {
AERROR << "NO GE3 chassis information!";
return chassis_;
}
Ge3 ge3 = chassis_detail.ge3();
- // 3
- chassis_.set_engine_started(true);
- /* ADD YOUR OWN CAR CHASSIS OPERATION
- */
- if (!chassis_detail.has_ge3()) {
- AERROR << "NO TSY chassis information!";
- return chassis_;
- }
- TSY tsy = chassis_detail.tsy();
接下来我遇到了一点问题,官方技术文档中的ge3和实际酷黑devkit的//5是不一致的,具体看下面的代码。
第一个是ge3的:
if (ge3.has_scu_bcs_3_308()) {
Scu_bcs_3_308 scu_bcs_3_308 = ge3.scu_bcs_3_308();
if (scu_bcs_3_308.has_bcs_rrwheelspd()) {
if (chassis_.has_wheel_speed()) {
chassis_.mutable_wheel_speed()->set_is_wheel_spd_rr_valid(
scu_bcs_3_308.bcs_rrwheelspdvd());
chassis_.mutable_wheel_speed()->set_wheel_direction_rr(
(WheelSpeed::WheelSpeedType)scu_bcs_3_308.bcs_rrwheeldirection());
chassis_.mutable_wheel_speed()->set_wheel_spd_rr(
scu_bcs_3_308.bcs_rrwheelspd());
}
}
第二个是devkit的:
if (chassis_detail.devkit().has_wheelspeed_report_506()) {
if (chassis_detail.devkit().wheelspeed_report_506().has_rr()) {
chassis_.mutable_wheel_speed()->set_wheel_spd_rr(
chassis_detail.devkit().wheelspeed_report_506().rr());
}
可以看到这两个在set是出现了不一致,ge3多了两个set。我从devkit_controller.h中的头文件找到了一个文件:
#include "modules/canbus/proto/chassis.pb.h"
我在这个文件夹下找到了一个文件:
这个文件里面有一段代码
message WheelSpeed {
enum WheelSpeedType {
FORWARD = 0;
BACKWARD = 1;
STANDSTILL = 2;
INVALID = 3;
}
optional bool is_wheel_spd_rr_valid = 1 [default = false];
optional WheelSpeedType wheel_direction_rr = 2 [default = INVALID];
optional double wheel_spd_rr = 3 [default = 0.0];
optional bool is_wheel_spd_rl_valid = 4 [default = false];
optional WheelSpeedType wheel_direction_rl = 5 [default = INVALID];
optional double wheel_spd_rl = 6 [default = 0.0];
optional bool is_wheel_spd_fr_valid = 7 [default = false];
optional WheelSpeedType wheel_direction_fr = 8 [default = INVALID];
optional double wheel_spd_fr = 9 [default = 0.0];
optional bool is_wheel_spd_fl_valid = 10 [default = false];
optional WheelSpeedType wheel_direction_fl = 11 [default = INVALID];
optional double wheel_spd_fl = 12 [default = 0.0];
}
看这里可以发现是不一样的,valid是转速信号的有效位,wheel_direction是转向,估计是正反向的,wheel_spd_rr是转速信号。
轮速反馈
现在回到正题,我们可以认为按照devkit的信号来是可以的,所以我们参考devkit的代码而不是ge3的代码。但是我们和酷黑不同的地方是,酷黑的DBC中专门有一个反馈信号506用来存放四个车轮的转速反馈,我们是分散在4个反馈信号10/20/30/40里。
// 4 engine rpm ch has no engine rpm
// chassis_.set_engine_rpm(0);
// 5 wheel spd
if (chassis_detail.devkit().has_wheelspeed_report_506()) {
if (chassis_detail.devkit().wheelspeed_report_506().has_rr()) {
chassis_.mutable_wheel_speed()->set_wheel_spd_rr(
chassis_detail.devkit().wheelspeed_report_506().rr());
}
if (chassis_detail.devkit().wheelspeed_report_506().has_rl()) {
chassis_.mutable_wheel_speed()->set_wheel_spd_rl(
chassis_detail.devkit().wheelspeed_report_506().rl());
}
if (chassis_detail.devkit().wheelspeed_report_506().has_fr()) {
chassis_.mutable_wheel_speed()->set_wheel_spd_fr(
chassis_detail.devkit().wheelspeed_report_506().fr());
}
if (chassis_detail.devkit().wheelspeed_report_506().has_fl()) {
chassis_.mutable_wheel_speed()->set_wheel_spd_fl(
chassis_detail.devkit().wheelspeed_report_506().fl());
}
}
- //4 Tsy:tsy 没有发动机转速信号
- //5 wheel spd
- if (tsy.has_mcufl_torque_feedback_10()) {
- if (tsy.mcufl_torque_feedback_10().has_fl_speed()) {
- chassis_.mutable_wheel_speed()->set_wheel_spd_fl(
- tsy.mcufl_torque_feedback_10().fl_speed());
- }
- }
- if (tsy.has_mcufr_torque_feedback_20()) {
- if (tsy.mcufr_torque_feedback_20().has_fr_speed()) {
- chassis_.mutable_wheel_speed()->set_wheel_spd_fr(
- tsy.mcufr_torque_feedback_20().fr_speed());
- }
- }
- if (tsy.has_mcurl_torque_feedback_30()) {
- if (tsy.mcurl_torque_feedback_30().has_rl_speed()) {
- chassis_.mutable_wheel_speed()->set_wheel_spd_rl(
- tsy.mcurl_torque_feedback_30().rl_speed());
- }
- }
- if (tsy.has_mcurr_torque_feedback_40()) {
- if (tsy.mcurr_torque_feedback_40().has_rr_speed()) {
- chassis_.mutable_wheel_speed()->set_wheel_spd_rr(
- tsy.mcurr_torque_feedback_40().rr_speed());
- }
- }
车速反馈
if (ge3.has_scu_bcs_2_307() && ge3.scu_bcs_2_307().has_bcs_vehspd()) {
chassis_.set_speed_mps(
static_cast<float>(ge3.scu_bcs_2_307().bcs_vehspd()));
} else {
chassis_.set_speed_mps(0);
}
- //6 speed_mps 这个是米每秒的车速
- if (tsy.has_vcu_vehicle_status_2_304() && tsy.vcu_vehicle_status_2_304().has_vehicle_speed()) {
- chassis_.set_speed_mps(
- static_cast<float>(tsy.vcu_vehicle_status_2_304().vehicle_speed()));
- } else {
- chassis_.set_speed_mps(0);
- }
油门反馈
// 9 throttle
if (chassis_detail.devkit().has_throttle_report_500() &&
chassis_detail.devkit()
.throttle_report_500()
.has_throttle_pedal_actual()) {
chassis_.set_throttle_percentage(static_cast<float>(
chassis_detail.devkit().throttle_report_500().throttle_pedal_actual()));
} else {
chassis_.set_throttle_percentage(0);
}
- // 9 throttle 这里有一个问题,这是油门的实际反馈,我们缺少这部分的DBC和定义
- /*
- if (tsy().has_throttle_report_500() &&
- tsy().throttle_report_500().has_throttle_pedal_actual()) {
- chassis_.set_throttle_percentage(static_cast<float>(
- tsy().throttle_report_500().throttle_pedal_actual()));
- } else {
- chassis_.set_throttle_percentage(0);
- }
- */
制动反馈
// 10 brake
if (chassis_detail.devkit().has_brake_report_501() &&
chassis_detail.devkit().brake_report_501().has_brake_pedal_actual()) {
chassis_.set_brake_percentage(static_cast<float>(
chassis_detail.devkit().brake_report_501().brake_pedal_actual()));
} else {
chassis_.set_brake_percentage(0);
}
- // 10 brake 这里也有一个问题,要求的是制动百分比的反馈,所以在制动压力反馈的DBC
- // 中应该除以一下最大的制动压力
- if (tsy().has_dbsf_status_142() &&
- tsy().dbsf_status_142().has_dbsf_hp_pressure()) {
- chassis_.set_brake_percentage(static_cast<float>(
- tsy().dbsf_status_142().has_dbsf_hp_pressure()));
- } else {
- chassis_.set_brake_percentage(0);
- }
挡位反馈
// 23, previously 11 gear
if (chassis_detail.devkit().has_gear_report_503() &&
chassis_detail.devkit().gear_report_503().has_gear_actual()) {
Chassis::GearPosition gear_pos = Chassis::GEAR_INVALID;
if (chassis_detail.devkit().gear_report_503().gear_actual() ==
Gear_report_503::GEAR_ACTUAL_INVALID) {
gear_pos = Chassis::GEAR_INVALID;
}
if (chassis_detail.devkit().gear_report_503().gear_actual() ==
Gear_report_503::GEAR_ACTUAL_NEUTRAL) {
gear_pos = Chassis::GEAR_NEUTRAL;
}
if (chassis_detail.devkit().gear_report_503().gear_actual() ==
Gear_report_503::GEAR_ACTUAL_REVERSE) {
gear_pos = Chassis::GEAR_REVERSE;
}
if (chassis_detail.devkit().gear_report_503().gear_actual() ==
Gear_report_503::GEAR_ACTUAL_DRIVE) {
gear_pos = Chassis::GEAR_DRIVE;
}
if (chassis_detail.devkit().gear_report_503().gear_actual() ==
Gear_report_503::GEAR_ACTUAL_PARK) {
gear_pos = Chassis::GEAR_PARKING;
}
chassis_.set_gear_location(gear_pos);
} else {
chassis_.set_gear_location(Chassis::GEAR_NONE);
}
存在一些的问题,目前我们是没有挡位反馈的,所以我初步打算在0x303这个报文内,用8位来反馈这个数据。
转向反馈
// 12 steering
if (chassis_detail.devkit().has_steering_report_502() &&
chassis_detail.devkit().steering_report_502().has_steer_angle_actual()) {
chassis_.set_steering_percentage(static_cast<float>(
chassis_detail.devkit().steering_report_502().steer_angle_actual() *
100.0 / vehicle_params_.max_steer_angle() * M_PI / 180));
} else {
chassis_.set_steering_percentage(0);
}
- // 12 steering
- if (tsy.has_vcu_vehicle_status_2_304() &&
- tsy.vcu_vehicle_status_2_304().has_f_tire_angle()) {
- chassis_.set_steering_percentage(static_cast<float>(
- tsy.vcu_vehicle_status_2_304().f_tire_angle() *
- 100.0 / vehicle_params_.max_steer_angle() * M_PI / 180));
- } else {
- chassis_.set_steering_percentage(0);
- }
感觉前面的制动反馈可以借鉴这里的用法,在vehicl_params_里加一个最大制动压力的参数。
驻车EPB反馈
// 13 parking brake
if (chassis_detail.devkit().has_park_report_504() &&
chassis_detail.devkit().park_report_504().has_parking_actual()) {
if (chassis_detail.devkit().park_report_504().parking_actual() ==
Park_report_504::PARKING_ACTUAL_PARKING_TRIGGER) {
chassis_.set_parking_brake(true);
} else {
chassis_.set_parking_brake(false);
}
} else {
chassis_.set_parking_brake(false);
}
- // 13 parking brake
- if (tsy.has_vcu_vehicle_status_2_304() &&
- tsy.vcu_vehicle_status_2_304().has_epb_final_state()) {
- if (tsy.vcu_vehicle_status_2_304().epb_final_state() ==
- Vcu_vehicle_status_2_304::PARKED) {
- chassis_.set_parking_brake(true);
- } else {
- chassis_.set_parking_brake(false);
- }
- } else {
- chassis_.set_parking_brake(false);
- }
这里直接用EPB_status_375或许不太妥,因为实际EPB的反馈是有四个状态的,而Apollo中只定义了两种状态,所以我想在303中用8位来指代这个EPB状态。PARKED代表加紧,另外的代表放松,去掉保留这个状态,用上升和下降的阶跃来判断。
到这里为止,反馈报文的修改以及修改意见就结束了,下面是请求报文的部分了。
iECU有效性设定(ENABLE)
// set enable
brake_command_101_->set_brake_en_ctrl(
Brake_command_101::BRAKE_EN_CTRL_ENABLE);
throttle_command_100_->set_throttle_en_ctrl(
Throttle_command_100::THROTTLE_EN_CTRL_ENABLE);
steering_command_102_->set_steer_en_ctrl(
Steering_command_102::STEER_EN_CTRL_ENABLE);
gear_command_103_->set_gear_en_ctrl(Gear_command_103::GEAR_EN_CTRL_ENABLE);
park_command_104_->set_park_en_ctrl(Park_command_104::PARK_EN_CTRL_ENABLE);
- // set enable
- iecu_control_flag_501_->set_iecu_control_request_flag(
- Iecu_control_flag_501::ENABLE)
- iecu_control_steering_502_->set_iecu_steering_valid(
- Iecu_control_steering_502::ENABLE);
- iecu_control_ibc_503_->set_iecu_ibc_valid(
- Iecu_control_ibc_503::ENABLE);
- iecu_control_power_504_->set_iecu_power_valid(
- Iecu_control_power_504::ENABLE);
- gear_command_103_->set_gear_en_ctrl(Gear_command_103::GEAR_EN_CTRL_ENABLE);
- park_command_104_->set_park_en_ctrl(Park_command_104::PARK_EN_CTRL_ENABLE);
这里存在一些问题,后续需要去查看一下Apollo对驻车和挡位的要求,是否需要一个直接的EPB以及挡位控制请求。
从代码中可以看到devkit的DBC是有一个en_ctrl的位置的,但是新的DBC中好像没有提到这个事:
同样需要注意的是,我们将EPB和驻车挡结合了,在0x504里有一个关于挡位的信息:
退出自动驾驶(DISABLE)
这部分使用自动生成代码就可以,实现的就是退出自动驾驶改为人工驾驶。
仅自动转向模式
这里和devkit一致,直接采用不能仅自动转向的方案:
AFATAL << "SteerOnlyMode is not supported in devkit!";
return ErrorCode::CANBUS_ERROR;
但是在模板中我们可以看到Apollo的方法是其他都DISABLE,只有转向ENABLE就是仅自动转向模式:
- brake_60_->set_disable();
- throttle_62_->set_disable();
- steering_64_->set_enable();
这里提出一个后续人机共驾的改进方法,把驱动、制动、转向分开来做,希望可以实现人工油门但是自动转向。
仅自动速度模式
同自动转向。
挡位控制
switch (gear_position) {
case Chassis::GEAR_NEUTRAL: {
gear_command_103_->set_gear_target(Gear_command_103::GEAR_TARGET_NEUTRAL);
break;
}
case Chassis::GEAR_REVERSE: {
gear_command_103_->set_gear_target(Gear_command_103::GEAR_TARGET_REVERSE);
break;
}
case Chassis::GEAR_DRIVE: {
gear_command_103_->set_gear_target(Gear_command_103::GEAR_TARGET_DRIVE);
break;
}
case Chassis::GEAR_PARKING: {
gear_command_103_->set_gear_target(Gear_command_103::GEAR_TARGET_PARK);
break;
}
case Chassis::GEAR_INVALID: {
gear_command_103_->set_gear_target(Gear_command_103::GEAR_TARGET_NEUTRAL);
break;
}
default: {
gear_command_103_->set_gear_target(Gear_command_103::GEAR_TARGET_NEUTRAL);
break;
}
}
- switch (gear_position) {
- case Chassis::GEAR_NEUTRAL: {
- iecu_control_power_504_->set_iecu_power_gear(Iecu_control_power_504::NEUTRAL);
- break;
- }
- case Chassis::GEAR_REVERSE: {
- iecu_control_power_504_->set_iecu_power_gear(Iecu_control_power_504::REVERSE);
- break;
- }
- case Chassis::GEAR_DRIVE: {
- iecu_control_power_504_->set_iecu_power_gear(Iecu_control_power_504::DRIVE);
- break;
- }
- case Chassis::GEAR_PARKING: {
- iecu_control_power_504_->set_iecu_power_gear(Iecu_control_power_504::PARKING);
- break;
- }
- /*
- case Chassis::GEAR_LOW: {
- gear_66_->set_gear_low();
- break;
- }
- 并没有设计低速档,所以这段不用。
- */
- case Chassis::GEAR_NONE: {
- iecu_control_power_504_->set_iecu_power_gear(Iecu_control_power_504::NEUTRAL);
- break;
- }
- case Chassis::GEAR_INVALID: {
- AERROR << "Gear command is invalid!";
- iecu_control_power_504_->set_iecu_power_gear(Iecu_control_power_504::NEUTRAL);
- break;
- }
- default: {
- iecu_control_power_504_->set_iecu_power_gear(Iecu_control_power_504::NEUTRAL);
- break;
- }
- }
这里提出一点需要改进的地方,在0x504里的挡位,不仅需要在comment里解释各个挡位的含义,还需要再value table里对应上,为这里Iecu_control_power_504::NEUTRAL之类的代码实现提供可能,因为并不确定这里是否可以直接给0或者1.
制动请求
void DevkitController::Brake(double pedal) {
// double real_value = params_.max_acc() * acceleration / 100;
// TODO(All) : Update brake value based on mode
if (driving_mode() != Chassis::COMPLETE_AUTO_DRIVE &&
driving_mode() != Chassis::AUTO_SPEED_ONLY) {
AINFO << "The current drive mode does not need to set brake pedal.";
return;
}
brake_command_101_->set_brake_pedal_target(pedal);
}
- void TsyController::Brake(double pedal) {
- // double real_value = params_.max_acc() * acceleration / 100;
- // TODO(All) : Update brake value based on mode
- if (driving_mode() != Chassis::COMPLETE_AUTO_DRIVE &&
- driving_mode() != Chassis::AUTO_SPEED_ONLY) {
- AINFO << "The current drive mode does not need to set brake pedal.";
- return;
- }
- iecu_control_ibc_503_->set_iecu_breakpressure_cmd(pedal);
- }
同样也有需要注意的问题,这里的制动应该是百分比,而不是Mpa,所以需要改一下。
驱动请求
void DevkitController::Throttle(double pedal) {
if (driving_mode() != Chassis::COMPLETE_AUTO_DRIVE &&
driving_mode() != Chassis::AUTO_SPEED_ONLY) {
AINFO << "The current drive mode does not need to set throttle pedal.";
return;
}
throttle_command_100_->set_throttle_pedal_target(pedal);
}
- void TsyController::Throttle(double pedal) {
- if (driving_mode() != Chassis::COMPLETE_AUTO_DRIVE &&
- driving_mode() != Chassis::AUTO_SPEED_ONLY) {
- AINFO << "The current drive mode does not need to set throttle pedal.";
- return;
- }
- iecu_control_power_504_->set_iecu_total_or_distribute(
- Iecu_control_power_504::TOTAL);
- iecu_control_power_504_->set_torque_or_speed_or_acc(
- Iecu_control_power_504::TORQUE);
- iecu_control_power_504_->set_iecu_torque_control(pedal);
- }
这里需要注意的是我们的iecu设计是分了驱动模式,以及集中式或者分布式驱动的:
我想我们应该将切换驱动模式的量都用value table来定义,我这里先给出一个初版:转矩驱动:TORQUE;转速驱动:SPEED;加速度驱动:ACC;集中驱动:TOTAL;分布式:DISTRIBUTE。
加速度请求
可以看到酷黑是没有加速度控制的。
void DevkitController::Acceleration(double acc) {
if (driving_mode() != Chassis::COMPLETE_AUTO_DRIVE ||
driving_mode() != Chassis::AUTO_SPEED_ONLY) {
AINFO << "The current drive mode does not need to set acceleration.";
return;
}
// None
}
但是我们是有的,所以这样做:
- void TsyController::Acceleration(double acc) {
- if (driving_mode() != Chassis::COMPLETE_AUTO_DRIVE ||
- driving_mode() != Chassis::AUTO_SPEED_ONLY) {
- AINFO << "The current drive mode does not need to set acceleration.";
- return;
- }
- iecu_control_power_504_->set_iecu_total_or_distribute(
- Iecu_control_power_504::TOTAL);
- iecu_control_power_504_->set_torque_or_speed_or_acc(
- Iecu_control_power_504::ACC);
- iecu_control_power_504_->set_iecu_acc_or_de_control(acc);
- }
转向请求(仅是转向角度)
可以看到酷黑的请求并不能直接是实际转角,而是有轮端传动比。这是因为Apollo自己规定了这一点,并不知道是为什么。
// const double real_angle = params_.max_steer_angle() * angle / 100.0;
// reverse sign
/* ADD YOUR OWN CAR CHASSIS OPERATION
steering_64_->set_steering_angle(real_angle)->set_steering_angle_speed(200);
*/
void DevkitController::Steer(double angle) {
if (driving_mode() != Chassis::COMPLETE_AUTO_DRIVE &&
driving_mode() != Chassis::AUTO_STEER_ONLY) {
AINFO << "The current driving mode does not need to set steer.";
return;
}
const double real_angle =
vehicle_params_.max_steer_angle() / M_PI * 180 * angle / 100.0;
steering_command_102_->set_steer_angle_target(real_angle)
->set_steer_angle_spd(250);
}
我们默认的转角速度是200,而酷黑是250。
- void TsyController::Steer(double angle) {
- if (driving_mode() != Chassis::COMPLETE_AUTO_DRIVE &&
- driving_mode() != Chassis::AUTO_STEER_ONLY) {
- AINFO << "The current driving mode does not need to set steer.";
- return;
- }
- const double real_angle = params_.max_steer_angle() * angle / 100.0;
- // reverse sign
- iecu_control_steering_502_->set_iecu_ftire_angle_cmd(real_angle);
- iecu_control_steering_502_->set_iecu_ftire_speed_cmd(200);
- }
这里我还是要提一点问题,我们的底盘转角是左负右正的,而Apollo要求左正右负,这一点需要修改。
转向请求(转角、角速度)
酷黑的转角速度居然不会变。
void DevkitController::Steer(double angle, double angle_spd) {
if (driving_mode() != Chassis::COMPLETE_AUTO_DRIVE &&
driving_mode() != Chassis::AUTO_STEER_ONLY) {
AINFO << "The current driving mode does not need to set steer.";
return;
}
const double real_angle =
vehicle_params_.max_steer_angle() / M_PI * 180 * angle / 100.0;
steering_command_102_->set_steer_angle_target(real_angle)
->set_steer_angle_spd(250);
}
- void TsyController::Steer(double angle, double angle_spd) {
- if (driving_mode() != Chassis::COMPLETE_AUTO_DRIVE &&
- driving_mode() != Chassis::AUTO_STEER_ONLY) {
- AINFO << "The current driving mode does not need to set steer.";
- return;
- }
- const double real_angle = params_.max_steer_angle() * angle / 100.0;
- const double real_angle_spd = ProtocolData::BoundedValue(
- params_.min_steer_angle_spd(), params_.max_steer_angle_spd(),
- params_.max_steer_angle_spd() * angle_spd / 100.0);
- // reverse sign
- iecu_control_steering_502_->set_iecu_ftire_angle_cmd(real_angle);
- iecu_control_steering_502_->set_iecu_ftire_speed_cmd(real_angle_spd);
- }
这个地方居然转角速度也是百分比的,看来是为了统一不同的车型,使用无量纲的方法。
转向灯控制
虽然再Apollo6.0中酷黑的程序里没有给出转向灯控制:
void DevkitController::SetTurningSignal(const ControlCommand& command) {
// Set Turn Signal do not support on devkit
}
但是在新的DBC中是有这一项的:
我觉得我们后续也可以把这一项加进来,不过这并不是很要紧的信号。
车辆自检(CheckChassisError)
参考酷黑的代码进行修改:
- bool TsyController::CheckChassisError() {
- ChassisDetail chassis_detail;
- message_manager_->GetSensorData(&chassis_detail);
- if (!chassis_detail.has_tsy()) {
- AERROR_EVERY(100) << "ChassisDetail has no tsy vehicle info."
- << chassis_detail.DebugString();
- return false;
- }
- Tsy tsy = chassis_detail.tsy();
- // steer fault
- if (tsy.has_vcu_vehicle_diagnosis_301()) {
- if (Vcu_vehicle_diagnosis_301::FSTEER_FAULT ==
- tsy.vcu_vehicle_diagnosis_301().fsteering_state()) {
- return true;
- }
- }
- // drive fault
- if (tsy.has_vcu_vehicle_diagnosis_301()) {
- if (Vcu_vehicle_diagnosis_301::FL_FAULT ==
- tsy.vcu_vehicle_diagnosis_301().flmotor_state()) {
- return true;
- }
- if (Vcu_vehicle_diagnosis_301::FR_FAULT ==
- tsy.vcu_vehicle_diagnosis_301().frmotor_state()) {
- return true;
- }
- if (Vcu_vehicle_diagnosis_301::RL_FAULT ==
- tsy.vcu_vehicle_diagnosis_301().rlmotor_state()) {
- return true;
- }
- if (Vcu_vehicle_diagnosis_301::RR_FAULT ==
- tsy.vcu_vehicle_diagnosis_301().rrmotor_state()) {
- return true;
- }
- }
- // brake fault
- if (tsy.has_vcu_vehicle_diagnosis_301()) {
- if (Vcu_vehicle_diagnosis_301::BRAKE_FAULT ==
- tsy.vcu_vehicle_diagnosis_301().dbsf_state()) {
- return true;
- }
- }
- // gear fault
- /*
- 挡位并没有错误码,也不知道酷黑是哪里来的这个信号。
- */
- // park fault
- if (tsy.has_vcu_vehicle_diagnosis_301()) {
- if (Vcu_vehicle_diagnosis_301::EPB_FAULT ==
- tsy.vcu_vehicle_diagnosis_301().epb_state()) {
- return true;
- }
- }
- return false;
- }
这里建议对0x301这个报文的内容提出修改,将0/1改为XX_FAULT/XX_OK,在value table中体现。
反馈检测(CheckResponse)
这部分可能我在之前酷黑的代码分析上写的不是很对,这里引用技术文档中的内容。
添加`CheckResponse`逻辑,Apollo程序内增加了对车辆底层是否在自动驾驶模式的监控,即车辆横向、驱动、制动模块的驾驶模式反馈是否处于自动驾驶状态,如果在一个`CheckResponse`周期内,车辆某个模块驾驶模块反馈处于接管或者手动驾驶模式,则Apollo会控制车辆使能为紧急停车模式(`Emergency`),即各模块均控制为手动模式,确保控制车辆时的安全。不同的车辆`CheckResponse`周期可能不同,需要开发者根据情况通过设置`retry_num`设定`check`周期。
开发者可以不改原check代码方案,将3个驾驶模式反馈报文与apollo内`chassis_detail`做映射:
`is_eps_online->转向模式反馈信号`
`is_vcu_online->驱动模式反馈信号`
`is_esp_online->制动模式反馈信号`
在`apollo/modules/canbus/vehicle/ge3/protocol/scu_eps_311.cc`文件内,增加以下代码:
```
chassis->mutable_check_response()->set_is_eps_online(eps_drvmode(bytes, length) == 3);
```
在`apollo/modules/canbus/vehicle/ge3/protocol/scu_vcu_1_312.cc`文件内,增加以下代码:
```
chassis->mutable_check_response()->set_is_vcu_online(vcu_drvmode(bytes, length) == 3);
```
在`apollo/modules/canbus/vehicle/ge3/protocol/scu_bcs_1_306.cc`文件内,增加以下代码:
```
chassis->mutable_check_response()->set_is_esp_online(bcs_drvmode(bytes, length) == 3);
```
所以从这里看,需要对代码进行改动,包括本小节引用的技术文档中黄色高光的部分。
这部分的代码直接复制粘贴技术文档中的代码,出于规范,这里还是贴出来我们在tsy_controller.cc中的配适代码。
- bool TsyController::CheckResponse(const int32_t flags, bool need_wait) {
- int32_t retry_num = 20;
- ChassisDetail chassis_detail;
- bool is_eps_online = false;
- bool is_vcu_online = false;
- bool is_esp_online = false;
- do {
- if (message_manager_->GetSensorData(&chassis_detail) != ErrorCode::OK) {
- AERROR_EVERY(100) << "get chassis detail failed.";
- return false;
- }
- bool check_ok = true;
- if (flags & CHECK_RESPONSE_STEER_UNIT_FLAG) {
- is_eps_online = chassis_detail.has_check_response() &&
- chassis_detail.check_response().has_is_eps_online() &&
- chassis_detail.check_response().is_eps_online();
- check_ok = check_ok && is_eps_online;
- }
- if (flags & CHECK_RESPONSE_SPEED_UNIT_FLAG) {
- is_vcu_online = chassis_detail.has_check_response() &&
- chassis_detail.check_response().has_is_vcu_online() &&
- chassis_detail.check_response().is_vcu_online();
- is_esp_online = chassis_detail.has_check_response() &&
- chassis_detail.check_response().has_is_esp_online() &&
- chassis_detail.check_response().is_esp_online();
- check_ok = check_ok && is_vcu_online && is_esp_online;
- }
- if (check_ok) {
- return true;
- } else {
- AINFO << "Need to check response again.";
- }
- if (need_wait) {
- --retry_num;
- std::this_thread::sleep_for(
- std::chrono::duration<double, std::milli>(20));
- }
- } while (need_wait && retry_num);
- AINFO << "check_response fail: is_eps_online:" << is_eps_online
- << ", is_vcu_online:" << is_vcu_online
- << ", is_esp_online:" << is_esp_online;
- return false;
- }
本篇完
2020年12月21日 17:42
于宁波天尚元振狮路365号工厂二楼