野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 1567|回复: 0

【鲁班猫创意大赛】基于鲁班猫0的满血版AWTRIX时钟

[复制链接]
发表于 2023-5-18 15:26:30 | 显示全部楼层 |阅读模式
本帖最后由 POMIN 于 2023-5-18 15:39 编辑



鲁班猫创意大赛参赛项目——基于鲁班猫0的满血版AWTRIX时钟,基于鲁班猫0的开发板,搭配ESP8266制作该项目。
硬件组成部分框图
开发步骤
AWTRIX时钟的官方网站: https://awtrixdocs.blueforcer.de/#/en-en/

官方在2022的八月份停止了更新,不过硬件连接图、代码都已经开源,服务器端也公开了jar包,源码没有开源。
复刻AWTRIX硬件
直接用核心板,连接一下各种模块,用立创eda画一个底板。
具体管脚信息在代码中可以看到,代码地址: https://github.com/awtrix/AWTRIX2.0-Controller
简单布线一下pcb。
AWTRIX时钟使用的灯光板淘宝可以买到,但是比较大,重新画了个灯光板来缩小面积。
自制灯光板PCB
256个灯珠、256个104电容
固件修改
焊一焊已经到货的底板
把模块插上,拧上铜柱
由于体积较大,3D打印比较费材料(其实是比较费钱),就买了个25*7*7cm尺寸的木盒子。
灯光板到了开始组装AWTRIX控制端。
灯光板到了才发现AWTRIX时钟使用的灯光板和我画的灯板扫描顺序不太一样,固件需要修改。
我画的的扫描顺序:
原版的扫描顺序:

查阅 AWTRIX 的代码可以看到采用的是 FastLED_NeoMatrix 这个库,这个库是用 C++ 写的库,不过代码结构比较清晰,找出画点的函数 FastLED_NeoMatrix::drawPixel,函数实现如下
  1. void FastLED_NeoMatrix::drawPixel(int16_t x, int16_t y, uint16_t color) {

  2.   if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;

  3.   _leds[XY(x,y)] = passThruFlag ? passThruColor : expandColor(color);
  4. }
