ROS-raspi

树莓派ROS小车

安装树莓派相关ROS环境

安装ubuntu mate系统

下载ubuntu mate20.04镜像

image-20251023165941768

image-20251023170041982

image-20251023170222972

制作并烧录到SD卡里

  • 前往树莓派官网下载他的烧录工具

image-20251023170412766

  • 第一个选择烧录的设备型号(树莓派4B),第二个选择自己下载的ubuntu mate ,第三个选择烧录的位置,选择你的sd卡。随后点击烧录即可

    image-20251023170559247

  • 可以提前配置一下用户名、网络啥的。

进入树莓派ubuntu mate系统

把sd卡插入树莓派,随后插电开机。使用micro HDMI线连上显示器。

进行基本的配置,设置用户名密码、网络连接。

更换清华源,不再赘述。

安装network工具

1
sudo apt install net-tools

查看树莓派的ip

1
ifconfig

image-20251023171300357

将树莓派和主机放在同一局域网,测试ping通,在主机终端输入

1
ping 10.43.234.55(树莓派ip)

image-20251023171505520

这样就是ping通了,可以使用远程连接。

树莓派配置远程连接

ssh连接

直接终端连接

在ubuntu主机里,下载remmina连接工具。

ping通了之后,终端可以直接连,但是使用remmina工具更方便。

终端输入ssh <树莓派用户名>@<树莓派IP地址>

1
shh pi@10.43.234.55

image-20251023171926032

输入树莓派密码后就可以连接上了。

利于remmina

这是linux下一个软件能储存信息,方便连接:

点击左上角加好,再输入ip 密码啥的就可以连接了。

image-20251025164851196

利用TigerVNC进行远程桌面连接

先给ubuntu mate换个桌面,自带的mate桌面有点卡。

更换xfce4桌面并卸载自带mate桌面不赘述了(自行搜索)。

image-20251025165110719

个人IP

校园网环境下

​ PC有线连接校园网IP:10.43.173.38

​ 树莓派无线连接宿舍校园网IP:10.43.234.55

609wifi环境下:

​ PC有线连接校园网IP:10.43.173.38

​ 树莓派无线连接宿舍校园网IP:10.43.234.55

sync同步文件的使用

基本用法:

  • 路径在左边:意味着将左边同步到右边
  • 路径在右边:同理
1
2
sync <本地路径> <远程连接用户名>@<IP地址>:<远程路径>
# 注意空格,路径写全不要用~

sync同步命令是一次性的,每次输入都很长,很麻烦,编写一个脚本来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 树莓派目标目录
REMOTE_DIR=/home/pi/pi_ws/src

echo "==============================="
echo " 选择要同步的树莓派"
echo "==============================="

# 显示菜单
index=1
for name in "${!PI_HOSTS[@]}"; do
echo "$index. $name (${PI_HOSTS[$name]})"
names[$index]=$name
((index++))
done

# 用户输入编号
read -p "请输入编号 (1-$((index-1))): " choice

if [[ -z "${names[$choice]}" ]]; then
echo "无效的编号,退出。"
exit 1
fi

# 获取选择的名称和IP
SELECTED_NAME=${names[$choice]}
PI_HOST=${PI_HOSTS[$SELECTED_NAME]}

echo ""
echo " 已选择: $SELECTED_NAME ($PI_HOST)"
echo " 本地目录: $LOCAL_DIR/"
echo " 目标目录: $PI_USER@$PI_HOST:$REMOTE_DIR/"
echo ""

# 二次确认
read -p "确认执行同步吗?(y/n): " confirm
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
echo "已取消同步。"
exit 0
fi

# 检查设备是否在线
ping -c 1 -W 1 "$PI_HOST" &>/dev/null
if [[ $? -ne 0 ]]; then
echo "无法连接到 $PI_HOST,请检查网络。"
exit 1
fi

# Rsync 同步
rsync -avz --progress "${LOCAL_DIR}/" "${PI_USER}@${PI_HOST}:${REMOTE_DIR}/"

echo "同步到 $SELECTED_NAME 完成"
# --progress 命令可以中显示文件传输进度条,包括文件大小、已经传输的大小、传输速度和剩余时间
  • -a———>保留文件属性并递归复制目录
  • -v———>显示详细信息
  • -z———>压缩数据,加快传输
  • –progress———>显示每个文件传输进度

ROS与STM32间的通信

完成hello world!

首先,让STM32F407串口发送一个**”hello world!”**

linux下串口工具可以使用xTools:

image-20251025165649697

cutecom在我的环境下有显示的问题,不使用。

查询串口:

1
ls /dev/tty*

image-20251025170343631

可以通过插拔来查找usb串口通道

