首页/文章/ 详情

汽车圈为啥越来越卷了?

10月前浏览179

一直不想谈这个话题,原因是,如果说不透就对不起观众,但如果说透了就必然会伤害很多人。然而,最近总有人问我,为啥这么卷?还要卷到什么时候?既然大家都想知道,那么就满足客户的需求吧。不保证说的一定正确和完整,只能保证自己思考的东西一定和盘托出。

(卷卷卷)

咋就卷起来了?

故事还是需要从十几年前说起,那时的国内汽车市场还是风平浪静的。合资、国企和民企等各方势力虽然一直都在竞争,但是很有序。大部分玩家至少都能赚到钱,而且从业人员也基本不用996与007。这种状态就如同一个菜市场的情形一样,里面的商户自在地卖着自己的菜:卖肉的安心卖肉,卖鱼的安心卖鱼,卖青菜的安心卖青菜。总之,大家虽然没有大富大贵,但小日子过得都怡然自得。

然而,这么祥和的景象逐渐被电动化的浪潮打破了。由于不用再搞发动机了,买块电池就可以让车跑起来了,于是400多家新势力相继入市,而且还有Tesla这条巨大的鲶鱼进来。这就像突然之间卖菜不需要自己有地才行了,于是大量的人有钱就可以来卖菜了。

这些新进来的商户,有的想卖肉,有的想卖鱼,还有的既想卖肉又想卖鱼。尽管商户多了许多,但菜市场还是那个菜市场,来买菜的人并没有增加。于是,大家就只能拼命的抢夺市场份额了,尤其是新进入市场的商户,纷纷使出浑身解数,把自己在其他行业取得成功的方法带了进来。一时间,菜市场中热闹非凡,各种新式的叫卖方式层出不穷。有人在网上卖,有人把摊位摆到了商场里面……

为了彰显自己的与众不同,有的人说自己的肉可以自己走路,有人说自己的鱼是智能的,有人说自己的菜是绿色的。同时,为了拉来更多的投资,并让买菜的人相信自己的东西好,把原来每个月才搞一次的销量排行变成了每周一次甚至每天公布,甚至搞起了预售。

竞争多了,价格战就无法避免了。大家把本就不高的利润率一降再降,甚至不惜亏本赚吆喝。为了能够活下来,各个老板就只能各显神通了。只是大家采取的策略不太相同。

一些人采用不断推陈出新的方式,试图让自己的产品能够有一些竞争力。于是,把以前需要三四年才能做完的事情压缩到一两年完成。

有些人绞尽脑汁来让自己的产品显得与众不同:从外观到内部,把自己能想到的东西都塞进去,并创造了大量的新名词。

(煎饼卷一切)

不管怎样,受苦的都是打工仔。再也没有可以按时上班下班的节奏了。老板亏钱的时候肯定不会让员工好受的。地主家没有余粮了,长工们不但要饿肚子,而且挨的鞭子也会更多。幸好,新势力那么多,打工的地方还是不缺的。只不过能干多久就全凭运气了。运气好的,能干上好几年,虽然累点,但至少还能按时领薪水。运气差的,一年半年就不得不再找其他的工作了,而且还可能被拖欠血汗钱。

为了参与价格战,大家不得不开始想办法降低成本。一方面是技术上的努力:保证基本功能和性能不变的前提下降本。另一方面,降低采购成本最为直接。由于所有的OEM都想着怎么降价,那么供应商们就必然很惨了。于是乎,供应商也开始向内卷,导致供应商的员工们也越来越辛苦了。

此外,在各种社交媒体和短视频平台的推波助澜下,大家的焦虑感更强了,于是就卷的更加厉害了。

(内要卷的紧实,外要奶油裱花)

因为啥就卷起来了?

以上只是对现象的浅层解释,实际上的原因要复杂的多。

首先,从技术的角度来讲。电动化是主要助推因素。其次是智能化。

在燃油车时代,发动机和变速箱的技术门槛还是很高的,搞得好的人不多。这就限制了能够上场参与竞争的玩家的数量。到了电动车时代,造车的门槛一下子下降了,动力系统可以轻松的花钱买到了,车身等传统部件的供应商体系已经很成熟,有经验的工程师数量也非常多了。因此,只要有钱就至少可以去尝试造车了。

