12074浏览
查看: 12074|回复: 3

[项目] 行空板——手写点阵屏

[复制链接]
本帖最后由 云天 于 2023-4-11 09:29 编辑

行空板——手写点阵屏图6


【项目背景】
本项目要实现行空板无线手写投点阵屏。
【项目设计】
本项目结合行空板屏幕上手写加python os库截屏,再分析图像上的手写痕迹,获取坐标,通过TCP发送给Ardunio,点亮点阵屏。
【点阵屏】

通过DF官网学习一下如何使用。https://wiki.dfrobot.com.cn/_SKU_DFR0471_32x16_RGB_LED_Matrix_-_6mm_pitch



结合以上两图,连接Arduino与点阵屏。
【Arduino连接WIFI】
使用WiFiBee-MT7681,插在Arduino扩展板上。
行空板——手写点阵屏图7

【硬件展示】
行空板——手写点阵屏图5

【测试显示】
行空板联网,加载socket库,按下A键发送“A”,按下B键发送“B”。
  1. s.connect(('192.168.31.38',1000))
复制代码
“192.168.31.38”,是WiFiBee-MT7681联网IP地址。
  1. import socket
  2. from unihiker import GUI
  3. i=0
  4. # 事件回调函数
  5. def on_buttonb_click_callback():
  6.     s.send(b'B')
  7. def on_buttona_click_callback():
  8.     s.send(b'A')
  9. u_gui=GUI()
  10. u_gui.on_a_click(on_buttona_click_callback)
  11. u_gui.on_b_click(on_buttonb_click_callback)
  12. s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  13. s.connect(('192.168.31.38',1000))
  14. while True:
  15.     pass
复制代码
行空板——手写点阵屏图4



Arduino利用串口接收WiFiBee-MT7681信息,接收“A”点阵屏显示字母“A",接收“B”清屏。
  1. #include <Adafruit_GFX.h>   
  2. #include <RGBmatrixPanel.h>
  3. #define CLK 8  
  4. #define LAT A3
  5. #define OE  9
  6. #define A   A0
  7. #define B   A1
  8. #define C   A2
  9. RGBmatrixPanel matrix(A, B, C, CLK, LAT, OE, false);
  10. void setup() {
  11.   Serial.begin(115200);
  12.   matrix.begin();
  13.   matrix.fillScreen(matrix.Color333(0, 0, 0));
  14.   matrix.setCursor(1, 0);   
  15.   matrix.setTextSize(1);   
  16.   matrix.setTextColor(matrix.Color333(7,0,0));
  17. }
  18. void loop() {
  19.   if ((Serial.available())) {
  20.   String  mystr=Serial.readString();
  21.   if(mystr=="B"){
  22.      matrix.fillScreen(matrix.Color333(0, 0, 0));
  23.   }
  24.   else{
  25.     matrix.print(mystr);
  26.   }
  27. }
复制代码
【发送坐标信息】
行空板Python程序获取手写痕迹,发痕迹坐标。
  1. import socket
  2. from unihiker import GUI
  3. import time
  4. import os
  5. import cv2
  6. import numpy as np
  7. pos_xy = []
  8. # 图像旋转(以原点(0,0)为中心旋转)
  9. def image_rotate(src, rotate=0):
  10.   h,w,c = src.shape
  11.   cos_val = np.cos(np.deg2rad(rotate))
  12.   sin_val = np.sin(np.deg2rad(rotate))
  13.   M = np.float32([[cos_val, -sin_val, 0], [sin_val, cos_val, 0]])
  14.   img = cv2.warpAffine(src, M, (w,h))
  15.   return img
  16. # 事件回调函数
  17. def on_buttonb_click_callback():
  18.     u_gui.clear()
  19.     s.send(b'B')
  20.    
  21. def on_buttona_click_callback():
  22.     os.system("scrot -a 0,0,240,320 sc.png")
  23.     img = cv2.imread("sc.png")
  24.     img=cv2.resize(img,(16,32))
  25.    
  26.     hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)  # 色彩空间转换为hsv,分离.
  27.     #色相(H)是色彩的基本属性,就是平常所说的颜色名称,如红色、黄色等。
  28.     #饱和度(S)是指色彩的纯度,越高色彩越纯,低则逐渐变灰,取0-100%的数值。
  29.     #明度(V),取0-100%。
  30.     #OpenCV中H,S,V范围是0-180,0-255,0-255
  31.     low = np.array([0, 0, 0])
  32.     high = np.array([180, 255, 46])
  33.     dst = cv2.inRange(src=hsv, lowerb=low, upperb=high) # HSV高低阈值,提取图像部分区域
  34.     #寻找白色的像素点坐标。
  35.     #白色像素值是255,所以np.where(dst==255)
  36.     xy = np.column_stack(np.where(dst==255))
  37.     mystr=b''
  38.     k=0
  39.     for c in xy:
  40.         
  41.          for d in c:
  42.           mystr=mystr+b","+str(d).encode()
  43.           k+=1
  44.           if k==10:
  45.              mystr=str(k).encode()+mystr
  46.              print(mystr)
  47.              s.send(mystr)
  48.              k=0
  49.              mystr=b''
  50.              time.sleep(2)
  51.     if k>0:
  52.         mystr=str(k).encode()+mystr
  53.         print(mystr)
  54.         s.send(mystr)
  55.    
  56. u_gui=GUI()
  57. u_gui.on_a_click(on_buttona_click_callback)
  58. u_gui.on_b_click(on_buttonb_click_callback)
  59. s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  60. s.connect(('192.168.31.38',1000))
  61. def mouse_move(x, y):# 画线
  62.     global temp_time
  63.     temp_time = time.time()
  64.     '''
  65.     首先判断pos_xy列表中是不是至少有两个点了
  66.     然后将pos_xy中第一个点赋值给point_start
  67.     利用中间变量pos_tmp遍历整个pos_xy列表
  68.     point_end = pos_tmp
  69.     画point_start到point_end之间的线
  70.     point_start = point_end
  71.     这样,不断地将相邻两个点之间画线,就能留下鼠标移动轨迹了
  72.     '''
  73.     pos_xy.append([x,y])
  74.     if len(pos_xy) > 1:
  75.         point_start = pos_xy[0]
  76.         for pos_tmp in pos_xy:
  77.             point_end = pos_tmp
  78.             line_text = u_gui.draw_line(x0=point_start[0],y0=point_start[1],x1=point_end[0],y1=point_end[1],width=20, color=(0,0,0))
  79.             point_start = point_end   
  80. def on_release(event):
  81.     pos_xy.clear()
  82. u_gui.master.bind("<ButtonRelease>", on_release)# 抬笔检测
  83. u_gui.on_mouse_move(mouse_move)      #鼠标检测
  84. while True:
  85.     #增加等待,防止程序退出和卡住
  86.     time.sleep(0.5)
