OpenHarmony开源社区
直播中

爱与友人

9年用户 985经验值
擅长:可编程逻辑 模拟技术 存储技术
私信 关注
[经验]

基于全志XR806开发板开发的棋子分拣机

棋子分拣机

先放个效果视频:
最近沉迷于看《棋魂》,突发奇想做个棋子分拣机器。刚好涉及到的材料与之前写的XR806例程能差不多对应上,就差一个外壳,于是圣诞节就宅在实验室画了草图,趁着月黑风高偷偷用学校的CNC切了一个模型,基于XR806开发板和openHarmony实现了分拣棋子的功能。


技术原理
关于技术实现,用到的材料主要有XR806开发板、两个9g的舵机,以及一个红外光传感器。
工作机制非常简单,如图所示:
上电后舵机复位到初始状态,任何开始工作,由一号舵机把待分类的棋子推移到检测区域,由红外传感器判断棋子的颜色,白色返回值为1,黑色则为0。

硬件模型制作
这一部分看似工作量大,但其实是参考了网上一些开源的例程,只不过加以了尺寸改动。

实现方法可以用3d打印或者激光切割亚克力,我选择了后者因为时间相对简短。使用的建模软件为Solidworks2019,亚克力板厚度后3mm,画好零件后,搭建好装配体确认尺寸无误后转为dxf格式即可用CNC机床切割。(我是用了学校的CNC,网上切也很便宜哈)


电路部分
使用的开发板为XR806,一款iot产品开发板,他最大的特点就是适配的轻鸿蒙,使用起来能有不错的体验。

需要驱动的设备就是两个舵机及一个红外传感器。

舵机就是一种位置伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。其工作原理是:控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。

以180度角度伺服为例,那么对应的控制关系是这样的:
0.5ms--------------0度;
1.0ms------------45度;
1.5ms------------90度;
2.0ms-----------135度;
2.5ms-----------180度;
拆开看看:
减速齿轮
驱动电路
因为片子上的字眼实在太小,令人“望眼欲穿”,本来还想查查有没有技术文档研究一下,只能放弃先了。刚好鸿蒙也适配了pwm的接口驱动xr806,所以我们只要修改freq频率和duty占空比两个选项如下即可。
  1. IoTPwmStart(PWM_OUTPUT_CH0,8,50);
关于其他基础操作姿势可以参考我之前的一篇呼吸灯的demo帖子。还有一点值得一提的是关于这种舵机的输入信号口我是用806上的接口直接驱动的,并没有再拉高,内部是否需要或者有没有额外的驱动由于没有舵机内部电路的原理图也暂时无从得知,但总感觉在调节duty占空这一参数时舵机时而会不听使唤(占空比调制不准确),希望有大佬指点。

红外传感器原理则相对简单,一个红外发射管和一个红外接收管。模块通电后红外发射管向前方不断发射一定频率的红外线,通过板载了一个电压比较器LM393
比较输出和输入的信号做出相应反馈,体现到我手里这块小板子上就是接收到红外信号为1,没有接收到(遇到黑色物体)则为0。所以读取判断值的代码相对简单:
  1. IoTGpioGetinputVal(13,&mode);
整体代码部分
openHarmony用的是gn和ninja编译,由很多种上手学习方式,如果说gn对标的是gcc脚本构建生成器,ninja就对应的是makefile构建系统文档了。
BUILD.gn
  1. #Create by Randolph.

  2. import("//device/xradio/xr806/liteos_m/config.gni")

  3. static_library("app_GO")
  4. {
  5.    configs = []

  6.    sources = ["main.c",]

  7.    cflags = board_cflags

  8.    include_dirs = board_include_dirs
  9.    include_dirs += [
  10.       "//kernel/liteos_m/kernel/arch/include",
  11.       "//base/iot_hardware/peripheral/interfaces/kits",
  12.       "//device/xradio/xr806/xr_skylark/src/rom/rom_bin/src/driver",
  13.    ]
  14. }