复制代码
其中 XY(x,y) 函数就是把屏幕的坐标点转换为_leds数组的索引,跳到XY(x,y)函数中查看。

  1. int FastLED_NeoMatrix::XY(int16_t x, int16_t y) {

  2.   // Beware, this returns a special out of bounds value, you need an extra
  3.   // safety pixel at the end of your array to host this, or if you use
  4.   // drawPixel, the value willl get rejected.
  5.   if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return numpix-1;

  6.   int16_t t;
  7.   switch(rotation) {
  8.    case 1:
  9.     t = x;
  10.     x = WIDTH  - 1 - y;
  11.     y = t;
  12.     break;
  13.    case 2:
  14.     x = WIDTH  - 1 - x;
  15.     y = HEIGHT - 1 - y;
  16.     break;
  17.    case 3:
  18.     t = x;
  19.     x = y;
  20.     y = HEIGHT - 1 - t;
  21.     break;
  22.   }

  23.   int tileOffset = 0, pixelOffset;

  24.   if(remapFn) { // Custom X/Y remapping function
  25.     pixelOffset = (*remapFn)(x, y);
  26.   } else {      // Standard single matrix or tiled matrices

  27.     uint8_t  corner = type & NEO_MATRIX_CORNER;
  28.     uint16_t minor, major, majorScale;

  29.     if(tilesX) { // Tiled display, multiple matrices
  30.       uint16_t tile;

  31.       minor = x / matrixWidth;            // Tile # X/Y; presume row major to
  32.       major = y / matrixHeight,           // start (will swap later if needed)
  33.       x     = x - (minor * matrixWidth);  // Pixel X/Y within tile
  34.       y     = y - (major * matrixHeight); // (-* is less math than modulo)

  35.       // Determine corner of entry, flip axes if needed
  36.       if(type & NEO_TILE_RIGHT)  minor = tilesX - 1 - minor;
  37.       if(type & NEO_TILE_BOTTOM) major = tilesY - 1 - major;

  38.       // Determine actual major axis of tiling
  39.       if((type & NEO_TILE_AXIS) == NEO_TILE_ROWS) {
  40.         majorScale = tilesX;
  41.       } else {
  42.         _swap_uint16_t(major, minor);
  43.         majorScale = tilesY;
  44.       }

  45.       // Determine tile number
  46.       if((type & NEO_TILE_SEQUENCE) == NEO_TILE_PROGRESSIVE) {
  47.         // All tiles in same order
  48.         tile = major * majorScale + minor;
  49.       } else {
  50.         // Zigzag; alternate rows change direction.  On these rows,
  51.         // this also flips the starting corner of the matrix for the
  52.         // pixel math later.
  53.         if(major & 1) {
  54.           corner ^= NEO_MATRIX_CORNER;
  55.           tile = (major + 1) * majorScale - 1 - minor;
  56.         } else {
  57.           tile =  major      * majorScale     + minor;
  58.         }
  59.       }

  60.       // Index of first pixel in tile
  61.       tileOffset = tile * matrixWidth * matrixHeight;

  62.     } // else no tiling (handle as single tile)

  63.     // Find pixel number within tile
  64.     minor = x; // Presume row major to start (will swap later if needed)
  65.     major = y;

  66.     // Determine corner of entry, flip axes if needed
  67.     if(corner & NEO_MATRIX_RIGHT)  minor = matrixWidth  - 1 - minor;
  68.     if(corner & NEO_MATRIX_BOTTOM) major = matrixHeight - 1 - major;

  69.     // Determine actual major axis of matrix
  70.     if((type & NEO_MATRIX_AXIS) == NEO_MATRIX_ROWS) {
  71.       majorScale = matrixWidth;
  72.     } else {
  73.       _swap_uint16_t(major, minor);
  74.       majorScale = matrixHeight;
  75.     }

  76.     // Determine pixel number within tile/matrix
  77.     if((type & NEO_MATRIX_SEQUENCE) == NEO_MATRIX_PROGRESSIVE) {
  78.       // All lines in same order
  79.       pixelOffset = major * majorScale + minor;
  80.     } else {
  81.       // Zigzag; alternate rows change direction.
  82.       if(major & 1) pixelOffset = (major + 1) * majorScale - 1 - minor;
  83.       else          pixelOffset =  major      * majorScale     + minor;
  84.     }
  85.   }

  86.   return(tileOffset + pixelOffset);
  87. }
复制代码

这段代码就是根据当前的旋转方向等信息来计算偏移从而确定其索引。
其中有很重要的一行代码
  1.   if(remapFn) { // Custom X/Y remapping function
  2.     pixelOffset = (*remapFn)(x, y);
  3.   }
复制代码

这行代码调用了一个回调函数,通过回调函数可以实现对于计算数组索引方法的自定义
我画的屏幕是横S形状的扫描方式,简单数学计算可以得到坐标和索引的变换关系为:
y 为偶数时 index = 32 y;
y 为奇数时 index = 32
y + 31 - x;
写一个转换函数
  1. uint16_t remapDisp(uint16_t x, uint16_t y) {
  2.   if (y % 2) {

  3.       return (32 * y + x);
  4.   } else {
  5.       return (32 * y + (31 - x));
  6.   }
  7. }
复制代码

然后初始化函数 matrixInit 中添加一行注册代码,注册到XY函数的回调
  1. matrix->setRemapFunction(remapDisp);
复制代码

用 VSCode 中的 PIO 插件编译一下
烧录到ESP8266接上控制板,正常点亮。
PS:灯光板的大小超了这个木盒子,把四个角切掉,飞线解决;栅格板是用fashion360画,3D打印的,均光板直接剪的A4纸。
鲁班猫网络配置
AWTRIX 服务器官方文档:https://awtrixdocs.blueforcer.de/#/en-en/host
先把鲁班猫设置为静态地址,这里使用 nmtui 工具来设置,静态 IP 为 192.168.0.150,网关地址为 192.168.0.1,DNS 地址为 114.114.114.114
安装  JAVA环境
直接用 apt 工具安装即可,安装完成后使用 java --version 命令查看版本信息,查看是否安装成功。
  1. apt install openjdk-11-jdk
复制代码

