回答

收藏

[项目提交] 《DigiKey AI应用创意挑战赛项目》-基于树莓派5 的4舵轮智能移动机器人

2025 DigiKey AI应用创意挑战赛 2025 DigiKey AI应用创意挑战赛 513 人阅读 | 0 人回复 | 2026-01-14

本帖最后由 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舵轮移动机器人

宇树关节电机测试代码

  1. #include <unistd.h>
  2. #include "serialPort/SerialPort.h"
  3. #include "unitreeMotor/unitreeMotor.h"


  4. int main() {

  5.   SerialPort  serial("/dev/ttyUSB0");
  6.   MotorCmd    cmd;
  7.   MotorData   data;

  8.   while(true)
  9.   {
  10.         cmd.motorType = MotorType::GO_M8010_6;
  11.         data.motorType = MotorType::GO_M8010_6;
  12.         cmd.mode = queryMotorMode(MotorType::GO_M8010_6,MotorMode::FOC);
  13.         cmd.id   = 0;

  14.         cmd.q    = 60*queryGearRatio(MotorType::GO_M8010_6);
  15.         cmd.dq   = 0.01*queryGearRatio(MotorType::GO_M8010_6);
  16.         cmd.kp   = 0.01;
  17.         cmd.kd   = 0.01;
  18.         cmd.tau  = 0.0;
  19.         serial.sendRecv(&cmd,&data);

  20.         std::cout <<  std::endl;
  21.         std::cout <<  "motor.q: "    << data.q    <<  std::endl;
  22.         std::cout <<  "motor.temp: "   << data.temp   <<  std::endl;
  23.         std::cout <<  "motor.W: "      << data.dq      <<  std::endl;
  24.         std::cout <<  "motor.merror: " << data.merror <<  std::endl;
  25.         std::cout <<  std::endl;

  26.             usleep(200);
  27.   }

  28. }
复制代码