复制代码
【Arduino接收显示】

使用自定义函数fenge,分割接收的字符串坐标,利用matrix.drawPixel点亮坐标。
  1. #include <Adafruit_GFX.h>   
  2. #include <RGBmatrixPanel.h>
  3. #define CLK 8  
  4. #define LAT A3
  5. #define OE  9
  6. #define A   A0
  7. #define B   A1
  8. #define C   A2
  9. RGBmatrixPanel matrix(A, B, C, CLK, LAT, OE, false);
  10. void setup() {
  11.   Serial.begin(115200);
  12.   matrix.begin();
  13.   matrix.fillScreen(matrix.Color333(0, 0, 0));
  14.   // draw  text!
  15.   matrix.setCursor(1, 0);   
  16.   matrix.setTextSize(1);   
  17.   matrix.setTextColor(matrix.Color333(7,0,0));
  18. }
  19. int fenge(String str,String fen,int index)
  20. {
  21. int weizhi;
  22. String temps[str.length()];
  23. int i=0;
  24. do
  25. {
  26.     weizhi = str.indexOf(fen);
  27.     if(weizhi != -1)
  28.     {
  29.       temps[i] =  str.substring(0,weizhi);
  30.       str = str.substring(weizhi+fen.length(),str.length());
  31.       i++;
  32.       }
  33.       else {
  34.         if(str.length()>0)
  35.         temps[i] = str;
  36.       }
  37. }
  38.   while(weizhi>=0);
  39.   if(index>i)return "-1";
  40.   return temps[index].toInt();
  41. }
  42. String Mystr = "";//声明字符串变量
  43. void loop() {
  44.   
  45.   
  46.    if (Serial.available() > 0)
  47.     {  Mystr=Serial.readString();   
  48.        if(Mystr=="B"){
  49.        matrix.fillScreen(matrix.Color333(0, 0, 0));
  50.        }
  51.        else{
  52.            int num=fenge(Mystr,",",0);
  53.            for(int i=1;i<=num-1;i=i+2){
  54.               int pose0=31-fenge(Mystr,",",i);
  55.               int pose1=fenge(Mystr,",",i+1);
  56.               matrix.drawPixel(pose0,pose1, matrix.Color333(7, 7, 7));
  57.              }
  58.            }
  59.       Mystr=="";
  60.       }
  61. }
复制代码

行空板——手写点阵屏图1行空板——手写点阵屏图2行空板——手写点阵屏图3



【演示视频】




IMG_20230409_173322.jpg

macCosmo  中级技师

发表于 2023-4-13 15:46:56

66666666666
回复

使用道具 举报

若晗  中级技师

发表于 2023-5-4 14:29:14

学习了,感谢分享
回复

使用道具 举报

少东  高级技师

发表于 2024-2-22 11:13:16

看完直呼过瘾,哈哈哈哈哈
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail