鸿蒙Hi3861智能小车WiFi控制全流程实战:从硬件配置到云端交互

第一次拿到Hi3861开发板和小车套件时,那种兴奋感至今记忆犹新。但当我真正开始动手搭建时,才发现从PWM电机控制到WiFi通信的完整实现,每一步都可能遇到意想不到的"坑"。本文将带你完整走通Hi3861智能小车的开发全流程,重点解决那些官方文档没细说、但实际开发中必然遇到的典型问题。

1. 硬件准备与环境搭建

在开始编码前,正确的硬件连接和开发环境配置能避免80%的后续问题。Hi3861开发板通常采用L9110S电机驱动芯片,这种双H桥驱动电路需要特别注意PWM信号与电机转向的对应关系。典型接线方式如下表所示:

Hi3861 GPIO引脚 PWM通道 L9110S控制端 电机动作
GPIO0 PWM3 A-IA 左轮正转
GPIO1 PWM4 A-IB 左轮反转
GPIO9 PWM0 B-IA 右轮正转
GPIO10 PWM1 B-IB 右轮反转

开发环境配置关键步骤

  1. 安装DevEco Device Tool时,务必选择3.0.0以上版本,旧版对Hi3861支持不完善
  2. 修改 usr_config.mk 时,除了开启PWM支持,还需要添加:
    CONFIG_PWM_SUPPORT=y
    CONFIG_NET_LWIP_SACK=y  # 启用TCP/IP协议栈
    
  3. 首次烧录前执行 python build.py wifiiot -b debug 可启用调试输出

注意:开发板上的GPIO9和GPIO10默认可能被复用为串口功能,需要在代码中显式配置为PWM模式。

2. PWM电机控制的深度优化

原始示例中的PWM控制代码虽然能工作,但在实际小车运动中会出现明显的顿挫感。经过多次测试,发现以下优化点:

2.1 动态频率调整

不同电压下电机的最佳PWM频率不同,可通过以下函数动态调整:

void set_motor_frequency(uint32_t freq) {
    PwmSetClock(WIFI_IOT_PWM_PORT_PWM0, freq);
    PwmSetClock(WIFI_IOT_PWM_PORT_PWM1, freq);
    PwmSetClock(WIFI_IOT_PWM_PORT_PWM3, freq); 
    PwmSetClock(WIFI_IOT_PWM_PORT_PWM4, freq);
}

2.2 运动平滑处理

直接切换PWM会导致电机急启急停,加入渐变函数:

void smooth_start(uint8_t port, uint32_t target_duty) {
    for(int i=0; i<target_duty; i+=10) {
        PwmStart(port, i, 1500);
        usleep(10000);
    }
}

常见问题排查

  • 电机只震动不转动:检查PWM频率是否在500-2000Hz范围内
  • 一侧电机不工作:用万用表测量GPIO输出电压,确认不是硬件问题
  • 控制响应延迟:将 /vendor/hisi/hi3861/hi3861/config/sys_config.mk 中的 CONFIG_TASK_STACK_SIZE 增加到4096

3. 高可靠WiFi通信实现

原始示例中的UDP服务端存在丢包和抗干扰差的问题,我们重构为事件驱动架构:

3.1 增强型UDP服务端

#define UDP_PORT 50001
static int udp_fd = -1;

void udp_server_init() {
    struct sockaddr_in addr;
    
    udp_fd = socket(AF_INET, SOCK_DGRAM, 0);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(UDP_PORT);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    
    bind(udp_fd, (struct sockaddr*)&addr, sizeof(addr));
    
    // 设置非阻塞模式
    fcntl(udp_fd, F_SETFL, O_NONBLOCK);
}

void check_udp_command() {
    char buf[256];
    struct sockaddr_in client_addr;
    socklen_t addr_len = sizeof(client_addr);
    
    int len = recvfrom(udp_fd, buf, sizeof(buf), 0, 
                      (struct sockaddr*)&client_addr, &addr_len);
    if(len > 0) {
        buf[len] = '\0';
        process_json_command(buf);  // JSON解析函数
    }
}

3.2 JSON协议设计

推荐采用以下紧凑格式:

{
  "cmd": "move",
  "param": {
    "left": 80,
    "right": 60,
    "duration": 1000
  }
}

WiFi优化技巧

  • /etc/wpa_supplicant.conf 中添加:
    ap_scan=1
    fast_reauth=1
    
  • 通过 iwpriv hi0 set_channel 6 锁定信道减少干扰
  • 定期发送心跳包检测连接状态

4. 进阶功能扩展

基础控制稳定后,可以扩展以下实用功能:

4.1 多控制端管理

#define MAX_CLIENTS 5
struct sockaddr_in clients[MAX_CLIENTS];

void add_client(struct sockaddr_in* addr) {
    for(int i=0; i<MAX_CLIENTS; i++) {
        if(memcmp(&clients[i], addr, sizeof(*addr)) == 0) return;
        if(clients[i].sin_addr.s_addr == 0) {
            memcpy(&clients[i], addr, sizeof(*addr));
            break;
        }
    }
}

4.2 OTA远程升级

  1. usr_config.mk 启用:
    CONFIG_FS_FAT=y
    CONFIG_FS_VFS=y
    
  2. 实现差分升级逻辑:
    # 升级脚本示例
    import hashlib
    def check_firmware(file):
        md5 = hashlib.md5(open(file,'rb').read()).hexdigest()
        return md5 == expected_md5
    

4.3 运动轨迹记录

使用Flash存储模块记录运动数据:

void save_trajectory(point_t* points, int count) {
    int fd = open("/data/traj.bin", O_WRONLY|O_CREAT);
    write(fd, points, count*sizeof(point_t));
    close(fd);
}

5. 典型问题解决方案

问题1 :PWM初始化失败,返回错误码-1

  • 检查 usr_config.mk 是否配置正确
  • 确认GPIO没有被其他功能占用
  • 调用 GpioInit() 前先执行 IoTGpioInit()

问题2 :UDP接收不稳定

  • 增大接收缓冲区: setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size))
  • 禁用ARP缓存: echo 1 > /proc/sys/net/ipv4/neigh/default/gc_stale_time

问题3 :WiFi频繁断开

  • 调整电源管理: iwconfig hi0 power off
  • 添加看门狗定时器重启网络模块

在完成基础功能后,可以尝试接入华为IoT平台,使用设备影子同步状态。实际测试中,这套架构可以稳定支持20ms的控制周期,满足大多数教育机器人项目的需求。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