智能车学习笔记/备忘录乱写 | 地平线篇

DarthVictor / 2024-01-28 / 原文

前言

持续更新中!

校内赛打完分到地平线组了,好多新东西,写篇笔记记录。

比赛使用OriginBot车模,车模搭载Ubuntu系统。以后估计主要在Ubuntu虚拟机上工作。现在需要先学习ROS2和FoxGlove。

一些很基础或者很好记的东西就不写了。

常用网址

比赛简介(场地、车模、规则等)

FoxGlove教程

OriginBot教程

OriginBot开源套件

OriginBot PC端代码

ROS2课程

Linux

指令连Wifi

nmcli device wifi rescan        # 扫描wifi网络
nmcli device wifi list          # 列出找到的wifi网络
wifi_connect "SSID" "PASSWD"    # 连接某指定的wifi网络

后面的所有操作都是默认上位机和小车连接到同一局域网下进行的。

SSH

ssh <target_username>@<target_ip_address>可以直接连接到target的一个终端。

rsync <local_file_address> <target_username>@<target_ip_address>:<target_address>local_file_address发送到target的指定位置。在本机写完代码可以用这个同步到车上。下面是一个使用示例:

rsync -r "/home/darthvictor/test/src/python_test" root@192.168.100.228:/root/test/src

ROS2

基本原理

存在若干分工不同的结点同时运行,结点之间可以通过话题/服务相互沟通数据。

工作空间

ROS2的工作空间由src, build, install, build, log四个文件夹构成,其中源码在src里,结构是src-若干功能包-若干结点代码。

写完代码之后可通过rosdepc install -i --from-path src --rosdistro foxy -y自动安装依赖。

之后通过colcon build编译工作空间。

编译成功后运行source install/local_setup.sh将自己写好的包添加到环境变量里,就能运行包里的节点了。

当然,也可以运行一次echo "source ~/<workspace_name>/install/local_setup.sh">>~/.bashrc,这样此工作空间就被添加到.bashrc里了,以后再编译完就能直接运行这个包。

功能包

ros2 pkg create --build-type ament_cmake <package_name>创建使用C艹的功能包。

ros2 pkg create --build-type ament_python <package_name>创建使用python的功能包。

以下描述针对Python功能包:

在功能包内的同名文件夹内编写若干结点代码,之后需要在setup.py里添加结点代码的接口。

setup.py内部如下所示:

from setuptools import setup

package_name = 'python_test'

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='darthvictor',
    maintainer_email='darthvictor@todo.todo',
    description='TODO: Package description',
    license='TODO: License declaration',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
        	'test=python_test.test:main',
            'pub_test=python_test.pub_test:main',
            'sub_test=python_test.sub_test:main',
            'client_test=python_test.client_test:main',
            'server_test=python_test.server_test:main',
        ],
    },
)

添加接口的形式如'console_scripts'中所示。

结点

下面是一个简单、典型的结点代码,它会不断在日志里输出Hello,World!:

import rclpy #rclpy是一个提供了ROS2相关操作的库
from rclpy.node import Node
import time

def main(args=None):
	rclpy.init(args=args) #固定起手
	node=Node('test') #创建结点
	
	while rclpy.ok():
		node.get_logger().info('Hello,World!') #循环在日志中输出信息
		time.sleep(1)
		
	node.destroy_node() #运行结束后销毁结点
	rclpy.shutdown() #关闭ROS2

在编译之后用ros2 run <package_name> <node_name>运行节点。

话题

结点之间的数据沟通方式之一。由若干个Publisher单向发送数据,然后由若干个Subscriber单向接收数据,即支持多对多。

下面是一个典型的Publisher代码,它在chatter话题下循环发布信息:

import rclpy
from rclpy.node import Node
from std_msgs.msg import String #std_msgs.msg中包含了ROS2传递消息时一些常用的数据类型

class PublisherNode(Node): #创建结点类
    def __init__(self,name):
        super().__init__(name) #调用父类Node的初始化方法
        self.pub=self.create_publisher(String,'chatter',10) #创建了一个Publisher,它会在chatter主题下发布string类型的消息,队列长度为10(队列长度意为消息发不出去时最多储存的消息数)
        self.timer=self.create_timer(0.5,self.timer_callback) #创建一个定时器,每0.5s调用一次下面的timer_callback
    
    def timer_callback(self):
        msg=String() #创建一条信息
        msg.data='Hello,World!' #信息的内容
        self.pub.publish(msg) #发布信息
        self.get_logger().info('Message Published Successfully!')

def main(args=None):
    rclpy.init(args=args)
    node=PublisherNode('pub_test')
    rclpy.spin(node) #spin用于循环启动结点运行
    node.destroy_node()
    rclpy.shutdown()

下面是一个典型的Subscriber代码,它会不断接收chatter话题下的新信息:

import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class SubscriberNode(Node):
    def __init__(self,name):
        super().__init__(name)
        self.sub=self.create_subscription(String,'chatter',self.listener,10) #创建一个Subscriber,它不断从chatter获取字符串类型的信息,队列长度为10,当有新消息到达时,会传入listener处理
    
    def listener(self,msg):
        self.get_logger().info('I heard: %s'%msg.data) #listener在日志里输出收到的信息

def main(args=None):
    rclpy.init(args=args)
    node=SubscriberNode('sub_test')
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

OriginCar

代码编写

OriginBot机器人端的功能包都放置在/userdata/dev_ws工作空间,编写的时候参照上面的ROS2部分即可。

手操常用功能

这些方法都是使用指令控制的时候用的,实际上它们都已经集成到了FoxGlove里。

启动与运动控制

ros2 launch originbot_bringup originbot.launch.py use_camera:=true use_lidar:=true use_imu:=true启动底盘,后面两个参数决定是否同时启动摄像头和雷达。之后在第二个终端里使用ros2 run teleop_twist_keyboard teleop_twist_keyboard启动键盘控制结点即可控制小车。

摄像头

ros2 launch originbot_bringup camera_websoket_display.launch.py启动摄像头。之后在上位机打开http://<小车的IP地址>:8000即可查看摄像头。

FoxGlove

常用网址里给的FoxGlove教程网站写的足够详细干练了,直接看。

注意连接到机器人后要选择一下自己需要哪些话题的信息,然后选择性接收,否则接收所有话题的话传输会卡的一批。