Apollo搭建control轻量级仿真闭环

  1. 背景
    在研究Apollo开源代码时,需要闭环才能更好的理解代码。但个人读者研究,受到资金和精力限制,无法购买硬件设备或无力调试实体小车。而无论是基于强动力学(Carsim, CarMaker等)的仿真或场景仿真(LGsimulator, Carla,Prescan等)都相对麻烦,且对电脑性能要求高。本文旨在通过code实现一简单车辆模型,达到闭环调试Apollo代码的目的。

  2. 实现原理
    在这里插入图片描述
    用运动学模型模拟实车,接受control模块的控车信号,产生运动。基于定位的初始位置姿态信息推演仿真车辆实时的位置姿态,可以把该位姿信息以/apollo/localization/pose的通道发出,频率设定为100hz。根据control的挂挡和加速转向指令模拟出仿真车辆的底盘信息,以/apollo/canbus/chassis的通道发出,频率设定为100hz。在仿真里可模拟各种障碍物,以/apollo/prediction的通道发出。障碍物信息读者可自己构建,本文不详细说明。

  3. 代码讲解

#include <cstdio>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

#include "master/modules/control/common/control_gflags.h"
#include "cyber/common/file.h"
#include "cyber/common/log.h"
#include "cyber/cyber.h"
#include "cyber/init.h"
#include "cyber/time/rate.h"
#include "cyber/time/time.h"
#include "gflags/gflags.h"
#include "modules/common/adapters/adapter_gflags.h"
#include "modules/common/math/math_utils.h"
#include "modules/common/math/quaternion.h"
#include "modules/common/time/time.h"

#include "modules/common/pnc_point.pb.h"
#include "modules/localization/proto/localization.pb.h"
#include "modules/control/proto/control_cmd.pb.h"
#include "modules/canbus/proto/chassis.pb.h"

using namespace std;
using apollo::cyber::Reader;
using apollo::cyber::Time;
using apollo::cyber::Writer;
using apollo::canbus::Chassis;
using apollo::common::Point3D;
using apollo::common::Angle3D;
using apollo::common::Quaternion;
using apollo::common::TrajectoryPoint;
using apollo::localization::LocalizationStatus;
using apollo::common::math::HeadingToQuaternion;
using apollo::common::math::InverseQuaternionRotate;
using apollo::common::time::Clock;
using apollo::control::ControlCommand;
using apollo::localization::LocalizationEstimate;
using std::this_thread::sleep_for;

DEFINE_string(fake_initial_localization_file,
              "apollo/modules/control/conf"
              "fake_initial_localization.pb.txt",
              "Used for set inital localization.");

DEFINE_int32(feed_frequency, 100,
             "Frequency with which protos are fed to control.");
DEFINE_double(diff, 0.1, "Length of control_ms timeout.");

static double kInitialXOffset = 0.0;
static double kInitialYOffset = 0.0;
static double kInitialZOffset = 0.0;
static double kInitialHeading = 0.0;

struct SimCarStatus {
  double x;
  double y;
  double z;
  double yaw;
  double v;
  double acceleration;
  double yaw_rate;
  double steer;
  double angular_speed;
  apollo::canbus::Chassis::GearPosition current_gear;
  apollo::canbus::Chassis::DrivingMode current_driving_mode;
};
double current_x = 0.0;
double current_y = 0.0;
double current_z = 0.0;
double current_heading = 0.0;
double current_speed = 0.0;
double simcar_period = 0.01;
double steer_ratio = 20;
double wheelbase = 2.87;
double max_steer_angle = 490;
double acceleration = 0.0;
double steering_target = 0.0;
double steering_rate = 0.0;
apollo::canbus::Chassis::GearPosition gear_location;
std::shared_ptr<Reader<ControlCommand>> control_reader;
std::shared_ptr<Writer<LocalizationEstimate>> localization_writer;
std::shared_ptr<Writer<Chassis>> chassis_writer;

void PublishLocalization(const SimCarStatus* simcar_status);
void PublishCanbus(const SimCarStatus* simcar_status);
void fake_chassis(const double acc, const double steer, const double steer_rate,
                  const apollo::canbus::Chassis::GearPosition gear,
                  SimCarStatus* simcar_status);

