電子發(fā)燒友App

硬聲App

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示
創(chuàng)作
電子發(fā)燒友網(wǎng)>電子資料下載>電子資料>FPGA供電的電磁占卜板

FPGA供電的電磁占卜板

2022-11-21 | zip | 3.77 MB | 次下載 | 免費(fèi)

資料介紹

描述

利用電磁的力量在這個(gè)萬(wàn)圣節(jié)與靈魂交談,使用 FPGA 驅(qū)動(dòng)的占卜板,運(yùn)行網(wǎng)絡(luò)服務(wù)器,允許用戶激活板子移動(dòng)。

在今年萬(wàn)圣節(jié)季節(jié)開(kāi)始時(shí)播放了我最喜歡的恐怖電影和播客之后,我被 Ouija 板的想法所困擾。我想要一種免提使用的方法,這最初讓我想到了使用具有無(wú)線功能的 FPGA,運(yùn)行網(wǎng)絡(luò)服務(wù)器供用戶連接。這與在正確時(shí)間激活的電磁鐵配對(duì)以移動(dòng)板,將允許連接到與 FPGA 相同的 Wi-Fi 網(wǎng)絡(luò)的用戶與網(wǎng)頁(yè)接口以控制板的運(yùn)動(dòng)。

基于 Zynq 的MiniZed非常適合我作為該項(xiàng)目使用的理想 FPGA 板,因?yàn)樗Y(jié)構(gòu)緊湊,內(nèi)置 Murata“Type 1DX”無(wú)線模塊,支持 802.11b/g/n Wi-Fi 和藍(lán)牙 4.1,并可通過(guò)其 USB 端口供電。它還有一個(gè) 8GB eMMC 內(nèi)存芯片,可以通過(guò) Wi-Fi 連接重新編程,所以我覺(jué)得它是一個(gè)理想的選擇,適合留在你可能不想經(jīng)常訪問(wèn)的封閉空間。這是該項(xiàng)目的確切用例,其中 FPGA 和相關(guān)電路將被封裝在本質(zhì)上是游戲板形狀的盒子中。

為了概述所有內(nèi)容,該項(xiàng)目有四個(gè)主要步驟:

  • MiniZed 上的 FPGA 設(shè)計(jì)(網(wǎng)絡(luò)服務(wù)器和 GPIO 驅(qū)動(dòng)程序腳本)
  • 游戲板盒的構(gòu)造與頂蓋上的占卜板設(shè)計(jì)。
  • 游戲板箱內(nèi)的電磁鐵和機(jī)械部件的電路布局。
  • 根據(jù)網(wǎng)頁(yè)上的用戶輸入,更新 GPIO 驅(qū)動(dòng)程序腳本以及何時(shí)打開(kāi)電磁鐵和電機(jī)。

FPGA設(shè)計(jì)

我將使用從 Avnet BSP 為 Vivado/Vitis/PetaLinux 版本 2019.2 創(chuàng)建的 PetaLinux 項(xiàng)目開(kāi)始該項(xiàng)目的 FPGA 設(shè)計(jì)部分,然后修改為添加 Arduino 標(biāo)頭 GPIO. 但是,只有 128MB 的 eMMC 被分區(qū)用于 initramfs 根文件系統(tǒng),作為 MiniZed 開(kāi)箱即用的嵌入式 Linux 映像的默認(rèn)配置。除了存儲(chǔ)所有項(xiàng)目文件之外,這還不足以安裝該項(xiàng)目所需的所有 Python 包。對(duì) initramfs 根文件系統(tǒng)的任何更改在電源循環(huán)之間也不是持久的。因此,需要重新配置 PetaLinux 項(xiàng)目以從存儲(chǔ)在第二個(gè)分區(qū)中的 ext4 文件系統(tǒng)引導(dǎo),該分區(qū)可以訪問(wèn) eMMC 芯片的其余 8GB 內(nèi)存。這也意味著 MiniZed 上的 eMMC 需要重新分區(qū)以具有格式化為 FAT 的引導(dǎo)分區(qū)和格式化為 ext4 的根文件系統(tǒng)分區(qū)。

在重新分區(qū)和重新格式化 eMMC 之前,我們需要在 initramfs 中運(yùn)行的當(dāng)前嵌入式 Linux 版本中添加一些庫(kù)文件以格式化 eMMC,特別是在 e2fsprogs 實(shí)用程序集中用于格式化 ext4 中的分區(qū)的庫(kù)。我嘗試添加這些文件系統(tǒng)包并僅從 QSPI 閃存映像生成一個(gè)新啟動(dòng),但它使內(nèi)核太大而無(wú)法放入 MiniZed 的默認(rèn)分區(qū),所以我使用了這個(gè) hack 解決方法:

  • 在 rootfs 中啟用 e2fsprogs 構(gòu)建項(xiàng)目以獲得所需的 ext4 文件系統(tǒng)格式化文件。
  • 將 rootfs.tar.gz 精確到我計(jì)算機(jī)上的臨時(shí)位置。
  • 將所需的庫(kù)文件從 /sbin 和 /lib 復(fù)制到閃存驅(qū)動(dòng)器以傳輸?shù)?MiniZed。

首先,將目錄更改為 Petalinux 項(xiàng)目并打開(kāi)根文件系統(tǒng)配置編輯器:

cd ./minized/minized_emmc_enhanced_2019_2
petalinux-config -c rootfs

導(dǎo)航到 Filesystem Packages > base > e2fsprogs 并啟用所有包選項(xiàng):

poYBAGN290WAYfmJAABcSTolxhQ273.png
?

構(gòu)建 PetaLinux 項(xiàng)目:

petalinux-build

構(gòu)建完成后,在您的 PC 上創(chuàng)建一個(gè)臨時(shí)目錄以精確根文件系統(tǒng),以便您可以將所需的 sbin 和 lib 文件復(fù)制到閃存驅(qū)動(dòng)器(獲取所有庫(kù)依賴項(xiàng)以避免 Invalid ELF Header 消息)。

mkdir -p <project path>/image/linux/tmp_rootfs
tar -xvf /image/linux/rootfs.tar.gz
cp <project path>/image/linux/tmp_rootfs/lib/libcom_err.so /dev/sda1
cp /image/linux/tmp_rootfs/lib/libcom_err.so.2 /dev/sda1
cp <project path>/image/linux/tmp_rootfs/lib/libcom_err.so.2.1 /dev/sda1
cp /image/linux/tmp_rootfs/lib/libe2p.so /dev/sda1
cp <project path>/image/linux/tmp_rootfs/lib/libe2p.so.2 /dev/sda1
cp /image/linux/tmp_rootfs/lib/libe2p.so.2.3 /dev/sda1
cp <project path>/image/linux/tmp_rootfs/lib/libext2fs.so /dev/sda1
cp /image/linux/tmp_rootfs/lib/libext2fs.so.2 /dev/sda1
cp <project path>/image/linux/tmp_rootfs/lib/libext2fs.so.2.4 /dev/sda1
cp /image/linux/tmp_rootfs/sbin/mke2fs /dev/sda1
cp <project path>/image/linux/tmp_rootfs/sbin/mkfs.ext4 /dev/sda1

將第二根 USB 電纜連接到 Minized 上的 AUX 電源端口,將 USB 閃存驅(qū)動(dòng)器插入其中,然后將庫(kù) (lib) 文件復(fù)制到 /lib 目錄,并將 make 文件系統(tǒng)文件 (mkfs) 復(fù)制到 /sbin 目錄。

root@MiniZed:~# cp /dev/sda1/libcom_err.so /lib
root@MiniZed:~# cp /dev/sda1/libcom_err.so.2 /lib
root@MiniZed:~# cp /dev/sda1/libcom_err.so.2.1 /lib
root@MiniZed:~# cp /dev/sda1/libe2p.so /lib
root@MiniZed:~# cp /dev/sda1/libe2p.so.2 /lib
root@MiniZed:~# cp /dev/sda1/libe2p.so.2.3 /lib
root@MiniZed:~# cp /dev/sda1/libext2fs.so /lib
root@MiniZed:~# cp /dev/sda1/libext2fs.so.2 /lib
root@MiniZed:~# cp /dev/sda1/libext2fs.so.2.4 /lib
root@MiniZed:~# cp /dev/sda1/mke2fs /sbin
root@MiniZed:~# cp /dev/sda1/mkfs.ext4 /sbin

將文件復(fù)制到 MiniZed 上后,移除閃存驅(qū)動(dòng)器并返回 PC 上的 PetaLinux 項(xiàng)目。回到根文件系統(tǒng)編輯器,禁用 e2fsprogs 包,然后重建項(xiàng)目。

petalinux-build

繼續(xù)重新配置 Linux 映像以從 ext4 類型的外部文件系統(tǒng)引導(dǎo),打開(kāi) PetaLinux 硬件配置編輯器:

petalinux-config

導(dǎo)航到 Image Packaging Configuration 選項(xiàng)卡,首先將 Root 文件系統(tǒng)類型更改為 EXT (SD/eMMC/QSPI/SATA/USB)。然后將 SD 設(shè)備的設(shè)備節(jié)點(diǎn)更新為 /dev/mmcblk1p2,如您所見(jiàn),它將與我們將在后面的步驟中創(chuàng)建的 eMMC 中的 ext4 分區(qū)的名稱匹配。

編輯 Root 文件系統(tǒng)格式以僅包含 ext4。最后,禁用 TFTP 引導(dǎo)選項(xiàng)。

?
?
?
poYBAGN290eAT0UAAABE4u6M3vA253.png
?
1 / 4
?

保存并退出 PetaLinux 硬件配置編輯器。

我在之前的項(xiàng)目中介紹了如何創(chuàng)建自定義網(wǎng)絡(luò)服務(wù)器以在 MiniZed 上運(yùn)行,以及如何使用MiniZed 的 Arduino 標(biāo)頭 GPIO驅(qū)動(dòng)電磁鐵我決定通過(guò)向 PetaLinux 項(xiàng)目添加自定義配方,從這些項(xiàng)目中獲取源文件并將它們打包到根文件系統(tǒng)中的用戶包中。這樣,它們將始終在 MiniZed 上的這個(gè)新的嵌入式 Linux 映像中可用。

/project-spec/meta-user/目錄中創(chuàng)建一個(gè)新的配方目錄:

mkdir -p project path>/project-spec/meta-user/recipe-knitronics

在配方目錄中創(chuàng)建特定的包目錄:

mkdir -p project path>/project-spec/meta-user/recipe-knitronics/gameboard

創(chuàng)建一個(gè)名為“files”的目錄和一個(gè)與包目錄同名的 bitbake 文件:

mkdir -p project path>/project-spec/meta-user/recipe-knitronics/gameboard/files
nano /project-spec/meta-user/recipe-knitronics/gameboard/gameboard.bb
?
?
?
pYYBAGN290mAGpN-AABn3GPR3LE951.png
?
1 / 3
?