main.c
  1. //Create by Randolph
  2. #include "kernel/os/os.h"
  3. #include "ohos_init.h"
  4. #include "iot_pwm.h"
  5. #include "driver/chip/hal_pwm.h"

  6. #define PWM_OUTPUT_CH0     PWM_GROUP0_CH0  //front
  7. #define PWM_OUTPUT_CH1     PWM_GROUP0_CH1  //back

  8. static OS_Thread_t g_main_thread;

  9. unsigned char mode;

  10. static void Servo_init(void)
  11. {
  12.     IoTPwmInit(GPIO_PORT_A);
  13.     IoTGpioInit(13);
  14. }

  15. static void Servo_reset(void)
  16. {
  17.                             printf("0/n");
  18.                 IoTPwmStart(PWM_OUTPUT_CH0,8,50);
  19.                 OS_MSleep(500);

  20.                 printf("1/n");
  21.                 IoTPwmStart(PWM_OUTPUT_CH1,8,50);
  22.                 OS_MSleep(500);
  23. }

  24. static void Servo_start(void)
  25. {
  26.                 printf("2/n");
  27.                 IoTPwmStart(PWM_OUTPUT_CH1,5,50);
  28.                 OS_MSleep(500);

  29.         IoTGpioGetInputVal(13,&mode);
  30.             printf("3/n");
  31.                 IoTPwmStart(PWM_OUTPUT_CH1,8,50);
  32.                 OS_MSleep(500);

  33.         if(mode == 1)
  34.         {
  35.                         printf("4/n");
  36.                 IoTPwmStart(PWM_OUTPUT_CH0,10,50);
  37.                 OS_MSleep(500);
  38.         }
  39.         else
  40.         {
  41.             printf("4/n");
  42.                 IoTPwmStart(PWM_OUTPUT_CH0,6,50);
  43.                 OS_MSleep(500);
  44.         }
  45.                         printf("5/n");
  46.                 IoTPwmStart(PWM_OUTPUT_CH0,8,50);
  47.                 OS_MSleep(500);

  48. }

  49. static void MainThread(void *arg)
  50. {   
  51.     Servo_init();
  52.     Servo_reset();
  53.         while (1)
  54.     {
  55.         Servo_start();
  56.         }
  57. }

  58. void PWM_TestMain(void)
  59. {
  60.         printf("Test Startn");

  61.         if (OS_ThreadCreate(&g_main_thread,"MainThread",MainThread, NULL, OS_THREAD_PRIO_APP, 4096) != OS_OK)
  62.         {
  63.                 printf("[ERR] Create PWMLED_Task Failedn");
  64.         }
  65. }

  66. SYS_RUN(PWM_TestMain)
最后在编译选项中加上即可
  1. "GO_sorting:app_GO"
总结
到此基本功能是实现了,但有很多缺陷如我没有直观地体现出来分类后各种棋子的数量,也并没有给他加上控制开始和停止的操作。(没有一个对是否仍有棋子未被分类的判断机制)这些后续可以通过增加显示屏、替换红外传感器为压感贴片或者使用摄像头去学习判等等···最遗憾的是这个小demo暂时还没有发挥出XR806及鸿蒙的一些特征,如联网、连蓝牙。仅仅是个突发奇想的点子,希望能起到抛砖引玉的作用。后面我也会继续尝试给他加上其他功能。

再贴上一些前置学习内容:
官方文档:https://xr806.docs.aw-ol.com/
XR806鸿蒙开发板引脚功能表.pdf (241.95 KB)
(下载次数: 0, 2022-3-10 14:12 上传)
SDK获取到编译烧录:https://bbs.aw-ol.com/topic/499/xr806鸿蒙开发实战1-实操下载xr806鸿蒙代码并编译烧写
鸿蒙的外设接口:文件接口的头文件在:
  1. baseiot_hardwareperipheralinterfaceskit
源码在:
  1. devicexradioxr806adapterhalsiot_hardwarewifiiot_lit
带有iot字样的接口就是鸿蒙的接口。
端口复用
  1. Harmonydevicexradioxr806xr_skylarkprojectcommonboardxr806_OHOSboard_config.c
可以看到关于pwm的相关端口配置
  1. __xip_rodata
  2. static const GPIO_PinMuxParam g_pinmux_pwm[] = {
  3.         { GPIO_PORT_A, GPIO_PIN_19,  { GPIOA_P19_F4_PWM0_ECT0, GPIO_DRIVING_LEVEL_1, GPIO_PULL_NONE } },
  4.         { GPIO_PORT_A, GPIO_PIN_20,  { GPIOA_P20_F4_PWM1_ECT1, GPIO_DRIVING_LEVEL_1, GPIO_PULL_NONE } },
  5.         { GPIO_PORT_A, GPIO_PIN_22,  { GPIOA_P22_F4_PWM3_ECT3, GPIO_DRIVING_LEVEL_1, GPIO_PULL_NONE } },
  6.         { GPIO_PORT_A, GPIO_PIN_12,  { GPIOA_P12_F3_PWM4_ECT4, GPIO_DRIVING_LEVEL_1, GPIO_PULL_NONE } },
  7.         { GPIO_PORT_A, GPIO_PIN_13,  { GPIOA_P13_F3_PWM5_ECT5, GPIO_DRIVING_LEVEL_1, GPIO_PULL_NONE } },
  8.         { GPIO_PORT_B, GPIO_PIN_3,   { GPIOB_P3_F4_PWM7_ECT7,  GPIO_DRIVING_LEVEL_1, GPIO_PULL_NONE } },
  9. };
项目中所用到的引脚
一号舵机信号线---------PA20
二号舵机信号线---------PA19
红外传感信号线---------PA13
用面包板引出开发板上的电源跟地供外设共用。





文章转自全志在线开发者论坛,作者:Randolph


更多回帖

发帖
×
20
完善资料,
赚取积分