void TransformToVRF(const Angle3D& point_mrf, const Quaternion& orientation,
                    Angle3D* point_vrf);

void TransformToVRF(const Angle3D& point_mrf, const Quaternion& orientation,
                    Angle3D* point_vrf) {
  Eigen::Vector3d v_mrf(point_mrf.roll(), point_mrf.pitch(), point_mrf.yaw());
  auto v_vrf = InverseQuaternionRotate(orientation, v_mrf);
  point_vrf->set_roll(v_vrf.x());
  point_vrf->set_pitch(v_vrf.y());
  point_vrf->set_yaw(v_vrf.z());
}

void fake_chassis(const double acc, const double steer, const double steer_rate,
                  const apollo::canbus::Chassis::GearPosition gear,
                  SimCarStatus* simcar_status) {
  double angular_speed_ = (current_speed * tan(steer / 100 * max_steer_angle *
                                               (M_PI / 180) / steer_ratio)) /
                          wheelbase;
  current_speed += acc * simcar_period;
  current_speed = apollo::common::math::Clamp(current_speed, 0.0, 33.34);
  current_heading = current_heading + angular_speed_ * simcar_period;
  current_x = current_x + current_speed *
                              cos(current_heading + kInitialHeading) *
                              simcar_period;
  current_y = current_y + current_speed *
                              sin(current_heading + kInitialHeading) *
                              simcar_period;
  current_z = 0.0;
  simcar_status->x = current_x + kInitialXOffset;
  simcar_status->y = current_y + kInitialYOffset;
  simcar_status->z = current_z + kInitialZOffset;
  simcar_status->yaw = current_heading + kInitialHeading;
  simcar_status->v = current_speed;
  simcar_status->current_gear = gear;
  simcar_status->steer = steer;
  simcar_status->angular_speed = angular_speed_;
  simcar_status->acceleration = acc;
}

void PublishCanbus(const SimCarStatus* simcar_status) {
  Chassis chassis_;
  chassis_.mutable_header()->set_timestamp(Clock::NowInSeconds());
  chassis_.set_speed_mps(simcar_status->v);
  chassis_.set_longitudinal_velocity(simcar_status->v);
  chassis_.set_acc_o(simcar_status->acceleration);
  chassis_.set_steering_percentage(simcar_status->steer);
  chassis_.set_gear_location(simcar_status->current_gear);
  chassis_.set_driving_mode(simcar_status->current_driving_mode);
  chassis_writer->Write(chassis_);
}

void PublishLocalization(const SimCarStatus* simcar_status) {
  LocalizationEstimate localization_;
  localization_.mutable_header()->set_timestamp(Clock::NowInSeconds());
  auto* pose = localization_.mutable_global_localization()->mutable_pose();
  auto* motion = localization_.mutable_global_localization()->mutable_motion();
  localization_.mutable_global_localization()->set_status(LocalizationStatus::OK);
  pose->mutable_position()->set_x(simcar_status->x);
  pose->mutable_position()->set_y(simcar_status->y);
  pose->mutable_position()->set_z(simcar_status->z);
  double cur_heading = simcar_status->yaw;
  double cur_speed = simcar_status->v;
  Eigen::Quaternion<double> cur_orientation =
      HeadingToQuaternion<double>(cur_heading);
  pose->mutable_orientation()->set_qw(cur_orientation.w());
  pose->mutable_orientation()->set_qx(cur_orientation.x());
  pose->mutable_orientation()->set_qy(cur_orientation.y());
  pose->mutable_orientation()->set_qz(cur_orientation.z());
  motion->mutable_linear_vel()->set_x(std::cos(cur_heading) * cur_speed);
  motion->mutable_linear_vel()->set_y(std::sin(cur_heading) * cur_speed);
  motion->mutable_linear_vel()->set_z(0.0);
  motion->mutable_angular_vel()->set_roll(0);
  motion->mutable_angular_vel()->set_pitch(0);
  motion->mutable_angular_vel()->set_yaw(simcar_status->angular_speed);
  pose->mutable_euler_angles()->set_roll(0.0);
  pose->mutable_euler_angles()->set_pitch(0.0);
  pose->mutable_euler_angles()->set_yaw(cur_heading);
  TransformToVRF(motion->angular_vel(), pose->orientation(),
                 motion->mutable_angular_vel_vrf());

  localization_writer->Write(localization_);
}