bitbake 文件在 Yocto 工具集(PetaLinux 所基于)中的作用與 Makefile 在 PC 上的一般構(gòu)建自動(dòng)化中所起的作用相同。bitbake 指定如何將配方中的文件安裝到嵌入式 Linux 映像中。在這種情況下,bitbake 非常簡(jiǎn)單,因?yàn)樗枰龅木褪菑?fù)制 Web 服務(wù)器的項(xiàng)目源文件并將 GPIO 控制到嵌入式 Linux 映像的根目錄中。

為了簡(jiǎn)化 bitbake 中的代碼,我將 webserver 目錄壓縮到一個(gè) tarball 中,并將其指定為將復(fù)制到嵌入式 Linux 映像的根目錄中的內(nèi)容。

將以下代碼添加到 bitbake 以將在根目錄的“文件”文件夾中指定的所有文件。

SUMMARY = "MiniZed Gameboard"
DESCRIPTION = "Files for MiniZed webserver-enabled gameboard"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

#FILESEXTRAPATHS_prepend := "${THISDIR}/files:"

SRC_URI += "file://gpio_driver.py \
            file://gpio_setup.py \
            file://gameboard-webserver.tar.xz;unpack=0 \
"

do_install() {
    install -d ${D}/home/root/
    cp -r ${WORKDIR}/gpio_driver.py ${D}/home/root/
    cp -r ${WORKDIR}/gpio_setup.py ${D}/home/root/
    install -m 0755 ${WORKDIR}/gameboard-webserver.tar.xz ${D}/home/root/
}

FILES_${PN} = " \
    /home/root/gpio_driver.py \
    /home/root/gpio_setup.py \
    /home/root/gameboard-webserver.tar.xz \
"

將所有源文件添加到新配方中的 files 目錄并完成 bitbake 文件后,編輯/project-spec/meta-user/conf中的 user-rootfsconfig以添加以下行:

CONFIG_gameboard

這使根文件系統(tǒng)編輯器知道新配方可作為用戶定義包的選項(xiàng)使用。要將其添加到下一個(gè)構(gòu)建,請(qǐng)打開(kāi)根文件系統(tǒng)編輯器:

petalinux-config -c rootfs

導(dǎo)航到用戶包,您將看到新包作為啟用選項(xiàng)。

?
?
?
poYBAGN2906AXE1HAAP0H-qZ6VA996.png
?
1 / 2
?

啟用游戲板包,然后保存并關(guān)閉根文件系統(tǒng)編輯器。

編輯/project-spec/meta-user/recipes-bsp/minized-misc/files目錄中的 wpa_supplicant.conf 文件,其中包含您要連接 MiniZed 的網(wǎng)絡(luò)的 Wi-Fi SSID 和密碼。

最后,構(gòu)建 PetaLinux 項(xiàng)目:

petalinux-build

構(gòu)建完成后,使用 petalinux-package 命令創(chuàng)建新的引導(dǎo)二進(jìn)制映像:

petalinux-package --boot --fsbl <project directory>/images/linux/zynq_fsbl.elf --fpga . /images/linux/system.bit --u-boot --force

旁注:PetaLinux 2020.1 在為 SD 設(shè)備打包根文件系統(tǒng)和引導(dǎo)二進(jìn)制文件的方式上進(jìn)行了重大升級(jí),因此雖然我認(rèn)為這種方法與舊版本的 PetaLinux 相當(dāng)向后兼容,但我認(rèn)為它不適用于2020.1.

/image/linux目錄,將 BOOT.BIN、image.ub 和 rootfs.ext4 復(fù)制到 USB 閃存驅(qū)動(dòng)器。

再次,將第二條 USB 電纜連接到 MiniZed 上的 AUX 電源端口,然后將閃存驅(qū)動(dòng)器插入其中。

從根本上說(shuō),我遵循與為 FPGA 準(zhǔn)備 SD 卡以啟動(dòng)和運(yùn)行其文件系統(tǒng)相同的過(guò)程,將 eMMC 視為 SD 卡。

卸載 eMMC 并在其上運(yùn)行 fdisk 實(shí)用程序:

root@MiniZed:~# umount /dev/mmcblk1p1
root@MiniZed:~# fdisk /dev/mmcblk1

調(diào)整默認(rèn)分區(qū)的大小,使 eMMC 的引導(dǎo)分區(qū) mmcblk1p1 為 512MB,而 mmcblk1p2 的剩余大小為根文件系統(tǒng)的 8GB。

Command (m for help): d
Selected partition 1
Command (m for help): n
Command action
  e   extended
  p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-232448, default 1): 1
Last cylinder or +size or +sizeM or +sizeK (122-232448, default 232448): +512M
Command (m for help): a
Partition number (1-4): 1
Command (m for help): p
Disk /dev/mmcblk1: 7616 MB, 7616856064 bytes
4 heads, 16 sectors/track, 232448 cylinders
Units = cylinders of 64 * 512 = 32768 bytes
       Device Boot      Start         End      Blocks  Id System
/dev/mmcblk1p1   *          1       15747      500032  83 Linux
Command (m for help): n
Command action
  e   extended
  p   primary partition (1-4)
p
Partition number (1-4): 2
First cylinder (1-232448, default 1): 15748
Last cylinder or +size or +sizeM or +sizeK (15748-232448, default 232448): Using default value 232448
Command (m for help): p
Disk /dev/mmcblk1: 7616 MB, 7616856064 bytes
4 heads, 16 sectors/track, 232448 cylinders
Units = cylinders of 64 * 512 = 32768 bytes
       Device Boot      Start         End      Blocks  Id System