张大头步进电机树莓派测试代码
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <errno.h>
  7. #include <termios.h>
  8. #include <sys/select.h>
  9. #include <pthread.h>
  10. #include <signal.h>
  11. #include "Emmv5.h"


  12. #define SERIAL_PORT "/dev/ttyUSB0"
  13. #define BAUD_RATE B115200
  14. #define BUFFER_SIZE 1024
  15. #define TIMEOUT_SEC 1

  16. // 全局变量
  17. int serial_fd = -1;
  18. volatile int running = 1;

  19. // 串口配置结构体
  20. struct termios tty_config;

  21. // 信号处理函数
  22. void signal_handler(int sig) {
  23.     printf("\n接收到信号 %d,正在关闭串口...\n", sig);
  24.     running = 0;
  25.     if (serial_fd != -1) {
  26.         close(serial_fd);
  27.     }
  28.     exit(0);
  29. }

  30. /**
  31. * 配置串口参数
  32. */
  33. int configure_serial_port(int fd) {
  34.     struct termios tty;
  35.    
  36.     // 获取当前串口配置
  37.     if(tcgetattr(fd, &tty) != 0) {
  38.         perror("tcgetattr error");
  39.         return -1;
  40.     }

  41.     // 设置波特率
  42.     cfsetispeed(&tty, BAUD_RATE);
  43.     cfsetospeed(&tty, BAUD_RATE);

  44.     // 配置数据位、停止位、校验位
  45.     tty.c_cflag &= ~PARENB;  // 无奇偶校验
  46.     tty.c_cflag &= ~CSTOPB;  // 1个停止位
  47.     tty.c_cflag &= ~CSIZE;   // 清除数据位掩码
  48.     tty.c_cflag |= CS8;      // 8个数据位
  49.     tty.c_cflag &= ~CRTSCTS; // 无硬件流控制
  50.     tty.c_cflag |= CREAD | CLOCAL; // 使能接收器,本地连接

  51.     // 配置读取选项
  52.     tty.c_lflag &= ~ICANON;  // 非规范模式
  53.     tty.c_lflag &= ~ECHO;    // 不显示字符
  54.     tty.c_lflag &= ~ECHOE;   // 不显示退格
  55.     tty.c_lflag &= ~ISIG;    // 不处理信号

  56.     // 配置阻塞读取
  57.     tty.c_iflag &= ~(IXON | IXOFF | IXANY); // 关闭软件流控制
  58.     tty.c_oflag &= ~OPOST; // 关闭输出处理

  59.     // 设置最小字符数和超时时间
  60.     tty.c_cc[VMIN] = 0;  // 非阻塞读取
  61.     tty.c_cc[VTIME] = 10; // 1秒超时

  62.     // 应用配置
  63.     if (tcsetattr(fd, TCSANOW, &tty) != 0) {
  64.         perror("tcsetattr error");
  65.         return -1;
  66.     }

  67.     return 0;
  68. }

  69. /**
  70. * 打开串口连接
  71. */
  72. int open_serial_port(const char* port_name) {
  73.     int fd = open(port_name, O_RDWR | O_NOCTTY | O_SYNC);
  74.     if (fd < 0) {
  75.         printf("无法打开串口 %s: %s\n", port_name, strerror(errno));
  76.         return -1;
  77.     }

  78.     if (configure_serial_port(fd) < 0) {
  79.         printf("配置串口失败\n");
  80.         close(fd);
  81.         return -1;
  82.     }

  83.     printf("成功连接到串口 %s\n", port_name);
  84.     return fd;
  85. }

  86. /**
  87. * 关闭串口连接
  88. */
  89. void close_serial_port() {
  90.     if (serial_fd != -1) {
  91.         close(serial_fd);
  92.         serial_fd = -1;
  93.         printf("串口已关闭\n");
  94.     }
  95. }

  96. /**
  97. * 发送数据到串口
  98. */
  99. int send_data(const char* data, size_t length) {
  100.     if (serial_fd == -1) {
  101.         printf("串口未连接\n");
  102.         return -1;
  103.     }

  104.     ssize_t bytes_written = write(serial_fd, data, length);
  105.     if (bytes_written < 0) {
  106.         perror("write failed");
  107.         return -1;
  108.     }

  109.     printf("发送数据: %.*s (%zd 字节)\n", (int)length, data, bytes_written);
  110.     return bytes_written;
  111. }

  112. /**
  113. * 从串口接收数据
  114. */
  115. int receive_data(char* buffer, size_t buffer_size) {
  116.     if (serial_fd == -1) {
  117.         printf("串口未连接\n");
  118.         return -1;
  119.     }

  120.     ssize_t bytes_read = read(serial_fd, buffer, buffer_size - 1);
  121.     if (bytes_read < 0) {
  122.         perror("read failed");
  123.         return -1;
  124.     }

  125.     if (bytes_read > 0) {
  126.         buffer[bytes_read] = '\0'; // 添加字符串结束符
  127.         printf("[接收] %s", buffer);
  128.         return bytes_read;
  129.     }

  130.     return 0; // 没有数据可读
  131. }

  132. /**
  133. * 接收线程函数 - 用于连续接收数据
  134. */
  135. void* receive_thread_func(void* arg) {
  136.     char buffer[BUFFER_SIZE];
  137.     fd_set read_fds;
  138.     struct timeval timeout;
  139.    
  140.     while (running) {
  141.         FD_ZERO(&read_fds);
  142.         FD_SET(serial_fd, &read_fds);
  143.         
  144.         // 设置超时为1秒
  145.         timeout.tv_sec = 1;
  146.         timeout.tv_usec = 0;
  147.         
  148.         int activity = select(serial_fd + 1, &read_fds, NULL, NULL, &timeout);
  149.         
  150.         if (activity < 0) {
  151.             if (errno != EINTR) {
  152.                 perror("select error");
  153.             }
  154.             continue;
  155.         }
  156.         
  157.         if (FD_ISSET(serial_fd, &read_fds)) {
  158.             ssize_t bytes_read = read(serial_fd, buffer, sizeof(buffer) - 1);
  159.             if (bytes_read > 0) {
  160.                 buffer[bytes_read] = '\0';
  161.                 printf("\r[接收] %s\n> ", buffer);
  162.                 fflush(stdout);
  163.             } else if (bytes_read < 0) {
  164.                 perror("read error");
  165.                 break;
  166.             }
  167.         }
  168.     }
  169.    
  170.     return NULL;
  171. }

  172. /**
  173. * 显示帮助信息
  174. */
  175. void show_help() {
  176.     printf("\nTTY USB串口通信程序\n");
  177.     printf("=====================\n");
  178.     printf("命令:\n");
  179.     printf("  help     - 显示此帮助信息\n");
  180.     printf("  send     - 发送数据\n");
  181.     printf("  recv     - 接收数据\n");
  182.     printf("  continuous - 进入连续接收模式\n");
  183.     printf("  quit     - 退出程序\n\n");
  184. }

  185. /**
  186.   * @brief    将当前位置清零
  187.   * @param    addr  :电机地址
  188.   * @retval   地址 + 功能码 + 命令状态 + 校验字节
  189.   */
  190. void Emm_V5_Reset_CurPos_To_Zero(uint8_t addr)
  191. {
  192.   uint8_t cmd[16] = {0};
  193.   
  194.   // 装载命令
  195.   cmd[0] =  addr;                       // 地址
  196.   cmd[1] =  0x0A;                       // 功能码
  197.   cmd[2] =  0x6D;                       // 辅助码
  198.   cmd[3] =  0x6B;                       // 校验字节
  199.   
  200.   // 发送命令
  201.   send_data((uint8_t *)cmd, 4);
  202. }

  203. /**
  204.   * @brief    解除堵转保护
  205.   * @param    addr  :电机地址
  206.   * @retval   地址 + 功能码 + 命令状态 + 校验字节
  207.   */
  208. void Emm_V5_Reset_Clog_Pro(uint8_t addr)
  209. {
  210.   uint8_t cmd[16] = {0};
  211.   
  212.   // 装载命令
  213.   cmd[0] =  addr;                       // 地址
  214.   cmd[1] =  0x0E;                       // 功能码
  215.   cmd[2] =  0x52;                       // 辅助码
  216.   cmd[3] =  0x6B;                       // 校验字节
  217.   
  218.   // 发送命令
  219.   send_data((uint8_t *)cmd, 4);
  220. }

  221. /**
  222.   * @brief    读取系统参数
  223.   * @param    addr  :电机地址
  224.   * @param    s     :系统参数类型
  225.   * @retval   地址 + 功能码 + 命令状态 + 校验字节
  226.   */
  227. void Emm_V5_Read_Sys_Params(uint8_t addr, SysParams_t s)
  228. {
  229.   uint8_t i = 0;
  230.   uint8_t cmd[16] = {0};
  231.   
  232.   // 装载命令
  233.   cmd[i] = addr; ++i;                   // 地址

  234.   switch(s)                             // 功能码
  235.   {
  236.     case S_VER  : cmd[i] = 0x1F; ++i; break;
  237.     case S_RL   : cmd[i] = 0x20; ++i; break;
  238.     case S_PID  : cmd[i] = 0x21; ++i; break;
  239.     case S_VBUS : cmd[i] = 0x24; ++i; break;
  240.     case S_CPHA : cmd[i] = 0x27; ++i; break;
  241.     case S_ENCL : cmd[i] = 0x31; ++i; break;
  242.     case S_TPOS : cmd[i] = 0x33; ++i; break;
  243.     case S_VEL  : cmd[i] = 0x35; ++i; break;
  244.     case S_CPOS : cmd[i] = 0x36; ++i; break;
  245.     case S_PERR : cmd[i] = 0x37; ++i; break;
  246.     case S_FLAG : cmd[i] = 0x3A; ++i; break;
  247.     case S_ORG  : cmd[i] = 0x3B; ++i; break;
  248.     case S_Conf : cmd[i] = 0x42; ++i; cmd[i] = 0x6C; ++i; break;
  249.     case S_State: cmd[i] = 0x43; ++i; cmd[i] = 0x7A; ++i; break;
  250.     default: break;
  251.   }

  252.   cmd[i] = 0x6B; ++i;                   // 校验字节
  253.   
  254.   // 发送命令
  255.   send_data((uint8_t *)cmd, i);
  256. }

  257. /**
  258.   * @brief    修改开环/闭环控制模式
  259.   * @param    addr     :电机地址
  260.   * @param    svF      :是否存储标志,false为不存储,true为存储
  261.   * @param    ctrl_mode:控制模式(对应屏幕上的P_Pul菜单),0是关闭脉冲输入引脚,1是开环模式,2是闭环模式,3是让En端口复用为多圈限位开关输入引脚,Dir端口复用为到位输出高电平功能
  262.   * @retval   地址 + 功能码 + 命令状态 + 校验字节
  263.   */
  264. void Emm_V5_Modify_Ctrl_Mode(uint8_t addr, bool svF, uint8_t ctrl_mode)
  265. {
  266.   uint8_t cmd[16] = {0};
  267.   
  268.   // 装载命令
  269.   cmd[0] =  addr;                       // 地址
  270.   cmd[1] =  0x46;                       // 功能码
  271.   cmd[2] =  0x69;                       // 辅助码
  272.   cmd[3] =  svF;                        // 是否存储标志,false为不存储,true为存储
  273.   cmd[4] =  ctrl_mode;                  // 控制模式(对应屏幕上的P_Pul菜单),0是关闭脉冲输入引脚,1是开环模式,2是闭环模式,3是让En端口复用为多圈限位开关输入引脚,Dir端口复用为到位输出高电平功能
  274.   cmd[5] =  0x6B;                       // 校验字节
  275.   
  276.   // 发送命令
  277.   send_data((uint8_t *)cmd, 6);
  278. }

  279. /**
  280.   * @brief    使能信号控制
  281.   * @param    addr  :电机地址
  282.   * @param    state :使能状态     ,true为使能电机,false为关闭电机
  283.   * @param    snF   :多机同步标志 ,false为不启用,true为启用
  284.   * @retval   地址 + 功能码 + 命令状态 + 校验字节
  285.   */
  286. void Emm_V5_En_Control(uint8_t addr, bool state, bool snF)
  287. {
  288.   uint8_t cmd[16] = {0};
  289.   
  290.   // 装载命令
  291.   cmd[0] =  addr;                       // 地址
  292.   cmd[1] =  0xF3;                       // 功能码
  293.   cmd[2] =  0xAB;                       // 辅助码
  294.   cmd[3] =  (uint8_t)state;             // 使能状态
  295.   cmd[4] =  snF;                        // 多机同步运动标志
  296.   cmd[5] =  0x6B;                       // 校验字节
  297.   
  298.   // 发送命令
  299.   send_data((uint8_t *)cmd, 6);
  300. }

  301. /**
  302.   * @brief    速度模式
  303.   * @param    addr:电机地址
  304.   * @param    dir :方向       ,0为CW,其余值为CCW
  305.   * @param    vel :速度       ,范围0 - 5000RPM
  306.   * @param    acc :加速度     ,范围0 - 255,注意:0是直接启动
  307.   * @param    snF :多机同步标志,false为不启用,true为启用
  308.   * @retval   地址 + 功能码 + 命令状态 + 校验字节
  309.   */
  310. void Emm_V5_Vel_Control(uint8_t addr, uint8_t dir, uint16_t vel, uint8_t acc, bool snF)
  311. {
  312.   uint8_t cmd[16] = {0};

  313.   // 装载命令
  314.   cmd[0] =  addr;                       // 地址
  315.   cmd[1] =  0xF6;                       // 功能码
  316.   cmd[2] =  dir;                        // 方向
  317.   cmd[3] =  (uint8_t)(vel >> 8);        // 速度(RPM)高8位字节
  318.   cmd[4] =  (uint8_t)(vel >> 0);        // 速度(RPM)低8位字节
  319.   cmd[5] =  acc;                        // 加速度,注意:0是直接启动
  320.   cmd[6] =  snF;                        // 多机同步运动标志
  321.   cmd[7] =  0x6B;                       // 校验字节
  322.   
  323.   // 发送命令
  324.   send_data((uint8_t *)cmd, 8);
  325. }

  326. /**
  327.   * @brief    位置模式
  328.   * @param    addr:电机地址
  329.   * @param    dir :方向        ,0为CW,其余值为CCW
  330.   * @param    vel :速度(RPM)   ,范围0 - 5000RPM
  331.   * @param    acc :加速度      ,范围0 - 255,注意:0是直接启动
  332.   * @param    clk :脉冲数      ,范围0- (2^32 - 1)个
  333.   * @param    raF :相位/绝对标志,false为相对运动,true为绝对值运动
  334.   * @param    snF :多机同步标志 ,false为不启用,true为启用
  335.   * @retval   地址 + 功能码 + 命令状态 + 校验字节
  336.   */
  337. void Emm_V5_Pos_Control(uint8_t addr, uint8_t dir, uint16_t vel, uint8_t acc, uint32_t clk, bool raF, bool snF)
  338. {
  339.   uint8_t cmd[16] = {0};

  340.   // 装载命令
  341.   cmd[0]  =  addr;                      // 地址
  342.   cmd[1]  =  0xFD;                      // 功能码
  343.   cmd[2]  =  dir;                       // 方向
  344.   cmd[3]  =  (uint8_t)(vel >> 8);       // 速度(RPM)高8位字节
  345.   cmd[4]  =  (uint8_t)(vel >> 0);       // 速度(RPM)低8位字节
  346.   cmd[5]  =  acc;                       // 加速度,注意:0是直接启动
  347.   cmd[6]  =  (uint8_t)(clk >> 24);      // 脉冲数(bit24 - bit31)
  348.   cmd[7]  =  (uint8_t)(clk >> 16);      // 脉冲数(bit16 - bit23)
  349.   cmd[8]  =  (uint8_t)(clk >> 8);       // 脉冲数(bit8  - bit15)
  350.   cmd[9]  =  (uint8_t)(clk >> 0);       // 脉冲数(bit0  - bit7 )
  351.   cmd[10] =  raF;                       // 相位/绝对标志,false为相对运动,true为绝对值运动
  352.   cmd[11] =  snF;                       // 多机同步运动标志,false为不启用,true为启用
  353.   cmd[12] =  0x6B;                      // 校验字节
  354.   
  355.   // 发送命令
  356.   send_data((uint8_t *)cmd, 13);
  357. }
  358. /**
  359.   * @brief    角度模式
  360.   * @param    addr:电机地址
  361.   * @param    dir :方向        ,0为CW,其余值为CCW
  362.   * @param    vel :速度(RPM)   ,范围0 - 5000RPM
  363.   * @param    acc :加速度      ,范围0 - 255,注意:0是直接启动
  364.   * @param    angle :角度 , 0~360
  365.   * @param    raF :相位/绝对标志,false为相对运动,true为绝对值运动
  366.   * @param    snF :多机同步标志 ,false为不启用,true为启用
  367.   * @retval   地址 + 功能码 + 命令状态 + 校验字节
  368.   */
  369. void Emm_V5_angle_Control(uint8_t addr, uint8_t dir, uint16_t vel, uint8_t acc, uint8_t angle ,bool raF, bool snF)
  370. {
  371.    
  372.   uint32_t clk  = 0 ;

  373.   clk = angle*3200/360 ;

  374.    Emm_V5_Pos_Control(addr,dir,vel, acc, clk,  raF,  snF);
  375. }

  376. /**
  377.   * @brief    立即停止(所有控制模式都通用)
  378.   * @param    addr  :电机地址
  379.   * @param    snF   :多机同步标志,false为不启用,true为启用
  380.   * @retval   地址 + 功能码 + 命令状态 + 校验字节
  381.   */
  382. void Emm_V5_Stop_Now(uint8_t addr, bool snF)
  383. {
  384.   uint8_t cmd[16] = {0};
  385.   
  386.   // 装载命令
  387.   cmd[0] =  addr;                       // 地址
  388.   cmd[1] =  0xFE;                       // 功能码
  389.   cmd[2] =  0x98;                       // 辅助码
  390.   cmd[3] =  snF;                        // 多机同步运动标志
  391.   cmd[4] =  0x6B;                       // 校验字节
  392.   
  393.   // 发送命令
  394.   send_data((uint8_t *)cmd, 5);
  395. }

  396. /**
  397.   * @brief    多机同步运动
  398.   * @param    addr  :电机地址
  399.   * @retval   地址 + 功能码 + 命令状态 + 校验字节
  400.   */
  401. void Emm_V5_Synchronous_motion(uint8_t addr)
  402. {
  403.   uint8_t cmd[16] = {0};
  404.   
  405.   // 装载命令
  406.   cmd[0] =  addr;                       // 地址
  407.   cmd[1] =  0xFF;                       // 功能码
  408.   cmd[2] =  0x66;                       // 辅助码
  409.   cmd[3] =  0x6B;                       // 校验字节
  410.   
  411.   // 发送命令
  412.   send_data((uint8_t *)cmd, 4);
  413. }

  414. /**
  415.   * @brief    设置单圈回零的零点位置
  416.   * @param    addr  :电机地址
  417.   * @param    svF   :是否存储标志,false为不存储,true为存储
  418.   * @retval   地址 + 功能码 + 命令状态 + 校验字节
  419.   */
  420. void Emm_V5_Origin_Set_O(uint8_t addr, bool svF)
  421. {
  422.    uint8_t cmd[16] = {0};
  423.   
  424.   // 装载命令
  425.   cmd[0] =  addr;                       // 地址
  426.   cmd[1] =  0x93;                       // 功能码
  427.   cmd[2] =  0x88;                       // 辅助码
  428.   cmd[3] =  svF;                        // 是否存储标志,false为不存储,true为存储
  429.   cmd[4] =  0x6B;                       // 校验字节
  430.   
  431.   // 发送命令
  432.   send_data((uint8_t *)cmd, 5);
  433. }

  434. /**
  435.   * @brief    修改回零参数
  436.   * @param    addr  :电机地址
  437.   * @param    svF   :是否存储标志,false为不存储,true为存储
  438.   * @param    o_mode :回零模式,0为单圈就近回零,1为单圈方向回零,2为多圈无限位碰撞回零,3为多圈有限位开关回零
  439.   * @param    o_dir  :回零方向,0为CW,其余值为CCW
  440.   * @param    o_vel  :回零速度,单位:RPM(转/分钟)
  441.   * @param    o_tm   :回零超时时间,单位:毫秒
  442.   * @param    sl_vel :无限位碰撞回零检测转速,单位:RPM(转/分钟)
  443.   * @param    sl_ma  :无限位碰撞回零检测电流,单位:Ma(毫安)
  444.   * @param    sl_ms  :无限位碰撞回零检测时间,单位:Ms(毫秒)
  445.   * @param    potF   :上电自动触发回零,false为不使能,true为使能
  446.   * @retval   地址 + 功能码 + 命令状态 + 校验字节
  447.   */
  448. 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)
  449. {
  450.   uint8_t cmd[32] = {0};
  451.   
  452.   // 装载命令
  453.   cmd[0] =  addr;                       // 地址
  454.   cmd[1] =  0x4C;                       // 功能码
  455.   cmd[2] =  0xAE;                       // 辅助码
  456.   cmd[3] =  svF;                        // 是否存储标志,false为不存储,true为存储
  457.   cmd[4] =  o_mode;                     // 回零模式,0为单圈就近回零,1为单圈方向回零,2为多圈无限位碰撞回零,3为多圈有限位开关回零
  458.   cmd[5] =  o_dir;                      // 回零方向
  459.   cmd[6]  =  (uint8_t)(o_vel >> 8);     // 回零速度(RPM)高8位字节
  460.   cmd[7]  =  (uint8_t)(o_vel >> 0);     // 回零速度(RPM)低8位字节
  461.   cmd[8]  =  (uint8_t)(o_tm >> 24);     // 回零超时时间(bit24 - bit31)
  462.   cmd[9]  =  (uint8_t)(o_tm >> 16);     // 回零超时时间(bit16 - bit23)
  463.   cmd[10] =  (uint8_t)(o_tm >> 8);      // 回零超时时间(bit8  - bit15)
  464.   cmd[11] =  (uint8_t)(o_tm >> 0);      // 回零超时时间(bit0  - bit7 )
  465.   cmd[12] =  (uint8_t)(sl_vel >> 8);    // 无限位碰撞回零检测转速(RPM)高8位字节
  466.   cmd[13] =  (uint8_t)(sl_vel >> 0);    // 无限位碰撞回零检测转速(RPM)低8位字节
  467.   cmd[14] =  (uint8_t)(sl_ma >> 8);     // 无限位碰撞回零检测电流(Ma)高8位字节
  468.   cmd[15] =  (uint8_t)(sl_ma >> 0);     // 无限位碰撞回零检测电流(Ma)低8位字节
  469.   cmd[16] =  (uint8_t)(sl_ms >> 8);     // 无限位碰撞回零检测时间(Ms)高8位字节
  470.   cmd[17] =  (uint8_t)(sl_ms >> 0);     // 无限位碰撞回零检测时间(Ms)低8位字节
  471.   cmd[18] =  potF;                      // 上电自动触发回零,false为不使能,true为使能
  472.   cmd[19] =  0x6B;                      // 校验字节
  473.   
  474.   // 发送命令
  475.   send_data((uint8_t *)cmd, 20);
  476. }

  477. /**
  478.   * @brief    触发回零
  479.   * @param    addr   :电机地址
  480.   * @param    o_mode :回零模式,0为单圈就近回零,1为单圈方向回零,2为多圈无限位碰撞回零,3为多圈有限位开关回零
  481.   * @param    snF   :多机同步标志,false为不启用,true为启用
  482.   * @retval   地址 + 功能码 + 命令状态 + 校验字节
  483.   */
  484. void Emm_V5_Origin_Trigger_Return(uint8_t addr, uint8_t o_mode, bool snF)
  485. {
  486.   uint8_t cmd[16] = {0};
  487.   
  488.   // 装载命令
  489.   cmd[0] =  addr;                       // 地址
  490.   cmd[1] =  0x9A;                       // 功能码
  491.   cmd[2] =  o_mode;                     // 回零模式,0为单圈就近回零,1为单圈方向回零,2为多圈无限位碰撞回零,3为多圈有限位开关回零
  492.   cmd[3] =  snF;                        // 多机同步运动标志,false为不启用,true为启用
  493.   cmd[4] =  0x6B;                       // 校验字节
  494.   
  495.   // 发送命令
  496.   send_data((uint8_t *)cmd, 5);
  497. }

  498. /**
  499.   * @brief    强制中断并退出回零
  500.   * @param    addr  :电机地址
  501.   * @retval   地址 + 功能码 + 命令状态 + 校验字节
  502.   */
  503. void Emm_V5_Origin_Interrupt(uint8_t addr)
  504. {
  505.   uint8_t cmd[16] = {0};
  506.   
  507.   // 装载命令
  508.   cmd[0] =  addr;                       // 地址
  509.   cmd[1] =  0x9C;                       // 功能码
  510.   cmd[2] =  0x48;                       // 辅助码
  511.   cmd[3] =  0x6B;                       // 校验字节
  512.   
  513.   // 发送命令
  514.   send_data((uint8_t *)cmd, 5);
  515. }


  516. /**
  517. * 主函数
  518. */
  519. int main() {
  520.     char input_buffer[BUFFER_SIZE];
  521.     char command[64];
  522.     pthread_t receive_thread;
  523.     int continuous_mode = 0;
  524.    
  525.     // 注册信号处理器
  526.     signal(SIGINT, signal_handler);
  527.     signal(SIGTERM, signal_handler);
  528.    
  529.     printf("TTY USB串口通信程序 (C语言版本)\n");
  530.     printf("==================================\n");
  531.    
  532.     // 打开串口
  533.     serial_fd = open_serial_port(SERIAL_PORT);
  534.     if (serial_fd < 0) {
  535.         printf("无法打开串口 %s,程序退出\n", SERIAL_PORT);
  536.         return 1;
  537.     }
  538.    
  539.     show_help();
  540.    
  541.     while (running)
  542.     {
  543.       Emm_V5_Vel_Control(0x01,0x00,0x10,0x00,0x00);
  544.       usleep(10000);
  545.       Emm_V5_angle_Control(0x02,0x00,0x10,0x00,0xB4,0x01,0x00);
  546.       usleep(10000);  
  547.     }
  548.    
  549.     // 停止连续接收模式
  550.     if (continuous_mode)
  551.     {
  552.         running = 0;
  553.         pthread_join(receive_thread, NULL);
  554.     }
  555.    
  556.     // 关闭串口
  557.     close_serial_port();
  558.    
  559.     printf("程序结束\n");
  560.     return 0;
  561. }
复制代码

步进电机控制演示视频




yolo 手势识别



yolo视觉识别手势控制四舵轮












40b90c23c7a52c8d65d9537a3927e531.png (108 KB, 下载次数: 0)

40b90c23c7a52c8d65d9537a3927e531.png

de8340b26c96ab8d36930e102960ea8e.png (73.22 KB, 下载次数: 0)

de8340b26c96ab8d36930e102960ea8e.png

ddc0c524dcdd3d1b23015a7e54d69960.png (159.4 KB, 下载次数: 0)

ddc0c524dcdd3d1b23015a7e54d69960.png

503e817408b2c1b9f3c0106e9eb0fc83.png (89.55 KB, 下载次数: 0)

503e817408b2c1b9f3c0106e9eb0fc83.png

张大头舵轮装配体.zip

27.56 MB, 下载次数: 0

wheel_control.zip

12.16 KB, 下载次数: 0

步进电机测试代码

my_package.zip

8.54 KB, 下载次数: 0

接收cmd_vel

分享到:
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条