int main(int argc, char** argv) {
  google::ParseCommandLineFlags(&argc, &argv, true);
  apollo::cyber::Init(argv[0]);
  FLAGS_alsologtostderr = true;

  shared_ptr<apollo::cyber::Node> node(
      apollo::cyber::CreateNode("simulator_node"));
  control_reader =
      node->CreateReader<ControlCommand>(FLAGS_control_command_topic, nullptr);
  localization_writer =
      node->CreateWriter<LocalizationEstimate>(FLAGS_localization_topic);
  chassis_writer = node->CreateWriter<Chassis>(FLAGS_chassis_topic);
  SimCarStatus simcar_status;

  TrajectoryPoint initial_point;

  if (!apollo::cyber::common::GetProtoFromFile(
          FLAGS_fake_initial_localization_file, &initial_point)) {
    AERROR << "failed to load file: " << FLAGS_fake_initial_localization_file;
    return -1;
  } else {
    kInitialXOffset = initial_point.path_point().x();
    kInitialYOffset = initial_point.path_point().y();
    kInitialZOffset = initial_point.path_point().z();
    kInitialHeading = initial_point.path_point().theta();
    current_speed = initial_point.v();
  }

  while (apollo::cyber::OK()) {
    double current_timestamp = Clock::NowInSeconds();
    cout << "current_timestamp = " << setprecision(12) << current_timestamp
         << endl;
    control_reader->Observe();
    const auto& control_msg = control_reader->GetLatestObserved();
    if (control_msg == nullptr) {
      cout << "control_msg is empty!" << endl;
      acceleration = -1.0;
      steering_target = 0.0;
      steering_rate = 100.0;
      gear_location = apollo::canbus::Chassis::GEAR_NEUTRAL;
      simcar_status.current_driving_mode =
          apollo::canbus::Chassis::COMPLETE_MANUAL;
    } else if (current_timestamp - control_msg->header().timestamp() >
               FLAGS_diff) {
      cout << "control_msg is timeout!" << endl;
      acceleration = -3.5;
      steering_target = 0.0;
      steering_rate = 100.0;
      gear_location = apollo::canbus::Chassis::GEAR_NEUTRAL;
      simcar_status.current_driving_mode =
          apollo::canbus::Chassis::COMPLETE_MANUAL;
    } else {
      acceleration = control_msg->acceleration();
      steering_target = control_msg->steering_target();
      steering_rate = control_msg->steering_rate();
      gear_location = control_msg->gear_location();
      simcar_status.current_driving_mode =
          apollo::canbus::Chassis::COMPLETE_AUTO_DRIVE;
    }
    if (isnan(acceleration)) {
      acceleration = 0.0;
      cout << "acceleration is nan!" << endl;
    }
    if (isnan(steering_target)) {
      steering_target = 0.0;
      steering_rate = 0.0;
      cout << "steering_target is nan!" << endl;
    }
    fake_chassis(acceleration, steering_target, steering_rate, gear_location,
                 &simcar_status);
    PublishCanbus(&simcar_status);
    PublishLocalization(&simcar_status);

    sleep_for(chrono::milliseconds(1000 / FLAGS_feed_frequency));
  }
  cout << "Successfully fed proto files." << endl;
  return 0;
}

其中

fake_chassis(acceleration, steering_target, steering_rate, gear_location,
             &simcar_status);

函数是运动学模型,也是实现轻量级仿真的关键所在。

PublishCanbus(&simcar_status);

该段代码是发出底盘信息,供planning和control模块使用。

PublishLocalization(&simcar_status);

该段代码是发出定位信息,供planning和control模块使用。