/dev/mmcblk1p1   *           1       15747      500032  83 Linux
/dev/mmcblk1p2           15748      232448     6934432  83 Linux
Command (m for help): w

鍵入“w”將新分區(qū)寫(xiě)入磁盤(pán)。

退出 fdisk 實(shí)用程序后,將第二個(gè)分區(qū) (mmcblk1p2) 格式化為 ext4:

root@MiniZed:~# mkfs.ext4 -L root /dev/mmcblk1p2

創(chuàng)建一個(gè)目錄來(lái)掛載分區(qū)。

root@MiniZed:~# root@MiniZed:~# mkdir /mnt/emmc_rootfs
root@MiniZed:~# mount /dev/mmcblk1p2 /mnt/emmc_rootfs

將壓縮的根文件系統(tǒng)映像 (rootfs.ext4) 復(fù)制到該目錄。

root@MiniZed:~# cp /run/media/sda1/linux_ver1/rootfs.ext4 /mnt/emmc_rootfs/

創(chuàng)建一個(gè)臨時(shí)目錄以掛載到以防需要額外空間,然后將根文件系統(tǒng)內(nèi)容復(fù)制回第一個(gè)目錄。

root@MiniZed:~# mkdir /mnt/ext4
root@MiniZed:~# mount /mnt/emmc_rootfs/rootfs.ext4 /mnt/ext4/ -o loop
root@MiniZed:~# cp -rf /mnt/ext4/* /mnt/emmc_rootfs/

卸載臨時(shí)目錄并刪除壓縮的根文件系統(tǒng)映像。

root@MiniZed:~# umount /mnt/ext4/
root@MiniZed:~# rm /mnt/emmc_rootfs/rootfs.ext4

使用新的啟動(dòng)二進(jìn)制映像刷新 QSPI:

root@MiniZed:~# flashcp /run/media/sda1/linux_ver1/BOOT.BIN /dev/mtd0

將第一個(gè)分區(qū) (mmcblk1p1) 格式化為 FAT:

root@MiniZed:~# mkfs.vfat -F 32 -n BOOT /dev/mmcblk1p1

創(chuàng)建一個(gè)目錄來(lái)掛載分區(qū)。

root@MiniZed:~# mkdir /mnt/emmc_BOOT
root@MiniZed:~# mount /dev/mmcblk1p1 /mnt/emmc_BOOT/

將內(nèi)核映像和引導(dǎo)二進(jìn)制映像復(fù)制到引導(dǎo)分區(qū)。

root@MiniZed:~# cp /run/media/sda1/linux_ver1/BOOT.BIN /mnt/emmc_BOOT/
root@MiniZed:~# cp /run/media/sda1/linux_ver1/image.ub /mnt/emmc_BOOT/

完全關(guān)閉 MiniZed,然后使用重置按鈕重新開(kāi)啟。

root@MiniZed:~# shutdown -h now

重新開(kāi)機(jī)后,運(yùn)行 Wi-Fi 連接腳本以在 wpa_supplicant.conf 中指定的無(wú)線網(wǎng)絡(luò)上獲取 MiniZed:

root@MiniZed:~# wifi.sh

運(yùn)行 GPIO 設(shè)置 Python 腳本以導(dǎo)出 MiniZed 的 Arduino 接頭上的所有引腳,以便它們可供 GPIO 驅(qū)動(dòng)程序腳本使用。

root@MiniZed:~# python3 ./gpio_setup.py

將 webserver tarball 解壓縮到根目錄并通過(guò)運(yùn)行主要 Python 腳本來(lái)啟動(dòng)它:

root@MiniZed:~# tar -xvf gameboard-webserver.tar.xz ./
root@MiniZed:~# python3 ./gameboard-webserver/webserver.py

通過(guò)在您的 PC 或手機(jī)上的網(wǎng)絡(luò)瀏覽器中連接到 MiniZed 的分配 IP 來(lái)測(cè)試網(wǎng)絡(luò)服務(wù)器。

?
?
?
pYYBAGN291eAQqEtAACq3e17ujo785.png
?
1 / 2 ?顯然網(wǎng)頁(yè)設(shè)計(jì)不是我的強(qiáng)項(xiàng)...
?

現(xiàn)在,任何連接到同一個(gè) Wi-Fi 網(wǎng)絡(luò)的設(shè)備都可以連接到游戲板的主頁(yè),為游戲板鍵入下一個(gè)短語(yǔ)。

構(gòu)建游戲板盒

當(dāng)我第一次有這個(gè)項(xiàng)目的想法時(shí),建造圍欄是我最缺乏經(jīng)驗(yàn)的,所以我決定在我當(dāng)?shù)氐乃囆g(shù)用品商店四處逛逛,看看我的一些選擇是什么。由于整個(gè)項(xiàng)目都是基于電磁鐵的使用,我知道我想要一些薄的、有色金屬的,但也很堅(jiān)固。我一直傾向于木材,當(dāng)我在藝術(shù)用品商店遇到一整塊各種形狀和大小的工藝木材時(shí),我的選擇就被鞏固了。