然而,电动车与燃油车相比还有着众多的劣势,例如续航里程和补能的便利性等。而且相对而言,动力系统的成本过高。因此,为了让电动车这个新品种能够快速推广,大家纷纷把智能化的地位提的特别高。尽管这两个东西与电动化没有必然的联系,但这种宣传却客观上促进了智能座舱和智能驾驶的发展。于是,所谓的“软件定义汽车”出现了。又于是,众多不明就里的人泛化的把“软件”提到了至高无上的位置。大家互相“学习”,导致了同质化严重。为了避免同质化,就又不得不卷的更狠。因为,真正有独创能力和核心技术的人太少了,谁都不比谁强多少。

(吃我一卷)

其次,从宏观大环境上来讲,由于房地产的衰落和互联网大潮的逐渐退去,GDP的重担历史性的落到了汽车行业头上。我们这些年经济发展产生的大量资本的去处乏善可陈,因此,汽车这个体量足够大的行业成为了新的明显。众多的互联网大佬、IT巨头和家电大佬等纷纷下场,开始抢夺国内的汽车行业这个大蛋糕。身份从坐车的人转变为做车的人,类似于食客开始指导母鸡怎么下蛋。他们采用在互联网行业的思维,依仗着资本市场融来的钱,试图先不计成本的投入,等着把竞争对手搞死之后,自己能够一统江湖的时候再来割韭菜。

然而,汽车毕竟不是互联网,几百亿投下去都还没有见到回头钱。这导致众多的新势力死在了半路上。而且,由于汽车行业的玩家不只是咱们家里面的几个,还有众多的国际大鳄。即使放弃了中国市场,他们还是可以活得不错。这一点从下面这个全球销量排行就可以看出来。我们虽然搞得轰轰烈烈,但是国际竞争力还是有很大的差距,再加上大家为了PK,牺牲了利润,谁能活着见到明天的太阳也尚未可知。


身为卷中人

1. 未来汽车行业究竟是个什么样的格局,现在还很难下定论。毕竟影响因素太多了。

2. 市场中有人挑起价格战的时候,其他人很难不去跟随。因为,除非有足够的底气,否则销量的下降就是必然,这是任何一个企业家或者职业经理人都无法接受的。

3. 在这个充分竞争的存量市场中,如果不能打造自己的核心护城河,那么唯一的策略就是熬,把别人都熬死就剩者为王了。比的就是谁能活得更久!

4. 恶性竞争会伤害自己,杀敌一千自损八百。

5. 我们的目标应该是星辰大海,必须正视自己仍然很弱小的现实踏踏实实把技术做好,不能只靠博眼球来活着。

6. 造车是一个要至少持续几十年才能真正分出胜负的行业,打造核心竞争力才是真正的王道。至于啥是核心竞争力,请参见下图(车企的五力模型)。


努力卷到底!

这里,还想说一下中外的文化差异。国人的战略思维是与生俱来的,我们可以忍受短时间的损失,更加在乎未来。这种特质决定了我们在变革的时代能够抓住机遇。而老外更加在乎每一次交易的投资回报,虽然看似非常的精明,但这种思维方式更适合稳定的、线性发展的环境,属于工业时代思维,容易因小失大,错失机遇。

(看我七十二卷)

未来,鹿死谁手还真的很难说。虽然现在汽车行业中,确实存在着过度投资的现象,但也许只有这样,才能真正筛选出具有国际竞争力的选手。不搞掉一批没有竞争力的企业,新人就没有出头。这也许就是自然规律吧。

(新鲜,改变,没有终点)

变革总是能够为新人带来机会,产业结构也必然重组,全球格局也会随之而变。

(百卷齐放百卷争鸣)

最后,送给大家一首诗,由唐末农民起义领袖黄巢著的《不第后赋菊》。希望大家都能有前程似锦的未来。

待到春来九月八,我花开后百花杀,

冲天香阵透长安,满城尽带黄金甲。

原文完。

来源:车路漫漫
汽车
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2025-12-10
最近编辑:10月前
李慢慢
硕士 自动驾驶仿真工程师一枚
获赞 14粉丝 93文章 322课程 0
点赞
收藏
作者推荐

ROS2实战,自定义接口,让代码更优雅