DEFINE_string(fake_initial_localization_file,
              "apollo/modules/control/conf"
              "fake_initial_localization.pb.txt",
              "Used for set inital localization.");

该段代码的fake_initial_localization.pb.txt是给仿真模型指定初始信息,可在地图上任意选点。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Apache Apollo服务器是一款高性能的消息代理服务器,可以用于构建分布式系统中的消息传递机制。以下是Apache Apollo服务器搭建的步骤: 1. 下载Apache Apollo服务器的安装包,并解压到指定的目录。 2. 配置Apollo服务器的环境变量,将安装目录添加到系统的PATH变量中。 3. 启动Apollo服务器,可以使用命令行启动或者使用脚本启动。 4. 配置Apollo服务器的参数,包括端口号、用户名密码等。 5. 创建消息队列和主题,可以使用Web管理界面或者命令行工具创建。 6. 使用客户端程序连接到Apollo服务器,发送和接收消息。 7. 监控和管理Apollo服务器,可以使用Web管理界面或者命令行工具进行监控和管理。 以上是Apache Apollo服务器搭建的基本步骤,需要根据具体的需求进行配置和调整。 ### 回答2: Apache Apollo是一个高性能的消息代理服务器,它采用了先进的AMQP 1.0协议,使得它在数据处理速度和灵活性方面都能有很好的表现。下面简单介绍一下Apache Apollo服务器的搭建。 1. 下载和解压缩 首先,需要从官方网站下载Apache Apollo服务器的安装包,并解压缩到本地目录。 2. 配置服务器 接下来,需要在解压缩后的目录中,找到conf文件夹下面的apollo.xml文件,并将其中的以下内容进行修改: - broker.xml中的transportConnector和virtualHost元素,调整为自己需要的端口和地址,这里可以指定多个端口和地址。 - login.config中的用户账号信息。 3. 启动服务器 完成上述配置后,就可以启动Apache Apollo服务器了。在解压缩后的目录下,执行以下命令即可启动服务器: ./bin/apollo-broker run 4. 设置开机自启 为了实现开机自启动,可以在/etc/init.d目录中创建一个脚本,然后在其中使用启动服务器的命令,以达到开机自启的效果。 以上就是简单的Apache Apollo服务器的搭建过程,需要注意的是,服务器的配置文件需要按照实际需求进行设置,例如可以设置消息队列的大小,调整网络缓存等等,以提升服务器的性能和可靠性。 ### 回答3: Apache Apollo是一个高性能、可靠的消息代理服务器,适用于处理大规模的消息流和事件处理。它是由Apache Foundation开发和维护的,完全开源,是一种灵活的、易于使用的消息传递解决方案。 在进行Apache Apollo服务器的搭建之前,需要安装Java环境,以便启动Apollo服务器。可以通过以下步骤来搭建Apache Apollo服务器: 第一步:下载和解压Apollo软件包 可以从Apache Apollo的官方网站上下载需要的软件包。解压缩文件后,进入bin目录,并运行脚本apollo-broker命令来启动Apollo服务器。在Windows系统下,可以双击运行apollo.bat文件。 第二步:配置Apollo服务器 可以通过修改conf目录下的apollo.xml文件来进行Apache Apollo服务器的配置。在这个配置文件中,可以配置相应的端口、日志记录、身份验证、消息队列等。 第三步:添加消息队列 在Apollo服务器上,可以添加多个消息队列。可以使用apollo script命令来创建新的消息队列。例如,如果要创建一个名为“MyQueue”的新队列,可以运行如下命令: apollo create /queues/MyQueue --type queue 第四步:测试Apache Apollo服务器 可以使用web管理界面或命令行工具来测试Apache Apollo服务器。在web管理界面下,可以访问http://localhost:61680来查看服务器的状态和队列的相关信息。在命令行下,运行apollo-broker命令,可以查看服务器运行日志和队列的报告信息。 需要注意的是,Apache Apollo服务器的配置和使用都需要一定的技术水平和经验。如果遇到问题,可以查看官方文档或论坛进行交流和帮助。同时,应该加强对服务器的安全性和保密性,避免信息泄露和攻击。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值