我想在盒子里留出足夠的空間來(lái)舒適地容納游戲板的所有內(nèi)容,并能夠添加未來(lái)的更新/修復(fù),但它至少在某種程度上仍然類似于游戲板的尺寸。所以我決定一個(gè) 1 英寸的內(nèi)部厚度,只有頂部和底部的膠合板加上外部厚度是最好的中間地帶。我還想盡量減少我必須做的切割量,因?yàn)槟竟な且粋€(gè)新發(fā)現(xiàn)對(duì)我來(lái)說(shuō)技能,所以我選擇將游戲板盒保持為膠合板進(jìn)來(lái)的尺寸,即 12"x24"。

我最終使用的木材和用品是:

  • 24 英寸 x 1 英寸 x 1/2 英寸低音木板 - (x2) 作為盒子蓋的支撐支柱,因?yàn)槟z合板非常薄,對(duì)電磁鐵的干擾最小。
  • 24 英寸 x 1 英寸 x 1 英寸低音木板 - (x4) 用于游戲板盒的側(cè)面。
  • 24 英寸 x 12 英寸 x 1/4 英寸工藝膠合板 - (x1) 作為游戲板盒的底部。
  • 24 英寸 x 12 英寸 x 1/32 英寸樺木膠合板 - (x1) 用于帶有顯靈板設(shè)計(jì)的游戲板盒蓋。
  • 斜接盒用于切割游戲板盒側(cè)面的低音木板和盒內(nèi)的支撐支柱。
  • 埃爾默木匠的木膠
  • 金屬薄膜膠帶用于裝飾盒子的外部。
  • 打磨任何邊緣和表面的砂紙塊。
  • 用于安裝蓋子的螺絲,但也可以選擇在將來(lái)移除以進(jìn)行更新/修復(fù)。

我首先使用斜接盒切割 24" x 1" x 1" 低音木板,使其末端具有 45 度角,為游戲板盒創(chuàng)建框架。然后我使用木膠將框架粘合在一起。然后我將框架粘在 24" x 12" x 1/4" 工藝膠合板上,形成盒子的下半部分。

?
?
?
pYYBAGN291qAdHyDAAG3ux8EkBo225.png
?
1 / 3
?

我想得到一些字母印章和油漆,以在 24" x 12" x 1/32" 樺木膠合板上手工重新創(chuàng)建占卜板設(shè)計(jì),但經(jīng)過(guò)短暫的反復(fù)試驗(yàn),很快就發(fā)現(xiàn)我沒(méi)有沒(méi)有藝術(shù)技巧讓它看起來(lái)像我想要的那樣。所以我跑到我當(dāng)?shù)氐倪\(yùn)輸商店打印出一張 11"x 17" 小報(bào)大小的占卜板圖像,粘在游戲板的頂部(1/32英寸厚的膠合板)。

為了構(gòu)圖,我使用了在藝術(shù)用品商店找到的令人敬畏的金屬金色薄膜膠帶。我很快就知道,雖然我那把可憐的剪刀非常鈍,但這膠帶是相當(dāng)堅(jiān)硬的東西。

pYYBAGN292GADETDAAMHMxmxO8A179.png
?

我打破了我心愛(ài)的 Dymo 標(biāo)簽制造商,添加了“Knitronics”和“Halloween 2020”標(biāo)簽。

?
?
?
pYYBAGN292aAUj5YAAdsxm5w8uU364.png
?
1 / 2
?

我還將游戲板底座的邊緣包裹在相同的金色膠帶中。

游戲板盒中的電路布局

對(duì)于游戲板的膽量,我打算讓電磁鐵足夠堅(jiān)固,成為唯一必要的機(jī)械部件。我購(gòu)買了直徑為 1 英寸的空白金屬撞擊板,它是釹磁鐵(不是永磁體,但非常含鐵),用于連接到壓板的腳上,以便電磁鐵拉動(dòng)它。

poYBAGN292uAM_6CAAZBunbcjtc706.png
?

