|
|
本帖最后由 eefocus_4176750 于 2026-1-31 21:39 编辑
一.项目名称
基于树莓派5的4舵轮移动机器人
二.项目背景
在人工智能与嵌入式系统深度融合的背景下,智能移动机器人正朝着更高自主性、更强环境适应性以及更自然的人机交互方向演进。传统的遥控或固定路径控制方式已难以满足复杂动态场景下的灵活作业需求,而基于视觉的实时手势识别技术为实现直观、非接触式的人机协作提供了高效解决方案。 本项目设计并实现了一款基于树莓派5(Raspberry Pi 5)的四舵轮全向移动机器人系统,集成了轻量化YOLO目标检测模型与实时手势识别控制机制,构建了一个高性能、低延迟、高机动性的智能交互平台。该机器人采用四舵轮独立驱动与独立转向结构(即每个轮子均可独立控制转速与朝向),具备全向移动能力,可实现任意方向平移、原地零转弯、斜向穿行等复杂运动模式,显著提升在狭窄空间或动态障碍环境中的灵活性与通过性。 系统以树莓派5作为核心计算与控制单元,充分发挥其相较于前代产品更强的ARM Cortex-A76四核处理器、更快的LPDDR4X内存及增强型GPIO性能,支持在本地高效运行优化后的YOLOv8n或YOLOv5s等轻量级模型,实现对摄像头输入视频流中操作者手势(如“前进”“后退”“左平移”“右转”“停止”等)的实时检测与语义解析。识别结果经由自定义运动控制算法映射为四舵轮的协同驱动指令,完成低延迟、高响应的手势遥控操作。 此外,树莓派5丰富的外设接口(如双HDMI、PCIe、高速USB 3.0)和对Linux生态的良好支持,为后续集成IMU、编码器反馈、激光雷达、机械臂或ROS 2系统预留了良好扩展空间。本项目不仅验证了在低成本嵌入式平台上实现“感知-决策-执行”闭环的可行性,也为教育科研、智能竞赛、仓储巡检及未来服务机器人提供了一个兼具全向机动性、视觉智能与自然交互能力的技术原型。
三.代码设计框架
四.机械设计图纸
初始宇树关节电机4舵轮设计图纸
宇树舵轮初步安装示意图
因为宇树电机有个关节运行旋转迟钝 ,方案改成8个42步进电机
上面4个走位置模式
下面4个走速度模式
修改后机械图纸如下
实际基于树莓派4舵轮移动机器人
宇树关节电机测试代码
- #include <unistd.h>
- #include "serialPort/SerialPort.h"
- #include "unitreeMotor/unitreeMotor.h"
- int main() {
- SerialPort serial("/dev/ttyUSB0");
- MotorCmd cmd;
- MotorData data;
- while(true)
- {
- cmd.motorType = MotorType::GO_M8010_6;
- data.motorType = MotorType::GO_M8010_6;
- cmd.mode = queryMotorMode(MotorType::GO_M8010_6,MotorMode::FOC);
- cmd.id = 0;
- cmd.q = 60*queryGearRatio(MotorType::GO_M8010_6);
- cmd.dq = 0.01*queryGearRatio(MotorType::GO_M8010_6);
- cmd.kp = 0.01;
- cmd.kd = 0.01;
- cmd.tau = 0.0;
- serial.sendRecv(&cmd,&data);
- std::cout << std::endl;
- std::cout << "motor.q: " << data.q << std::endl;
- std::cout << "motor.temp: " << data.temp << std::endl;
- std::cout << "motor.W: " << data.dq << std::endl;
- std::cout << "motor.merror: " << data.merror << std::endl;
- std::cout << std::endl;
- usleep(200);
- }
- }
复制代码
张大头步进电机树莓派测试代码
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <termios.h>
- #include <sys/select.h>
- #include <pthread.h>
- #include <signal.h>
- #include "Emmv5.h"
- #define SERIAL_PORT "/dev/ttyUSB0"
- #define BAUD_RATE B115200
- #define BUFFER_SIZE 1024
- #define TIMEOUT_SEC 1
- // 全局变量
- int serial_fd = -1;
- volatile int running = 1;
- // 串口配置结构体
- struct termios tty_config;
- // 信号处理函数
- void signal_handler(int sig) {
- printf("\n接收到信号 %d,正在关闭串口...\n", sig);
- running = 0;
- if (serial_fd != -1) {
- close(serial_fd);
- }
- exit(0);
- }
- /**
- * 配置串口参数
- */
- int configure_serial_port(int fd) {
- struct termios tty;
-
- // 获取当前串口配置
- if(tcgetattr(fd, &tty) != 0) {
- perror("tcgetattr error");
- return -1;
- }
- // 设置波特率
- cfsetispeed(&tty, BAUD_RATE);
- cfsetospeed(&tty, BAUD_RATE);
- // 配置数据位、停止位、校验位
- tty.c_cflag &= ~PARENB; // 无奇偶校验
- tty.c_cflag &= ~CSTOPB; // 1个停止位
- tty.c_cflag &= ~CSIZE; // 清除数据位掩码
- tty.c_cflag |= CS8; // 8个数据位
- tty.c_cflag &= ~CRTSCTS; // 无硬件流控制
- tty.c_cflag |= CREAD | CLOCAL; // 使能接收器,本地连接
- // 配置读取选项
- tty.c_lflag &= ~ICANON; // 非规范模式
- tty.c_lflag &= ~ECHO; // 不显示字符
- tty.c_lflag &= ~ECHOE; // 不显示退格
- tty.c_lflag &= ~ISIG; // 不处理信号
- // 配置阻塞读取
- tty.c_iflag &= ~(IXON | IXOFF | IXANY); // 关闭软件流控制
- tty.c_oflag &= ~OPOST; // 关闭输出处理
- // 设置最小字符数和超时时间
- tty.c_cc[VMIN] = 0; // 非阻塞读取
- tty.c_cc[VTIME] = 10; // 1秒超时
- // 应用配置
- if (tcsetattr(fd, TCSANOW, &tty) != 0) {
- perror("tcsetattr error");
- return -1;
- }
- return 0;
- }
- /**
- * 打开串口连接
- */
- int open_serial_port(const char* port_name) {
- int fd = open(port_name, O_RDWR | O_NOCTTY | O_SYNC);
- if (fd < 0) {
- printf("无法打开串口 %s: %s\n", port_name, strerror(errno));
- return -1;
- }
- if (configure_serial_port(fd) < 0) {
- printf("配置串口失败\n");
- close(fd);
- return -1;
- }
- printf("成功连接到串口 %s\n", port_name);
- return fd;
- }
- /**
- * 关闭串口连接
- */
- void close_serial_port() {
- if (serial_fd != -1) {
- close(serial_fd);
- serial_fd = -1;
- printf("串口已关闭\n");
- }
- }
- /**
- * 发送数据到串口
- */
- int send_data(const char* data, size_t length) {
- if (serial_fd == -1) {
- printf("串口未连接\n");
- return -1;
- }
- ssize_t bytes_written = write(serial_fd, data, length);
- if (bytes_written < 0) {
- perror("write failed");
- return -1;
- }
- printf("发送数据: %.*s (%zd 字节)\n", (int)length, data, bytes_written);
- return bytes_written;
- }
- /**
- * 从串口接收数据
- */
- int receive_data(char* buffer, size_t buffer_size) {
- if (serial_fd == -1) {
- printf("串口未连接\n");
- return -1;
- }
- ssize_t bytes_read = read(serial_fd, buffer, buffer_size - 1);
- if (bytes_read < 0) {
- perror("read failed");
- return -1;
- }
- if (bytes_read > 0) {
- buffer[bytes_read] = '\0'; // 添加字符串结束符
- printf("[接收] %s", buffer);
- return bytes_read;
- }
- return 0; // 没有数据可读
- }
- /**
- * 接收线程函数 - 用于连续接收数据
- */
- void* receive_thread_func(void* arg) {
- char buffer[BUFFER_SIZE];
- fd_set read_fds;
- struct timeval timeout;
-
- while (running) {
- FD_ZERO(&read_fds);
- FD_SET(serial_fd, &read_fds);
-
- // 设置超时为1秒
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
-
- int activity = select(serial_fd + 1, &read_fds, NULL, NULL, &timeout);
-
- if (activity < 0) {
- if (errno != EINTR) {
- perror("select error");
- }
- continue;
- }
-
- if (FD_ISSET(serial_fd, &read_fds)) {
- ssize_t bytes_read = read(serial_fd, buffer, sizeof(buffer) - 1);
- if (bytes_read > 0) {
- buffer[bytes_read] = '\0';
- printf("\r[接收] %s\n> ", buffer);
- fflush(stdout);
- } else if (bytes_read < 0) {
- perror("read error");
- break;
- }
- }
- }
-
- return NULL;
- }
- /**
- * 显示帮助信息
- */
- void show_help() {
- printf("\nTTY USB串口通信程序\n");
- printf("=====================\n");
- printf("命令:\n");
- printf(" help - 显示此帮助信息\n");
- printf(" send - 发送数据\n");
- printf(" recv - 接收数据\n");
- printf(" continuous - 进入连续接收模式\n");
- printf(" quit - 退出程序\n\n");
- }
- /**
- * @brief 将当前位置清零
- * @param addr :电机地址
- * @retval 地址 + 功能码 + 命令状态 + 校验字节
- */
- void Emm_V5_Reset_CurPos_To_Zero(uint8_t addr)
- {
- uint8_t cmd[16] = {0};
-
- // 装载命令
- cmd[0] = addr; // 地址
- cmd[1] = 0x0A; // 功能码
- cmd[2] = 0x6D; // 辅助码
- cmd[3] = 0x6B; // 校验字节
-
- // 发送命令
- send_data((uint8_t *)cmd, 4);
- }
- /**
- * @brief 解除堵转保护
- * @param addr :电机地址
- * @retval 地址 + 功能码 + 命令状态 + 校验字节
- */
- void Emm_V5_Reset_Clog_Pro(uint8_t addr)
- {
- uint8_t cmd[16] = {0};
-
- // 装载命令
- cmd[0] = addr; // 地址
- cmd[1] = 0x0E; // 功能码
- cmd[2] = 0x52; // 辅助码
- cmd[3] = 0x6B; // 校验字节
-
- // 发送命令
- send_data((uint8_t *)cmd, 4);
- }
- /**
- * @brief 读取系统参数
- * @param addr :电机地址
- * @param s :系统参数类型
- * @retval 地址 + 功能码 + 命令状态 + 校验字节
- */
- void Emm_V5_Read_Sys_Params(uint8_t addr, SysParams_t s)
- {
- uint8_t i = 0;
- uint8_t cmd[16] = {0};
-
- // 装载命令
- cmd[i] = addr; ++i; // 地址
- switch(s) // 功能码
- {
- case S_VER : cmd[i] = 0x1F; ++i; break;
- case S_RL : cmd[i] = 0x20; ++i; break;
- case S_PID : cmd[i] = 0x21; ++i; break;
- case S_VBUS : cmd[i] = 0x24; ++i; break;
- case S_CPHA : cmd[i] = 0x27; ++i; break;
- case S_ENCL : cmd[i] = 0x31; ++i; break;
- case S_TPOS : cmd[i] = 0x33; ++i; break;
- case S_VEL : cmd[i] = 0x35; ++i; break;
- case S_CPOS : cmd[i] = 0x36; ++i; break;
- case S_PERR : cmd[i] = 0x37; ++i; break;
- case S_FLAG : cmd[i] = 0x3A; ++i; break;
- case S_ORG : cmd[i] = 0x3B; ++i; break;
- case S_Conf : cmd[i] = 0x42; ++i; cmd[i] = 0x6C; ++i; break;
- case S_State: cmd[i] = 0x43; ++i; cmd[i] = 0x7A; ++i; break;
- default: break;
- }
- cmd[i] = 0x6B; ++i; // 校验字节
-
- // 发送命令
- send_data((uint8_t *)cmd, i);
- }
- /**
- * @brief 修改开环/闭环控制模式
- * @param addr :电机地址
- * @param svF :是否存储标志,false为不存储,true为存储
- * @param ctrl_mode:控制模式(对应屏幕上的P_Pul菜单),0是关闭脉冲输入引脚,1是开环模式,2是闭环模式,3是让En端口复用为多圈限位开关输入引脚,Dir端口复用为到位输出高电平功能
- * @retval 地址 + 功能码 + 命令状态 + 校验字节
- */
- void Emm_V5_Modify_Ctrl_Mode(uint8_t addr, bool svF, uint8_t ctrl_mode)
- {
- uint8_t cmd[16] = {0};
-
- // 装载命令
- cmd[0] = addr; // 地址
- cmd[1] = 0x46; // 功能码
- cmd[2] = 0x69; // 辅助码
- cmd[3] = svF; // 是否存储标志,false为不存储,true为存储
- cmd[4] = ctrl_mode; // 控制模式(对应屏幕上的P_Pul菜单),0是关闭脉冲输入引脚,1是开环模式,2是闭环模式,3是让En端口复用为多圈限位开关输入引脚,Dir端口复用为到位输出高电平功能
- cmd[5] = 0x6B; // 校验字节
-
- // 发送命令
- send_data((uint8_t *)cmd, 6);
- }
- /**
- * @brief 使能信号控制
- * @param addr :电机地址
- * @param state :使能状态 ,true为使能电机,false为关闭电机
- * @param snF :多机同步标志 ,false为不启用,true为启用
- * @retval 地址 + 功能码 + 命令状态 + 校验字节
- */
- void Emm_V5_En_Control(uint8_t addr, bool state, bool snF)
- {
- uint8_t cmd[16] = {0};
-
- // 装载命令
- cmd[0] = addr; // 地址
- cmd[1] = 0xF3; // 功能码
- cmd[2] = 0xAB; // 辅助码
- cmd[3] = (uint8_t)state; // 使能状态
- cmd[4] = snF; // 多机同步运动标志
- cmd[5] = 0x6B; // 校验字节
-
- // 发送命令
- send_data((uint8_t *)cmd, 6);
- }
- /**
- * @brief 速度模式
- * @param addr:电机地址
- * @param dir :方向 ,0为CW,其余值为CCW
- * @param vel :速度 ,范围0 - 5000RPM
- * @param acc :加速度 ,范围0 - 255,注意:0是直接启动
- * @param snF :多机同步标志,false为不启用,true为启用
- * @retval 地址 + 功能码 + 命令状态 + 校验字节
- */
- void Emm_V5_Vel_Control(uint8_t addr, uint8_t dir, uint16_t vel, uint8_t acc, bool snF)
- {
- uint8_t cmd[16] = {0};
- // 装载命令
- cmd[0] = addr; // 地址
- cmd[1] = 0xF6; // 功能码
- cmd[2] = dir; // 方向
- cmd[3] = (uint8_t)(vel >> 8); // 速度(RPM)高8位字节
- cmd[4] = (uint8_t)(vel >> 0); // 速度(RPM)低8位字节
- cmd[5] = acc; // 加速度,注意:0是直接启动
- cmd[6] = snF; // 多机同步运动标志
- cmd[7] = 0x6B; // 校验字节
-
- // 发送命令
- send_data((uint8_t *)cmd, 8);
- }
- /**
- * @brief 位置模式
- * @param addr:电机地址
- * @param dir :方向 ,0为CW,其余值为CCW
- * @param vel :速度(RPM) ,范围0 - 5000RPM
- * @param acc :加速度 ,范围0 - 255,注意:0是直接启动
- * @param clk :脉冲数 ,范围0- (2^32 - 1)个
- * @param raF :相位/绝对标志,false为相对运动,true为绝对值运动
- * @param snF :多机同步标志 ,false为不启用,true为启用
- * @retval 地址 + 功能码 + 命令状态 + 校验字节
- */
- void Emm_V5_Pos_Control(uint8_t addr, uint8_t dir, uint16_t vel, uint8_t acc, uint32_t clk, bool raF, bool snF)
- {
- uint8_t cmd[16] = {0};
- // 装载命令
- cmd[0] = addr; // 地址
- cmd[1] = 0xFD; // 功能码
- cmd[2] = dir; // 方向
- cmd[3] = (uint8_t)(vel >> 8); // 速度(RPM)高8位字节
- cmd[4] = (uint8_t)(vel >> 0); // 速度(RPM)低8位字节
- cmd[5] = acc; // 加速度,注意:0是直接启动
- cmd[6] = (uint8_t)(clk >> 24); // 脉冲数(bit24 - bit31)
- cmd[7] = (uint8_t)(clk >> 16); // 脉冲数(bit16 - bit23)
- cmd[8] = (uint8_t)(clk >> 8); // 脉冲数(bit8 - bit15)
- cmd[9] = (uint8_t)(clk >> 0); // 脉冲数(bit0 - bit7 )
- cmd[10] = raF; // 相位/绝对标志,false为相对运动,true为绝对值运动
- cmd[11] = snF; // 多机同步运动标志,false为不启用,true为启用
- cmd[12] = 0x6B; // 校验字节
-
- // 发送命令
- send_data((uint8_t *)cmd, 13);
- }
- /**
- * @brief 角度模式
- * @param addr:电机地址
- * @param dir :方向 ,0为CW,其余值为CCW
- * @param vel :速度(RPM) ,范围0 - 5000RPM
- * @param acc :加速度 ,范围0 - 255,注意:0是直接启动
- * @param angle :角度 , 0~360
- * @param raF :相位/绝对标志,false为相对运动,true为绝对值运动
- * @param snF :多机同步标志 ,false为不启用,true为启用
- * @retval 地址 + 功能码 + 命令状态 + 校验字节
- */
- void Emm_V5_angle_Control(uint8_t addr, uint8_t dir, uint16_t vel, uint8_t acc, uint8_t angle ,bool raF, bool snF)
- {
-
- uint32_t clk = 0 ;
- clk = angle*3200/360 ;
- Emm_V5_Pos_Control(addr,dir,vel, acc, clk, raF, snF);
- }
- /**
- * @brief 立即停止(所有控制模式都通用)
- * @param addr :电机地址
- * @param snF :多机同步标志,false为不启用,true为启用
- * @retval 地址 + 功能码 + 命令状态 + 校验字节
- */
- void Emm_V5_Stop_Now(uint8_t addr, bool snF)
- {
- uint8_t cmd[16] = {0};
-
- // 装载命令
- cmd[0] = addr; // 地址
- cmd[1] = 0xFE; // 功能码
- cmd[2] = 0x98; // 辅助码
- cmd[3] = snF; // 多机同步运动标志
- cmd[4] = 0x6B; // 校验字节
-
- // 发送命令
- send_data((uint8_t *)cmd, 5);
- }
- /**
- * @brief 多机同步运动
- * @param addr :电机地址
- * @retval 地址 + 功能码 + 命令状态 + 校验字节
- */
- void Emm_V5_Synchronous_motion(uint8_t addr)
- {
- uint8_t cmd[16] = {0};
-
- // 装载命令
- cmd[0] = addr; // 地址
- cmd[1] = 0xFF; // 功能码
- cmd[2] = 0x66; // 辅助码
- cmd[3] = 0x6B; // 校验字节
-
- // 发送命令
- send_data((uint8_t *)cmd, 4);
- }
- /**
- * @brief 设置单圈回零的零点位置
- * @param addr :电机地址
- * @param svF :是否存储标志,false为不存储,true为存储
- * @retval 地址 + 功能码 + 命令状态 + 校验字节
- */
- void Emm_V5_Origin_Set_O(uint8_t addr, bool svF)
- {
- uint8_t cmd[16] = {0};
-
- // 装载命令
- cmd[0] = addr; // 地址
- cmd[1] = 0x93; // 功能码
- cmd[2] = 0x88; // 辅助码
- cmd[3] = svF; // 是否存储标志,false为不存储,true为存储
- cmd[4] = 0x6B; // 校验字节
-
- // 发送命令
- send_data((uint8_t *)cmd, 5);
- }
- /**
- * @brief 修改回零参数
- * @param addr :电机地址
- * @param svF :是否存储标志,false为不存储,true为存储
- * @param o_mode :回零模式,0为单圈就近回零,1为单圈方向回零,2为多圈无限位碰撞回零,3为多圈有限位开关回零
- * @param o_dir :回零方向,0为CW,其余值为CCW
- * @param o_vel :回零速度,单位:RPM(转/分钟)
- * @param o_tm :回零超时时间,单位:毫秒
- * @param sl_vel :无限位碰撞回零检测转速,单位:RPM(转/分钟)
- * @param sl_ma :无限位碰撞回零检测电流,单位:Ma(毫安)
- * @param sl_ms :无限位碰撞回零检测时间,单位:Ms(毫秒)
- * @param potF :上电自动触发回零,false为不使能,true为使能
- * @retval 地址 + 功能码 + 命令状态 + 校验字节
- */
- void Emm_V5_Origin_Modify_Params(uint8_t addr, bool svF, uint8_t o_mode, uint8_t o_dir, uint16_t o_vel, uint32_t o_tm, uint16_t sl_vel, uint16_t sl_ma, uint16_t sl_ms, bool potF)
- {
- uint8_t cmd[32] = {0};
-
- // 装载命令
- cmd[0] = addr; // 地址
- cmd[1] = 0x4C; // 功能码
- cmd[2] = 0xAE; // 辅助码
- cmd[3] = svF; // 是否存储标志,false为不存储,true为存储
- cmd[4] = o_mode; // 回零模式,0为单圈就近回零,1为单圈方向回零,2为多圈无限位碰撞回零,3为多圈有限位开关回零
- cmd[5] = o_dir; // 回零方向
- cmd[6] = (uint8_t)(o_vel >> 8); // 回零速度(RPM)高8位字节
- cmd[7] = (uint8_t)(o_vel >> 0); // 回零速度(RPM)低8位字节
- cmd[8] = (uint8_t)(o_tm >> 24); // 回零超时时间(bit24 - bit31)
- cmd[9] = (uint8_t)(o_tm >> 16); // 回零超时时间(bit16 - bit23)
- cmd[10] = (uint8_t)(o_tm >> 8); // 回零超时时间(bit8 - bit15)
- cmd[11] = (uint8_t)(o_tm >> 0); // 回零超时时间(bit0 - bit7 )
- cmd[12] = (uint8_t)(sl_vel >> 8); // 无限位碰撞回零检测转速(RPM)高8位字节
- cmd[13] = (uint8_t)(sl_vel >> 0); // 无限位碰撞回零检测转速(RPM)低8位字节
- cmd[14] = (uint8_t)(sl_ma >> 8); // 无限位碰撞回零检测电流(Ma)高8位字节
- cmd[15] = (uint8_t)(sl_ma >> 0); // 无限位碰撞回零检测电流(Ma)低8位字节
- cmd[16] = (uint8_t)(sl_ms >> 8); // 无限位碰撞回零检测时间(Ms)高8位字节
- cmd[17] = (uint8_t)(sl_ms >> 0); // 无限位碰撞回零检测时间(Ms)低8位字节
- cmd[18] = potF; // 上电自动触发回零,false为不使能,true为使能
- cmd[19] = 0x6B; // 校验字节
-
- // 发送命令
- send_data((uint8_t *)cmd, 20);
- }
- /**
- * @brief 触发回零
- * @param addr :电机地址
- * @param o_mode :回零模式,0为单圈就近回零,1为单圈方向回零,2为多圈无限位碰撞回零,3为多圈有限位开关回零
- * @param snF :多机同步标志,false为不启用,true为启用
- * @retval 地址 + 功能码 + 命令状态 + 校验字节
- */
- void Emm_V5_Origin_Trigger_Return(uint8_t addr, uint8_t o_mode, bool snF)
- {
- uint8_t cmd[16] = {0};
-
- // 装载命令
- cmd[0] = addr; // 地址
- cmd[1] = 0x9A; // 功能码
- cmd[2] = o_mode; // 回零模式,0为单圈就近回零,1为单圈方向回零,2为多圈无限位碰撞回零,3为多圈有限位开关回零
- cmd[3] = snF; // 多机同步运动标志,false为不启用,true为启用
- cmd[4] = 0x6B; // 校验字节
-
- // 发送命令
- send_data((uint8_t *)cmd, 5);
- }
- /**
- * @brief 强制中断并退出回零
- * @param addr :电机地址
- * @retval 地址 + 功能码 + 命令状态 + 校验字节
- */
- void Emm_V5_Origin_Interrupt(uint8_t addr)
- {
- uint8_t cmd[16] = {0};
-
- // 装载命令
- cmd[0] = addr; // 地址
- cmd[1] = 0x9C; // 功能码
- cmd[2] = 0x48; // 辅助码
- cmd[3] = 0x6B; // 校验字节
-
- // 发送命令
- send_data((uint8_t *)cmd, 5);
- }
- /**
- * 主函数
- */
- int main() {
- char input_buffer[BUFFER_SIZE];
- char command[64];
- pthread_t receive_thread;
- int continuous_mode = 0;
-
- // 注册信号处理器
- signal(SIGINT, signal_handler);
- signal(SIGTERM, signal_handler);
-
- printf("TTY USB串口通信程序 (C语言版本)\n");
- printf("==================================\n");
-
- // 打开串口
- serial_fd = open_serial_port(SERIAL_PORT);
- if (serial_fd < 0) {
- printf("无法打开串口 %s,程序退出\n", SERIAL_PORT);
- return 1;
- }
-
- show_help();
-
- while (running)
- {
- Emm_V5_Vel_Control(0x01,0x00,0x10,0x00,0x00);
- usleep(10000);
- Emm_V5_angle_Control(0x02,0x00,0x10,0x00,0xB4,0x01,0x00);
- usleep(10000);
- }
-
- // 停止连续接收模式
- if (continuous_mode)
- {
- running = 0;
- pthread_join(receive_thread, NULL);
- }
-
- // 关闭串口
- close_serial_port();
-
- printf("程序结束\n");
- return 0;
- }
复制代码
步进电机控制演示视频![]()
yolo 手势识别
yolo视觉识别手势控制四舵轮
|
|