linux系统下串口无法使用问题:

  • 没有安装usb转ttl的驱动导致问题
  • 没有给予usb权限

解决方法:

  • 去下载对应芯片的驱动(ch340/ch9102),linux自带了cp210x的驱动
  • 使用chmod给对应串口通道施加权限,没有权限无法运行。
1
2
3
chmod 777 <设备通道>
eg:
chmod 777 /dev/ttyUSB0

ros串口发布节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include "ros/ros.h"
#include "std_msgs/String.h"
#include "serial/serial.h"

serial::Serial ser;
void serial_init() {
ser.setPort("/dev/ttyUSB0");//串口名称
ser.setBaudrate(115200);//波特率
serial::Timeout to = serial::Timeout::simpleTimeout(100);//等待时间
ser.setTimeout(to);

try {
ser.open();//打开串口
}
catch(serial::IOException& e){
ROS_ERROR_STREAM("Unable to open port.");
}
if (ser.isOpen()) {
ROS_INFO("/dev/ttyCH341USB0 is open");
}
else {
ROS_ERROR("/dev/ttyCH341USB0 open failed.");
}
}
int main(int argc, char **argv) {
//ROS初始化
ros::init(argc, argv, "stm32_Serial_test01");
ros::NodeHandle nh;
//创建ROS发布者节点
ros::Publisher stm32_pub = nh.advertise<std_msgs::String>("stm32_data", 10);
//串口相关配置
serial_init();
ros::Rate loop_rate(10);//设置循环速率
while(ros::ok())
{
//获取缓冲区内的字节数
size_t n = ser.available();
if (n != 0)
{
//定义一个缓冲区,将数据存放在此
uint8_t buffer[1024];
n = ser.read(buffer, n);

std::string received_data(buffer, buffer + n); // 将字节转成字符串
ROS_INFO_STREAM("Received data: " << received_data);
//将接受到的内容封装为ROS消息,并发布消息出去
std_msgs::String msg;
msg.data = received_data;
stm32_pub.publish(msg);

if (received_data.find("hello world!") != std::string::npos) {
ROS_INFO("STM32 sent: hello world!");
}
}
ros::spinOnce();
loop_rate.sleep();
}
ser.close();
return 0;
}

设置stm32串口发送到上位机后,开启此节点,可以看到成功接收。

编写键盘输入节点实现键盘控制小车移动

键盘输入节点

核心是如何读取键盘输入,然后转换成数据发送话题出去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// ----------- 函数功能:从终端读取单个按键,不需要按回车 ----------- //
int getch() {
struct termios oldt, newt;
int ch;

// 获取当前终端属性
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;

// 关闭规范模式(ICANON)和回显(ECHO),实现即时单字符读取
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);

// 读取单个字符
ch = getchar();

// 恢复终端原设置
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);

return ch;
}
int main(int argc, char** argv) {
// 初始化 ROS 节点,节点名为 keyboard_ctrl_pub
ros::init(argc, argv, "keyboard_control");
ros::NodeHandle nh;

// 创建 Publisher,发布主题为 /cmd_vel,消息类型为 geometry_msgs::Twist
ros::Publisher cmd_pub = nh.advertise<geometry_msgs::Twist>("cmd_vel", 10);

geometry_msgs::Twist cmd; // 创建 Twist 消息对象

std::cout << "\n=== 键盘控制说明 ===\n";
std::cout << "w: 前进 | s: 后退 | a: 左转 | d: 右转\n";
std::cout << "空格: 停止 | q: 退出程序\n";
std::cout << "====================\n";

// 主循环:持续读取键盘按键
while (ros::ok()) {
int c = getch(); // 获取键盘输入

// 每次先清零速度
cmd.linear.x = 0.0;
cmd.angular.z = 0.0;

// 按键控制逻辑
if (c == 'w') {
cmd.linear.x = 0.5; // 前进,线速度为 0.5 m/s
} else if (c == 's') {
cmd.linear.x = -0.5; // 后退
} else if (c == 'a') {
cmd.angular.z = 1.0; // 左转,角速度正方向
} else if (c == 'd') {
cmd.angular.z = -1.0; // 右转,角速度负方向
} else if (c == ' ') {
cmd.linear.x = 0; // 停止
cmd.angular.z = 0;
} else if (c == 'q') {
// 按 q 退出程序
std::cout << "退出程序\n";
break;
}

// 发布速度命令
cmd_pub.publish(cmd);

// 打印调试信息
ROS_INFO("发布速度: linear=%.2f m/s, angular=%.2f rad/s", cmd.linear.x, cmd.angular.z);
}

return 0;
}

编写了这个控制节点后,成功将数据利用话题的方式发布出去。

通信节点

前面写了键盘并且把