然而,我發(fā)現(xiàn)沒(méi)有一個(gè)愛(ài)好者大小(又名合理大?。┑碾姶盆F足夠強(qiáng)大,可以從半厘米以上的地方吸引木板。

pYYBAGN293CAIdHnAAZm1hOb6ho377.png
?

這導(dǎo)致我實(shí)施了一個(gè)帶皮帶和滑輪系統(tǒng)的直流電機(jī),它可以拉動(dòng)電磁鐵。通過(guò)使用帶皮帶的雙極電機(jī),我將電磁鐵連接到皮帶的底部,電機(jī)能夠在任一方向旋轉(zhuǎn)以前后拉??動(dòng)電磁鐵。

poYBAGN293WAAwdaAAjh5nGYseA003.png
?

我從 Adafruit 找到了一些非常適合這項(xiàng)工作的迷你雙極步進(jìn)電機(jī),最后我使用 3D 打印機(jī)更換零件來(lái)更換滑輪和皮帶。

pYYBAGN293uAAds9AAmrzJw-g0I082.png
?

為了驅(qū)動(dòng)電磁鐵,我使用了一個(gè)簡(jiǎn)單的達(dá)林頓驅(qū)動(dòng)電路(使用ULN2803 )來(lái)允許 MiniZed 的 GPIO 打開(kāi)和關(guān)閉它們,同時(shí)保護(hù) MiniZed 的 IO 免受從電源斷開(kāi)時(shí)產(chǎn)生的反向電流的影響電磁鐵。對(duì)于步進(jìn)電機(jī),我使用了L293N H 橋 IC。

?
?
?
poYBAGN2936ALEbDAARFcWWOVws612.png
?
1 / 2 ?驅(qū)動(dòng)電路的電路圖和原理圖。
?

更新 GPIO 驅(qū)動(dòng)程序腳本

由 webserver (spell_phrase.py) 調(diào)用的 GPIO 驅(qū)動(dòng)程序腳本最終負(fù)責(zé)將網(wǎng)頁(yè)中的字符串形式的輸入短語(yǔ)轉(zhuǎn)換為相應(yīng)的 GPIO 切換以控制電磁鐵和電機(jī)的邏輯。

最后一分鐘的短片只讓我有一行工作,所以這就是我在這里包含的代碼。最終,該腳本由 main 函數(shù)中的一個(gè) case 語(yǔ)句組成,用于在 Ouija 板 (A - M) 的第一行中的可訪問(wèn)字符,以及其他四個(gè)函數(shù)。其他四個(gè)功能是用于電磁鐵和電機(jī)的 GPIO 控制器功能。

電磁鐵函數(shù)將 MiniZed 的每個(gè) GPIO 引腳作為文件對(duì)象打開(kāi) GPIO 編號(hào),導(dǎo)出引腳,然后將其設(shè)置引腳的方向輸出。

電機(jī)正向和反向功能也將每個(gè) GPIO 引腳作為文件對(duì)象打開(kāi) GPIO 編號(hào),導(dǎo)出引腳,然后將其設(shè)置引腳的方向輸出。由于步進(jìn)電機(jī)將其一個(gè)完整的旋轉(zhuǎn)分成多個(gè)相等的步數(shù),這轉(zhuǎn)化為一次將電流施加到步進(jìn)電機(jī)的四個(gè)相位輸入之一的特定順序;這意味著切換 H 橋的 4 個(gè) GPIO 輸入的特定序列。

由于我使用的是 4 針步進(jìn)電機(jī),因此將其向前驅(qū)動(dòng)一圈的順序如下:

步驟1:

  • 引腳0(1)
  • 引腳1(0)
  • 引腳2(1)
  • 引腳3(0)

第2步:

  • 引腳0(0)
  • 引腳1(1)
  • 引腳2(1)
  • 引腳3(0)

第 3 步:

  • 引腳0(0)
  • 引腳1(1)
  • 引腳2(0)
  • 引腳3(1)

第4步:

  • 引腳0(1)
  • 引腳1(0)
  • 引腳2(0)
  • 引腳3(1)

以相反方向驅(qū)動(dòng)步進(jìn)電機(jī)只需向后重復(fù)此序列即可。

最終,我測(cè)量到步進(jìn)器需要大約 381 轉(zhuǎn)才能將連接在皮帶上的電磁鐵從 A 到 M 移動(dòng)字母行的整個(gè)長(zhǎng)度,字母之間大約需要 30 轉(zhuǎn)。這意味著重復(fù)上述序列 30 次將使電磁鐵(以及最終在打開(kāi)時(shí)被吸引到它的板)從一個(gè)字母移動(dòng)到下一個(gè)相鄰字母。

總體而言,腳本從網(wǎng)頁(yè)前端獲取輸入短語(yǔ)并將其解析為單個(gè)字符,然后通過(guò)一個(gè)巨大的 if else 語(yǔ)句(case 語(yǔ)句的 Python 版本),其中每個(gè)字符都被分配一個(gè)數(shù)值。保存前一個(gè)字符的值,兩個(gè)數(shù)值之間的差乘以在相鄰字母之間移動(dòng)所需的步進(jìn)器轉(zhuǎn)數(shù)提供所需的距離和方向數(shù)據(jù)。

spell_phrase.py 的代碼:

import os
import re
import sys 
import time
import requests
import subprocess

emag0 = '/sys/class/gpio/gpio999/'
emag1 = '/sys/class/gpio/gpio1000/'
motor0a = '/sys/class/gpio/gpio1001/'
motor0c = '/sys/class/gpio/gpio1002/'
motor0b = '/sys/class/gpio/gpio1003/'
motor0d = '/sys/class/gpio/gpio1004/'

def emag_on(emag):
    emagPath = emag + 'value'
    emagFile = open(emagPath,'w')
    emagFile.write('1')
    emagFile.close()

def emag_off(emag):
    emagPath = emag + 'value'
    emagFile = open(emagPath,'w')
    emagFile.write('0')
    emagFile.close()

def motor0_forward(distance):
    for x in range(1, distance):
        motorPath0a = motor0a + 'value'
        motorPath0c = motor0c + 'value'
        motorPath0b = motor0b + 'value'
        motorPath0d = motor0d + 'value'

        motorFile0a = open(motorPath0a,'w')
        motorFile0c = open(motorPath0c,'w')
        motorFile0b = open(motorPath0b,'w')
        motorFile0d = open(motorPath0d,'w')

        motorFile0a.write('1')
        motorFile0c.write('0')
        motorFile0b.write('1')
        motorFile0d.write('0')

        motorFile0a.close()
        motorFile0c.close()
        motorFile0b.close()
        motorFile0d.close()

        motorFile0a = open(motorPath0a,'w')
        motorFile0c = open(motorPath0c,'w')
        motorFile0b = open(motorPath0b,'w')
        motorFile0d = open(motorPath0d,'w')

        motorFile0a.write('0')
        motorFile0c.write('1')
        motorFile0b.write('1')
        motorFile0d.write('0')

        motorFile0a.close()
        motorFile0c.close()
        motorFile0b.close()
        motorFile0d.close()

        motorFile0a = open(motorPath0a,'w')
        motorFile0c = open(motorPath0c,'w')
        motorFile0b = open(motorPath0b,'w')
        motorFile0d = open(motorPath0d,'w')

        motorFile0a.write('0')
        motorFile0c.write('1')
        motorFile0b.write('0')
        motorFile0d.write('1')

        motorFile0a.close()
        motorFile0c.close()
        motorFile0b.close()
        motorFile0d.close()

        motorFile0a = open(motorPath0a,'w')
        motorFile0c = open(motorPath0c,'w')
        motorFile0b = open(motorPath0b,'w')
        motorFile0d = open(motorPath0d,'w')

        motorFile0a.write('1')
        motorFile0c.write('0')
        motorFile0b.write('0')
        motorFile0d.write('1')

        motorFile0a.close()
        motorFile0c.close()
        motorFile0b.close()
        motorFile0d.close()

def motor0_backward(distance):
    for x in range(1, distance):
        motorPath0a = motor0a + 'value'
        motorPath0c = motor0c + 'value'
        motorPath0b = motor0b + 'value'
        motorPath0d = motor0d + 'value'

        motorFile0a = open(motorPath0a,'w')
        motorFile0c = open(motorPath0c,'w')
        motorFile0b = open(motorPath0b,'w')
        motorFile0d = open(motorPath0d,'w')

        motorFile0a.write('1')
        motorFile0c.write('0')
        motorFile0b.write('0')
        motorFile0d.write('1')

        motorFile0a.close()
        motorFile0c.close()
        motorFile0b.close()
        motorFile0d.close()

        motorFile0a = open(motorPath0a,'w')
        motorFile0c = open(motorPath0c,'w')
        motorFile0b = open(motorPath0b,'w')
        motorFile0d = open(motorPath0d,'w')

        motorFile0a.write('0')
        motorFile0c.write('1')
        motorFile0b.write('0')
        motorFile0d.write('1')

        motorFile0a.close()
        motorFile0c.close()
        motorFile0b.close()
        motorFile0d.close()

        motorFile0a = open(motorPath0a,'w')
        motorFile0c = open(motorPath0c,'w')
        motorFile0b = open(motorPath0b,'w')
        motorFile0d = open(motorPath0d,'w')

        motorFile0a.write('0')
        motorFile0c.write('1')
        motorFile0b.write('1')
        motorFile0d.write('0')

        motorFile0a.close()
        motorFile0c.close()
        motorFile0b.close()
        motorFile0d.close()

        motorFile0a = open(motorPath0a,'w')
        motorFile0c = open(motorPath0c,'w')
        motorFile0b = open(motorPath0b,'w')
        motorFile0d = open(motorPath0d,'w')

        motorFile0a.write('1')
        motorFile0c.write('0')
        motorFile0b.write('1')
        motorFile0d.write('0')

        motorFile0a.close()
        motorFile0c.close()
        motorFile0b.close()
        motorFile0d.close()

def spell_phrase(phrase):
    char_num = 1
    emag_on(emag0)

    if(phrase!=None):
        [char for char in phrase]:
            if char == 'a' or char == 'A':
                next_char_num = 1
                distance = (char_num - next_char_num)*30
                if distance == 0 or distance < 0:
                    # already at edge of board
                else:
                    motor0_forward(distance)

            elif char == 'b' or char == 'B':
                next_char_num = 2
                distance = (char_num - next_char_num)*30
                if distance < 0:
                    motor0_backward(distance)
                else:
                    motor0_forward(distance)

            elif char == 'c' or char == 'C':
                next_char_num = 3
                distance = (char_num - next_char_num)*30
                if distance < 0:
                    motor0_backward(distance)
                else:
                    motor0_forward(distance)

            elif char == 'd' or char == 'D':
                next_char_num = 4
                distance = (char_num - next_char_num)*30
                if distance < 0:
                    motor0_backward(distance)
                else:
                    motor0_forward(distance)

            elif char == 'e' or char == 'E':
                next_char_num = 5
                distance = (char_num - next_char_num)*30
                if distance < 0:
                    motor0_backward(distance)
                else:
                    motor0_forward(distance)

            elif char == 'f' or char == 'F':
                next_char_num = 6
                distance = (char_num - next_char_num)*30
                if distance < 0:
                    motor0_backward(distance)
                else:
                    motor0_forward(distance)

            elif char == 'g' or char == 'G':
                next_char_num = 7
                distance = (char_num - next_char_num)*30
                if distance < 0:
                    motor0_backward(distance)
                else:
                    motor0_forward(distance)

            elif char == 'h' or char == 'H':
                next_char_num = 8
                distance = (char_num - next_char_num)*30
                if distance < 0:
                    motor0_backward(distance)
                else:
                    motor0_forward(distance)

            elif char == 'i' or char == 'I':
                next_char_num = 9
                distance = (char_num - next_char_num)*30
                if distance < 0:
                    motor0_backward(distance)
                else:
                    motor0_forward(distance)

            elif char == 'j' or char == 'J':
                next_char_num = 10
                distance = (char_num - next_char_num)*30
                if distance < 0:
                    motor0_backward(distance)
                else:
                    motor0_forward(distance)

            elif char == 'k' or char == 'K':
                next_char_num = 11
                distance = (char_num - next_char_num)*30
                if distance < 0:
                    motor0_backward(distance)
                else:
                    motor0_forward(distance)

            elif char == 'l' or char == 'L':
                next_char_num = 12
                distance = (char_num - next_char_num)*30
                if distance < 0:
                    motor0_backward(distance)
                else:
                    motor0_forward(distance)

            elif char == 'm' or char == 'M':
                next_char_num = 13
                distance = (char_num - next_char_num)*30
                if distance == 0 or distance < 0:
                    motor0_backward(distance)
                else:
                    # already at edge of baord

            else:
                motor0_backward(1)
                motor0_forward(1)

        char_num = next_char_num
    else:
        phrase = "noPhrase"

    emag_off(emag0)

    return phrase

def main(arg):
    phraseOut = spell_phrase(arg)

if __name__ == "__main__":
    main(sys.argv[1])

項(xiàng)目總結(jié)

我在這個(gè)項(xiàng)目上遇到了一些障礙,然后才把它帶到我想要這個(gè)萬(wàn)圣節(jié)的確切點(diǎn),當(dāng)前版本只依賴于輸入由字母 A - M 組成的字符串。我還想找到更安靜的步進(jìn)電機(jī),但它仍然是一個(gè)今年有趣的道具!我對(duì) MiniZed 機(jī)械地融入這個(gè)項(xiàng)目感到非常滿意,我認(rèn)為它將成為我未來(lái)道具建造項(xiàng)目的首選板。

我已經(jīng)列出了一份清單,我將繼續(xù)升級(jí)主板!我認(rèn)為這將成為現(xiàn)在每個(gè)萬(wàn)圣節(jié)都適合我的主食。我還從機(jī)械設(shè)計(jì)和外殼制造中學(xué)到了很多東西,我已經(jīng)想要升級(jí)了。明年繼續(xù)關(guān)注!

未來(lái)更新:

  • 修改網(wǎng)頁(yè)以在啟動(dòng)時(shí)啟動(dòng)。
  • 讓 GPIO 設(shè)置 Python 腳本在啟動(dòng)時(shí)運(yùn)行,或者讓網(wǎng)絡(luò)服務(wù)器在第一次啟動(dòng)時(shí)運(yùn)行它,然后再接受第一個(gè)輸入短語(yǔ)。
  • 修復(fù)短路以使其他 4 行正常工作。

下載該資料的人也在下載 下載該資料的人還在閱讀
更多 >

評(píng)論

查看更多

下載排行

本周

  1. 1山景DSP芯片AP8248A2數(shù)據(jù)手冊(cè)
  2. 1.06 MB  |  532次下載  |  免費(fèi)
  3. 2RK3399完整板原理圖(支持平板,盒子VR)
  4. 3.28 MB  |  339次下載  |  免費(fèi)
  5. 3TC358743XBG評(píng)估板參考手冊(cè)
  6. 1.36 MB  |  330次下載  |  免費(fèi)
  7. 4DFM軟件使用教程
  8. 0.84 MB  |  295次下載  |  免費(fèi)
  9. 5元宇宙深度解析—未來(lái)的未來(lái)-風(fēng)口還是泡沫
  10. 6.40 MB  |  227次下載  |  免費(fèi)
  11. 6迪文DGUS開(kāi)發(fā)指南
  12. 31.67 MB  |  194次下載  |  免費(fèi)
  13. 7元宇宙底層硬件系列報(bào)告
  14. 13.42 MB  |  182次下載  |  免費(fèi)
  15. 8FP5207XR-G1中文應(yīng)用手冊(cè)
  16. 1.09 MB  |  178次下載  |  免費(fèi)

本月

  1. 1OrCAD10.5下載OrCAD10.5中文版軟件
  2. 0.00 MB  |  234315次下載  |  免費(fèi)
  3. 2555集成電路應(yīng)用800例(新編版)
  4. 0.00 MB  |  33566次下載  |  免費(fèi)
  5. 3接口電路圖大全
  6. 未知  |  30323次下載  |  免費(fèi)
  7. 4開(kāi)關(guān)電源設(shè)計(jì)實(shí)例指南
  8. 未知  |  21549次下載  |  免費(fèi)
  9. 5電氣工程師手冊(cè)免費(fèi)下載(新編第二版pdf電子書(shū))
  10. 0.00 MB  |  15349次下載  |  免費(fèi)
  11. 6數(shù)字電路基礎(chǔ)pdf(下載)
  12. 未知  |  13750次下載  |  免費(fèi)
  13. 7電子制作實(shí)例集錦 下載
  14. 未知  |  8113次下載  |  免費(fèi)
  15. 8《LED驅(qū)動(dòng)電路設(shè)計(jì)》 溫德?tīng)栔?/a>
  16. 0.00 MB  |  6656次下載  |  免費(fèi)

總榜

  1. 1matlab軟件下載入口
  2. 未知  |  935054次下載  |  免費(fèi)
  3. 2protel99se軟件下載(可英文版轉(zhuǎn)中文版)
  4. 78.1 MB  |  537798次下載  |  免費(fèi)
  5. 3MATLAB 7.1 下載 (含軟件介紹)
  6. 未知  |  420027次下載  |  免費(fèi)
  7. 4OrCAD10.5下載OrCAD10.5中文版軟件
  8. 0.00 MB  |  234315次下載  |  免費(fèi)
  9. 5Altium DXP2002下載入口
  10. 未知  |  233046次下載  |  免費(fèi)
  11. 6電路仿真軟件multisim 10.0免費(fèi)下載
  12. 340992  |  191187次下載  |  免費(fèi)
  13. 7十天學(xué)會(huì)AVR單片機(jī)與C語(yǔ)言視頻教程 下載
  14. 158M  |  183279次下載  |  免費(fèi)
  15. 8proe5.0野火版下載(中文版免費(fèi)下載)
  16. 未知  |  138040次下載  |  免費(fèi)