在上一篇文章《ROS2实战,我写了个AEB程序,在CARLA中进行了仿真测试》中,我们创建了两个节点,实现了车辆信息的发布和订阅。但是聪明的你,一定发现当时的程序非常笨重,简单的车辆信息的发送,竟然用到了三个publisher对象,仅仅是因为发送的数据类型不一样,就要换一个publisher,这也太傻了。还好ROS 2提供了用户自定义接口的方法,可以把这些要发送的信息统一定义到一个接口类型中,然后打包发布,打包订阅。接口:两个程序之间进行信号对接,所采用的统一的数据格式。接下来我们看看怎么实现用户自定义接口。我们还是从零做起,先定义工作空间,再定义功能包,再设计代码,再配置代码,最后编译测试。1、创建ROS 2工作空间打开终端创建本次演示案例的工作空间:cd ~/ROS2_studymkdir ros2_ws_demo006_custom_interface/cd ros2_ws_demo006_custom_interface 2、创建功能包为了创建能够在不同功能包之间都通用的接口,我们把接口也独立出来定义成一个只有接口的功能包。进入工作空间,创建src文件夹来存放源码,在src下创建本次演示所需要的用户自定义的接口功能包。mkdir srccd srcros2 pkg create my_custom_interfaces --build-type ament_cmake my_custom_interfaces 是新包的名称。请注意,它只能是 CMake 包,但这并不限制我们可以在哪种类型的包中使用消息和服务。我们可以在 CMake 包中创建自定义接口,然后在 C++ 或 Python 节点中使用它。然后我们进入这个包,删除不必要的文件。cd my_custom_interfaces/rm -rf include/ src/ 然后创建我们需要的接口文件夹(msg),和其内的接口文件(MyCarlaInterface.msg):mkdir msgtouch msg/MyCarlaInterface.msg 注意,到此时,我们的整个工作空间下的目录还非常简单:ros2_ws_demo006_custom_interface/└── src └── my_custom_interfaces ├── CMakeLists.txt ├── msg │ └── MyCarlaInterface.msg └── package.xml3 directories, 3 files 3、编辑接口文件文件目录定义好了以后,就可以开始编辑文件内容了。首先要编辑的是我们自定义的接口文件MyCarlaInterface.msg。我这里内容如下:string ego_idfloat64 ego_speed_xfloat64 ego_speed_yfloat64 ego_speed_zfloat64 ego_position_xfloat64 ego_position_yfloat64 ego_position_zstring obj_idfloat64 obj_speed_xfloat64 obj_speed_yfloat64 obj_speed_zfloat64 obj_position_xfloat64 obj_position_yfloat64 obj_position_z 这些都是我们在上一节文章中要发布和订阅的车辆信号,我这里统一把他们都定义在这个文件里面了。每个信号的格式都是“类型+变量名”,变量名是用户自己定义的,变量类型可以参考如下列表:boolbytecharfloat32float64int8uint8int16uint16int32uint32int64uint64string 注意,上面的这些类型都是最最最基础的类型,其实ROS 2还基于这些基础数据继续封装以提供其他更为复杂数据类型,比如std_msgs、geometry_msgs等,它们其实就是对一些比较典型的接口进行了封装,我们接下来要做的就是根据我们自己的需求,做出跟这个差不多的东西来。4、配置接口文件打开CMakeLists.txt文件,添加如下内容:find_package(rosidl_default_generators REQUIRED)rosidl_generate_interfaces(${PROJECT_NAME} "msg/MyCarlaInterface.msg") 它的作用是定义将我们刚刚创建的接口文件使用rosidl工具编译成可以调用的库文件。再来看下CMakeLists.txt的完整内容吧:cmake_minimum_required(VERSION 3.5)project(tutorial_interfaces)# Default to C99if(NOT CMAKE_C_STANDARD) set(CMAKE_C_STANDARD 99)endif()# Default to C++14if(NOT CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 14)endif()if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wall -Wextra -Wpedantic)endif()# find dependenciesfind_package(ament_cmake REQUIRED)find_package(rosidl_default_generators REQUIRED)rosidl_generate_interfaces(${PROJECT_NAME} "msg/MyCarlaInterface.msg")ament_package() 接下来需要配置下package.xml文件,需要新增以下内容:<buildtool_depend>rosidl_default_generators</buildtool_depend><exec_depend>rosidl_default_runtime</exec_depend><member_of_group>rosidl_interface_packages</member_of_group> 完整的package.xml文件内容如下:<?xml version="1.0"?><?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?><package format="3"> <name>my_custom_interfaces</name> <version>0.0.0</version> <description>TODO: Package description</description> <maintainer email="goodman@todo.todo">goodman</maintainer> <license>TODO: License declaration</license> <buildtool_depend>ament_cmake</buildtool_depend> <test_depend>ament_lint_auto</test_depend> <test_depend>ament_lint_common</test_depend> <export> <build_type>ament_cmake</build_type> </export> <buildtool_depend>rosidl_default_generators</buildtool_depend> <exec_depend>rosidl_default_runtime</exec_depend> <member_of_group>rosidl_interface_packages</member_of_group> </package> 然后我们回到工作空间,编译一下这个接口功能包。cd ~/ROS2_study/ros2_ws_demo006_custom_interface/colcon build --packages-select my_custom_interfaces 看到屏幕显示的如下编译信息,就是编译成功了。Starting >>> my_custom_interfacesFinished <<< my_custom_interfaces [5.04s] Summary: 1 package finished [7.04s] 5、接口文件检查接下来我们使用ros2命令行工具检查下当前工作空间下的接口属性吧:source install/setup.bashros2 interface show my_custom_interfaces/msg/MyCarlaInterface 我们看到屏幕上打印出如下的内容:string ego_idfloat64 ego_speed_xfloat64 ego_speed_yfloat64 ego_speed_zfloat64 ego_position_xfloat64 ego_position_yfloat64 ego_position_zstring obj_idfloat64 obj_speed_xfloat64 obj_speed_yfloat64 obj_speed_zfloat64 obj_position_xfloat64 obj_position_yfloat64 obj_position_z 这可不就是我们定义好的接口文件的内容嘛,它现在已经在工作空间的接口库里了,后面我们就能直接调用了。6、创建新的功能包接下来就是对上一篇文章中的代码进行基于新接口的改造。切换到src目录下,创建新的功能包。cd srcros2 pkg create aeb_control_pkg --build-type ament_python --dependencies rclpy 此时,src下的目录树如下:src/├── aeb_control_pkg│ ├── aeb_control_pkg│ │ └── __init__.py│ ├── package.xml│ ├── resource│ │ └── aeb_control_pkg│ ├── setup.cfg│ ├── setup.py│ └── test│ ├── test_copyright.py│ ├── test_flake8.py│ └── test_pep257.py└── my_custom_interfaces ├── CMakeLists.txt ├── msg │ └── MyCarlaInterface.msg └── package.xml6 directories, 11 files 7、创建节点我们来继续定义aeb_control_pkg这个功能包下的节点文件,scenario_runner_node.py和controller_node.py。cd src/aeb_control_pkg/aeb_control_pkgtouch scenario_runner_node.pytouch controller_node.py 在scenario_runner_node.py中填入以下内容:import tracebackimport rclpyfrom rclpy.node import Nodefrom my_custom_interfaces.msg import MyCarlaInterfaceimport timeimport carlaimport tracebackclass PublisherNode(Node): def __init__(self): super().__init__('publisher_node') # self.carla_world = None self.connect_to_carla() self.ego_car = None self.obj_car = None self.ego_speed_x = None self.obj_speed_x = None self.ego_pos_x = None self.obj_pos_x = None self.actor_list = [] self.spawn_actor_ego(position=(0, 28, 1)) self.spawn_actor_obj(position=(50, 28, 1)) self.set_ego_speed(x=5.5, y=0, z=0) self.logger = self.get_logger() # self.my_publisher = self.create_publisher(MyCarlaInterface, '/carla/info', 10) self.timer = self.create_timer(1, self.publish_vehicle_info) def publish_vehicle_info(self): self.get_carla_data() # print(self.ego_pos_x, self.ego_speed_x, self.obj_pos_x, self.obj_speed_x) if None not in (self.ego_pos_x, self.ego_speed_x , self.obj_pos_x, self.obj_speed_x): my_carla_info = MyCarlaInterface() my_carla_info.ego_id = self.ego_car.id my_carla_info.obj_id = self.obj_car.id my_carla_info.ego_position_x = self.ego_pos_x my_carla_info.ego_position_y = 2.0 my_carla_info.ego_position_z = 0.0 my_carla_info.obj_position_x = self.obj_pos_x my_carla_info.obj_position_y = 2.0 my_carla_info.obj_position_z = 0.0 my_carla_info.ego_speed_x = self.ego_speed_x my_carla_info.ego_speed_y = 0.0 my_carla_info.ego_speed_z = 0.0 my_carla_info.obj_speed_x = self.obj_speed_x my_carla_info.obj_speed_y = 0.0 my_carla_info.obj_speed_z = 0.0 # to pulish all message... self.my_publisher.publish(my_carla_info) self.logger.info('Publishing... ego:position_x={},speed_x={},obj:position_x={},speed_x={}'.format( round(my_carla_info.ego_position_x,2), round(my_carla_info.ego_speed_x,2), round(my_carla_info.obj_position_x,2), round(my_carla_info.obj_speed_x,2))) else: print("debug data:", self.ego_pos_x, self.ego_speed_x, self.obj_pos_x, self.obj_speed_x) def connect_to_carla(self): carla_client = carla.Client(host="192.168.2.6", port=2000) carla_client.set_timeout(10) # second try: self.carla_world = carla_client.get_world() except RuntimeError as e: self.get_logger().error('can not connect to CARLA world.') raise e def spawn_actor_ego(self, position): blueprint_library = self.carla_world.get_blueprint_library() # for ego car my_bp = blueprint_library.filter("model3")[0] trans_loc = carla.Location(x=position[0], y=position[1], z=position[2]) trans_rot = carla.Rotation(pitch=0, yaw=0, roll=0) spawn_point = carla.Transform(trans_loc, trans_rot) my_car = self.carla_world.spawn_actor(my_bp, spawn_point) # print("ego position:", my_car.get_location()) self.ego_car = my_car self.actor_list.append(my_car) def spawn_actor_obj(self, position): obj_blueprint_library = self.carla_world.get_blueprint_library() # for ego car obj_my_bp = obj_blueprint_library.filter("mkz_2020")[0] obj_trans_loc = carla.Location(x=position[0], y=position[1], z=position[2]) obj_trans_rot = carla.Rotation(pitch=0, yaw=0, roll=0) obj_spawn_point = carla.Transform(obj_trans_loc, obj_trans_rot) obj_my_car = self.carla_world.spawn_actor(obj_my_bp, obj_spawn_point) self.obj_car = obj_my_car self.actor_list.append(obj_my_car) def set_ego_speed(self, x, y, z): if self.ego_car: # print("ego_car:", self.ego_car.id) target_speed = carla.Vector3D(x, y, z) # print("target_speed:", target_speed) self.ego_car.set_target_velocity(target_speed) def destroy_actors(self): for actor in self.actor_list: actor.destroy() self.get_logger().info(f"destroy actor: {actor}") def get_carla_data(self): if self.ego_car: ego_loc = self.ego_car.get_location() self.ego_pos_x = ego_loc.x ego_spd = self.ego_car.get_velocity() self.ego_speed_x = ego_spd.x # print("current_speed:", ego_spd) if self.obj_car: obj_loc = self.obj_car.get_location() self.obj_pos_x = obj_loc.x obj_spd = self.obj_car.get_velocity() self.obj_speed_x = obj_spd.x # passdef main(): try: rclpy.init() publisher_node = PublisherNode() rclpy.spin(publisher_node) except: traceback.print_exc() finally: publisher_node.destroy_actors() publisher_node.destroy_node() rclpy.shutdown()if __name__ == '__main__': main() 在controller_node.py中填入以下内容:import rclpyfrom rclpy.node import Nodefrom my_custom_interfaces.msg import MyCarlaInterfaceimport carlaclass SubscriberNode(Node): def __init__(self): super().__init__('subscriber_node') # self.ttc = None self.ego_speed_x = None self.obj_speed_x = None self.ego_position_x = None self.obj_position_x = None self.logger = self.get_logger() self.my_subscription = self.create_subscription(MyCarlaInterface, '/carla/info', self.callback, 10) # self.carla_world = None self.connect_to_carla() self.ego_car_id = None def callback(self, msg): self.logger.info('Received... ego:position_x={},speed_x={},obj:position_x={},speed_x={}'.format( round(msg.ego_position_x,2), round(msg.ego_speed_x,2), round(msg.obj_position_x,2), round(msg.obj_speed_x,2))) self.ego_car_id = msg.ego_id self.ego_speed_x = msg.ego_speed_x self.ego_position_x = msg.ego_position_x self.obj_speed_x = msg.obj_speed_x self.obj_position_x = msg.obj_position_x # self.calculate_ttc() # brake ego if self.ttc is not None: if 0 < self.ttc < 3: if self.ego_car_id is not None: ego_car = self.carla_world.get_actor(self.ego_car_id) brake_control = carla.VehicleControl(brake=1, steer=0, throttle=0) ego_car.apply_control(brake_control) self.logger.info('send braking order to ego car') def calculate_ttc(self): if None not in (self.ego_speed_x, self.obj_speed_x, self.ego_position_x, self.obj_position_x): distance = (self.obj_position_x - self.ego_position_x) speed_relative = self.ego_speed_x - self.obj_speed_x if speed_relative != 0: self.ttc = distance / speed_relative # print("ttc:", self.ttc) self.logger.info('ttc: {}'.format(self.ttc)) else: self.ttc = 999 else: self.logger.info('ttc: can not be calculated') # print(self.ego_speed_x) # print(self.obj_speed_x) # print(self.ego_position_x) # print(self.obj_position_x) def connect_to_carla(self): carla_client = carla.Client(host="192.168.2.6", port=2000) carla_client.set_timeout(10) # second try: self.carla_world = carla_client.get_world() except RuntimeError as e: self.get_logger().error('can not connect to CARLA world.') raise edef main(): rclpy.init() subscriber_node = SubscriberNode() rclpy.spin(subscriber_node) subscriber_node.destroy_node() rclpy.shutdown()if __name__ == '__main__': main() 8、配置节点节点文件编写好之后又到了配置阶段了,我们打开setup.py脚本,将两个节点配置进去。打开配置文件'src/aeb_control_pkg/setup.py',修改’console_scripts‘的内容:加入本次的两个节点,完成后的setup.py完整内容如下:from setuptools import setuppackage_name = 'aeb_control_pkg'setup( name=package_name, version='0.0.0', packages=[package_name], data_files=[ ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), ], install_requires=['setuptools'], zip_safe=True, maintainer='goodman', maintainer_email='goodman@todo.todo', description='TODO: Package description', license='TODO: License declaration', tests_require=['pytest'], entry_points={ 'console_scripts': [ "scenario_runner_node = aeb_control_pkg.scenario_runner_node:main", "controller_node = aeb_control_pkg.controller_node:main" ], },) 到这里,源码内容就已经准备好了。最后再来看看src下的文件目录:src/├── aeb_control_pkg│ ├── aeb_control_pkg│ │ ├── controller_node.py│ │ ├── __init__.py│ │ └── scenario_runner_node.py│ ├── package.xml│ ├── resource│ │ └── aeb_control_pkg│ ├── setup.cfg│ ├── setup.py│ └── test│ ├── test_copyright.py│ ├── test_flake8.py│ └── test_pep257.py└── my_custom_interfaces ├── CMakeLists.txt ├── msg │ └── MyCarlaInterface.msg └── package.xml6 directories, 13 files 9、编译和试运行回到工作空间下,编译功能包:cd ~/ROS2_study/ros2_ws_demo006_custom_interface/colcon build 编译过程很快,我这里终端打印的消息长这样:Starting >>> aeb_control_pkgStarting >>> my_custom_interfaces Finished <<< my_custom_interfaces [2.17s] Finished <<< aeb_control_pkg [3.52s] Summary: 2 packages finished [6.47s] 这样就表示编译完成啦。接下来就是测试了。由于两个ROS 2节点都是CARLA的客户端程序,在运行客户端程序前,我们应该先把CARLA的服务端打开。这样客户端后面才能连接连接到服务端。我这边的CARLA的服务端启动程序如下:cd path/to/your/carla./CarlaUE4.sh 然后等CARLA服务端完全运行起来后。我们新打开一个终端,输入节点1启动指令:source install/setup.bashros2 run aeb_control_pkg scenario_runner_node 此时,我们应该能从CARLA的服务端看到两辆车被创建了出来,并且主车逐渐靠近前方的目标车。如果没有下方的节点2启动,则主车会与目标车发生碰撞。然后在新打开一个终端,赶在碰撞前,把AEB控制节点运行起来:source install/setup.bashros2 run aeb_control_pkg controller_node 然后我们就能看到主车在撞到目标车前就制动停了下来。节点1打印的消息如下:节点2打印的消息如下:10、总结本节我们通过对车辆之间通信消息的自定义,把所有消息用一个接口文件包装了起来,这样在发布和订阅过程中都更加的优雅,逻辑更加清晰,代码简化了不少。然后基于新的接口文件重新优化了上一节的发布和订阅程序,实现了AEB功能的控制。完结,撒花。ROS 2中比较多使用这种自定义接口的方法,但是采用protobuf对数据进行发送能更轻量级、也能更定制化,但是我一直没有成功。不知道哪位道友有知道做法的可以一起探讨下。来源:车路漫漫

未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习计划 福利任务
下载APP
联系我们
帮助与反馈