WSL2中的Echo机器人环境安装
1.WSL2内Ubuntu安装
首先命令窗口cmd(PowerShell)内输入
wsl --list --online这样可以看到微软官方支持的所有 Linux 发行版列表
像这样
NAME FRIENDLY NAME
Ubuntu Ubuntu
Ubuntu-24.04 Ubuntu 24.04 LTS
openSUSE-Tumbleweed openSUSE Tumbleweed
openSUSE-Leap-16.0 openSUSE Leap 16.0
SUSE-Linux-Enterprise-15-SP7 SUSE Linux Enterprise 15 SP7
SUSE-Linux-Enterprise-16.0 SUSE Linux Enterprise 16.0
kali-linux Kali Linux Rolling
Debian Debian GNU/Linux
AlmaLinux-8 AlmaLinux OS 8
AlmaLinux-9 AlmaLinux OS 9
AlmaLinux-Kitten-10 AlmaLinux OS Kitten 10
AlmaLinux-10 AlmaLinux OS 10
archlinux Arch Linux
FedoraLinux-43 Fedora Linux 43
FedoraLinux-42 Fedora Linux 42
eLxr eLxr 12.12.0.0 GNU/Linux
Ubuntu-20.04 Ubuntu 20.04 LTS
Ubuntu-22.04 Ubuntu 22.04 LTS
OracleLinux_7_9 Oracle Linux 7.9
OracleLinux_8_10 Oracle Linux 8.10
OracleLinux_9_5 Oracle Linux 9.5
openSUSE-Leap-15.6 openSUSE Leap 15.6
SUSE-Linux-Enterprise-15-SP6 SUSE Linux Enterprise 15 SP6之后选择版本命令进行安装
wsl --install -d <换成你想安装的版本名称>示例:
wsl --install -d Ubuntu-22.04# 更新软件包列表
sudo apt-get update
# 升级已安装的软件包(可选,但推荐)
sudo apt-get upgrade -y1.安装依赖环境
sudo apt-get install repo git ssh make gcc gcc-multilib g++-multilib module-assistant expect g++ gawk texinfo libssl-dev bison flex fakeroot cmake unzip gperf autoconf device-tree-compiler libncurses5-dev pkg-config2.下拉完整项目(SDK和软件demo)
git clone https://github.com/No-Chicken/Echo-Mate.git
cd Echo-Mate
git submodule update --init --recursive3.如果要递归更新所有子模块,请执行:
git submodule update --remote --merge --recursive4.由于子仓库有大文件LFS,需要执行:
# 下拉lfs
git lfs pull
# 下拉所有lfs
git submodule foreach --recursive 'git lfs pull'2.获取SDK
#进入到SDK的目录
cd Echo-Mate
cd ./SDK/rv1106-sdk
首先需要在SDK文件夹选择板级配置,这里选择对应的开发板,选择echo mate的配置即可。如果使用[7]custom,会弹出所有的.mk文件
./build.sh lunch一键自动编译(会自动下载交叉编译的工具链及相关配置)
./build.sh 如果PATH环境变量的目录出错,则换一个临时的PATH目录
清理缓存
./build.sh clean # 清理编译产物(如果失败则先清理一下缓存)3. 使用开发板demo的修改
打开DeskBot_demo目录
cd Echo-Mate/Demo/DeskBot_demo① 把conf文件夹中的dev_conf.h中的内容更换
#define LV_USE_SIMULATOR 0 (把这个宏定义的1改成0)② 把里面的toolchain.cmake的SDK_PATH目录换一下
set(SDK_PATH "/home/arthur/Echo-Mate/SDK/rv1106-sdk") #换成自己的目录# 把这个sysroot也换成自己的目录
# Specify the sysroot (if available)
set(CMAKE_SYSROOT ${SDK_PATH}/sysdrv/source/buildroot/buildroot-2023.02.6/output/host/arm-buildroot-linux-uclibcgnueabihf/sysroot)③ 把CMakeLists.txt
# Option to choose target architecture
option(TARGET_ARM "Build for ARM architecture" ON) // OFF改成ON4. 烧录进开发板
之后安装教程进入
cd ./Demo
cd ./DeskBot_demo
mkdir ./build
cd ./build
cmake ..
make
make -j4
rm -rf * # 清理缓存把编译好的bin文件使用ADB传输进开发板
在Windows的CMD/PowerShell中操作:
adb push F:\bin /root/
# 推送整个 bin 文件夹到 /root 目录
adb push C:\Users\Arthur\Downloads\bin /root/
# 前面windows的目录换成自己的,这里是把WSL内编译好的放到了windows中adb push C:\Users\Arthur\Downloads\bin /root/
adb shell chmod +x /root/bin/main
reboot# 文件传进开发板
scp -r ./bin root@192.168.0.6:/root/
scp -r ./bin root@172.32.0.93:/root/# 开发板传出文件,注意是传到当前目录下了
scp -r root@192.168.0.6:/root/test ./
scp -r root@172.32.0.93:/root/test ./
# 进入开发板
adb shell
ssh root@192.168.0.6
ssh root@172.32.0.93运行
adb shell # 进入开发板系统cd ../bin
chmod +x main #加入可执行操作
./main # 进入bin文件后运行这个main可执行程序5. 开机自启动
解决需要执行指令才能运行的问题
修改启动脚本
# 编辑脚本
vi /etc/init.d/S99main添加上这些:
#!/bin/sh
cd /root/bin && ./main &/etc/init.d/S99main # 重启脚本
chmod +x /etc/init.d/S99main6.开机联网
# 1. 配置 WiFi 信息
cat > /etc/wpa_supplicant.conf << EOF
ctrl_interface=/var/run/wpa_supplicant
ap_scan=1
network={
ssid="your name"
psk="your password"
}
EOF
# 2. 恢复网络接口配置(保持干净)
cat > /etc/network/interfaces << EOF
# interface file auto-generated by buildroot
auto lo
iface lo inet loopback
EOF
# 3. 创建 WiFi 自启动脚本
cat > /etc/init.d/S95wifi << 'EOF'
#!/bin/sh
(
sleep 10
ifconfig wlan0 up
wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf
sleep 5
udhcpc -i wlan0 -q > /dev/null 2>&1
) &
EOF
chmod +x /etc/init.d/S95wifi
# 4. 确保 main 自启动脚本正确
cat > /etc/init.d/S99main << 'EOF'
#!/bin/sh
cd /root/bin && ./main &
EOF
chmod +x /etc/init.d/S99main
# 5. 重启测试
reboot7. 解决双进程问题
加入自启动之后,这看不了这个调试信息,再次手动启动main可执行文件会导致双进程切换卡顿的问题
在 main.c 开头添加了 自动杀旧进程 的机制:
// 1. 查找所有 main 进程
FILE *fp = popen("pidof main", "r");
// 2. 如果找到其他 main 进程
if (找到其他进程) {
kill(其他进程PID, SIGTERM); // 杀掉它
usleep(100000); // 等它彻底退出
}
// 3. 设置调试输出
if (isatty(STDOUT_FILENO)) {
// 手动运行 → 输出调试信息
} else {
// 自启动 → 静默运行
freopen("/dev/null", "w", stdout);
}//示例:
static void kill_other_main_processes(void)
{
// 获取当前进程PID
pid_t my_pid = getpid();
// 执行命令查找所有 main 进程
FILE *fp = popen("pidof main", "r");
if (!fp) {
return; // 无法执行命令,直接返回
}
char line[128];
if (fgets(line, sizeof(line), fp)) {
// 解析出所有PID(可能多个,用空格分隔)
char *token = strtok(line, " \n");
while (token) {
pid_t other_pid = atoi(token);
// 如果是其他进程(不是自己),杀掉它
if (other_pid > 0 && other_pid != my_pid) {
// 手动运行时才显示调试信息
if (isatty(STDOUT_FILENO)) {
printf("[Main] Killing old process: PID=%d\n", other_pid);
}
kill(other_pid, SIGTERM); // 发送终止信号
usleep(50000); // 等50ms
}
token = strtok(NULL, " \n");
}
}
pclose(fp);
// 再等一会儿确保旧进程完全退出
usleep(100000); // 100ms
}
//在main函数中:
// ===== 第一步:杀死其他 main 进程 =====
// 这个函数会杀掉已经存在的 main 进程(包括开机自启动的那个)
kill_other_main_processes();
// ===== 第二步:设置调试输出 =====
if (isatty(STDOUT_FILENO)) {
// 有终端 = 手动运行 = 调试模式
printf("\n================================\n");
printf("System Monitor (Manual Debug Mode)\n");
printf("================================\n");
// 保持正常输出
} else {
// 无终端 = 后台自启动 = 静默模式
// 重定向所有输出到 /dev/null
freopen("/dev/null", "w", stdout);
freopen("/dev/null", "w", stderr);
}