注册 AWTRIX 为 service
编写一个 awtrix.service 文件
  1. [Unit]
  2. Description=AWTRIX HOST
  3. After=network.target
  4. [Service]
  5. WorkingDirectory=/root/awtrix/
  6. Type=simple
  7. ExecStart=/usr/bin/java -jar /root/awtrix/awtrix.jar
  8. Restart=always
  9. RestartSec=3

  10. [Install]
  11. WantedBy=multi-user.target
复制代码

复制到 /etc/systemd/system/ 文件夹中,设置开机自动启动并打开服务
  1. cp awtrix.service /etc/systemd/system/
  2. systemctl enable awtrix
  3. systemctl start awtrix
复制代码

AWTRIX 控制器连接到服务器
AWTRIX 时钟上电后进入 HOSTPOD 模式,设置 AWTRIX 的 Wi-Fi 和服务器 IP,服务器IP设置为 192.168.0.150
至此,鲁班猫作为 AWTRIX 的服务器已经搭建完成了。
安装 EMQX
执行如下命令安装即可
  1. curl -s https://assets.emqx.com/scripts/install-emqx-deb.sh | sudo bash
  2. apt install emqx
复制代码

设置 nginx 反向代理
记 IP太麻烦,用 nginx 设置反向代理来访问awtrix服务端
改写 nginx的网站配置文件
  1. nano /etc/nginx/sites-available/default
复制代码

改写为如下内容
  1. map $http_upgrade $connection_upgrade {
  2.     default upgrade;
  3.     ''      close;
  4. }

  5. server{
  6.   listen 80;
  7.   server_name  awtrix.lubancat.dev;
  8.   index  index.php index.html index.htm;

  9.   location / {
  10.     proxy_pass  http://127.0.0.1:7000;
  11.     proxy_set_header Host $proxy_host;
  12.     proxy_http_version 1.1;
  13.     proxy_set_header X-Real-IP $remote_addr;
  14.     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  15.     proxy_set_header Upgrade $http_upgrade;
  16.     proxy_set_header Connection $connection_upgrade;
  17.   }
  18. }

  19. server{
  20.   listen 80;
  21.   server_name  mqtt.lubancat.dev;
  22.   index  index.php index.html index.htm;

  23.   location / {
  24.     proxy_pass  http://127.0.0.1:18083;
  25.     proxy_set_header Host $proxy_host;
  26.     proxy_http_version 1.1;
  27.     proxy_set_header X-Real-IP $remote_addr;
  28.     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  29.     proxy_set_header Upgrade $http_upgrade;
  30.     proxy_set_header Connection $connection_upgrade;
  31.   }
  32. }
复制代码

用 SwitchHosts 修改一下 hosts 文件,设置 awtrx.lubancat.dev 和 mqtt.lubancat.dev 解析到 192.168.0.150,实现 emqx 的后台通过 mqtt.lubancat.dev 访问,AWTRIX 服务器后台通过 awtrx.lubancat.dev 来访问
组装 AWTRIX 所有硬件
使用 Type-C 转 Mirco USB 的线将鲁班猫和ESP8266连接在一起,使用 Type-C转 Type-C的线将鲁班猫的电源连接到主板的侧面电源接口上面,喇叭、触摸按键屏幕连接到主板上面
全都连接好:
将 AWTRIX 服务器设置为串口连接到控制器,可以实现稳定不掉线的显示,这里连接到鲁班猫的串口为 /dev/ttyUSB0,MQTT 服务器为本地地址127.0.0.1,端口1883,AWTRIX 也提供了 MQTT 的 api,说明文档:https://awtrixdocs.blueforcer.de/#/en-en/api
然后安装一些 APP
点亮 AWTRIX 时钟
可以查看温度、湿度和时间、当前度过了一年的百分之多少
也可以自定义显示内容
也可以显示打篮球的动画
查看设备端的状态
查看服务器端的状态
项目总结
用ESP8266和鲁班猫复刻了国外曾经很火的AWTRIX像素时钟,简单的外观,超强的“心脏”,得益于鲁班猫0的强大性能,可以完美的平替原项目作为服务器主机使用的树莓派,富余的性能还可以用来安装Alist、EMQX、ADguard、ESP Home、Home Assistant等应用,可玩性极高。
[size=0em]​


回复

使用道具 举报

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

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-3-28 17:50 , Processed in 0.035362 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表