Pick to Light Project 2 WiFi
组件和用品
| × | 1 | ||||
| × | 2 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 4 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
关于这个项目
这是我选择光探索的第二个项目。首先,我概述了我如何看待一个简单的采光工作,并使用串行通信创建了一个简单的采光工作(如果您想了解更多我在这里所做的事情,请阅读本文)。
它可以工作,但通过电缆连接到 PC。在这个项目中,我想使用 Wi-Fi 开发流程,另外我想在拣货确认中包含序列号,这样如果出现任何问题,系统就会知道工人已经拣到了哪里。我将使用与项目 1 相同的方式使用 MKR1000,但使用 WiFi 进行通信。为此,我将使用 UDP(用户数据报协议)。虽然我以前从未使用过它,但由于 Arduino 和 Python 中的库,这证明相对容易创建。
以下步骤与项目 1 大致相似,因此如果您遵循了该步骤,那么您将已经熟悉其中的一些步骤,无需重复。
第一步
首先,我们需要在我们的笔记本电脑或个人电脑上安装 Python v 3.6 或更高版本。你可以从这里下载:
https://www.python.org/downloads/
步骤 2
这次我们将使用 Python socket 库进行通信,它已经安装好了,所以不需要做任何事情来使 UDP 工作。
步骤 3
我们还需要 Arduino IDE,无论是 PC 版还是 Web 版。这些可以在这里下载:
https://www.arduino.cc/en/Main/Software
或连接到这里:
https://create.arduino.cc/
网站上的说明很全面,所以我不会不必要地复制它们。
第 4 步
在您的 PC 或笔记本电脑上启动 Python IDLE 并输入:import os press:enter。
然后输入: os.getcwd() 这应该给你你当前的工作目录(cwd)。
Python 工作目录
第五步
在记事本中,我创建了一个逗号分隔值文件,它非常简单地包含一个格式为始终为 4 位的序列号和一个以逗号分隔的 bin 编号。请参阅下面的记事本屏幕截图以及您可以下载的附加文本文件。我将它保存为我们在步骤 4 中收集的 cwd 中的 sequence1.txt(您可以使用 csv 扩展名保存文件,但 csv 不需要工作)。当我们使用 python 脚本读取文件时,将文件保存到 cwd 可以简化事情,因为我们不必指定存储文件的位置,因为它会自动在 cwd 中查找。
包含 csv 序列的 txt 文件
步骤 6
我们将在 Arduino 草图中使用串行,但仅用于我们可以在串行监视器上看到打印的消息。
第七步
Python脚本需要一次一行读入csv文件的内容,通过UDP连接发送序列号和Bin号,然后等待Arduino返回确认,即最后一个bin号的序列号,表示该零件已被拾取。如果接收到的序列号与上次发送的序列号不匹配,Python 程序将停止并显示指示序列号的错误消息。这将使序列能够在正确的位置重新启动。我在脚本中添加了注释,以便您可以理解我所写的内容。
复制脚本,然后启动 IDLE,然后>File>New File 并将脚本粘贴到窗口中。然后>文件>另存为给它一个名字(只要你知道名字,你怎么称呼它并不重要)。
第八步
Arduino 草图需要连接到互联网,然后等待从 PC 接收 udp 数据以供下一次选择。然后它通过点亮与序列中的 bin 匹配的 LED 来根据它接收到的信息进行操作。然后它需要监视代表该 bin 的按钮以查看它是否被按下。一旦工人按下按钮说零件已被拾取,草图就会亮起 LED 并将包含最后一个序列号的消息发送回 PC 或笔记本电脑,以表明零件已被拾取。然后它等待接收下一个选择的详细信息。
因此,如果您使用的是 Arduino 网络编辑器,请从草图下方复制并在 Arduino 网络编辑器中选择>sketchbook>NEW SKETCH
Arduino 网页编辑器
然后将脚本粘贴到新草图中,完全替换其中的所有内容。
如果您在粘贴草图后立即使用 Arduino 网络编辑器,编辑器会识别出需要创建一个包含该服务器的 SSID 和密码的机密文件。
只是在提供的空间中将相关详细信息添加到文件中的简单案例。
使用 Arduino IDE,它可能同样简单,但如果是,我找不到它。但是,因为我从示例草图 WiFiUdpSendReceiveString 开始我的草图。
如果你打开它,你会发现里面已经有一个标签 arduino_secrets.h。添加您的 SSID 和密码,然后将下面的草图粘贴到已经存在的草图上,并保存为您喜欢的任何名称。
如果您使用的是 Arduino IDE,则需要包含库 WiFi101,以下链接解释了如果您不知道如何添加库。
https://www.arduino.cc/en/Guide/Libraries
下载到 MKR1000。
步骤 9
按照fritzing图连接所有东西。如果您遵循了项目 1,那么您会发现我的接线方式有所不同。这背后的原因是,一旦 MKR1000 上的 WiFi 由于某种原因变为活动状态,引脚 8 和 9 上的功率就会下降并且 LED 不会亮起。我在网上找不到任何其他人发布有关此问题的任何信息,因此我使用晶体管来解决它。我相信会有一个解释,但到目前为止我还没有找到它。
警告! 请确保您使用的电阻适合您使用的 LED 和 NPN 晶体管。还要确保正确接线,因为允许 5V 在引脚 8 和 9 之间短路可能会损坏您的 Arduino。如果不确定,请使用二极管。
第十步
检查 Arduino 是否已连接到服务器,然后使用 F5 运行 Python 脚本,代表 Bin1 的 LED 将亮起。按下按钮确认零件已被拾取,会将序列号发送回 Python 程序进行检查,如果正确,则发送下一个序列。
Python 输出将如下所示
串行监视器输出将如下所示:
您可以通过注释该行来测试序列失败:
myseq.toCharArray(ReplyBuffer, 5);
并取消注释该行:
//char ReplyBuffer[5] ="0001";
如下;
当你现在运行 python 程序时,执行将在第二个 bin 之后停止,因为它会报告第一个 bin 的序列号。
如果序列失败,创建序列的人需要编辑包含序列的文件并重新启动 arduino 和 Python 程序。
结论
好吧,我想我已经实现了我想要做的事情。它很简单,很容易扩展到全尺寸的工作版本。但是,我已经可以看到项目 3 可以改进,即使比赛已经结束,在我有机会做进一步的项目之前,我想我想这样做,看看如何让它变得更好,但仍然保持最初的简单想法。
代码
- Arduino 草图
- Python 脚本
- 序列
Arduino 草图Arduino
要加载到 MKR1000 的草图#include#include #include const int OKbutton =2; // 设置 OK 按钮的引脚/switchconst int Bin1 =8; // bin 1的LED连接到const int Bin2 =9的引脚; // bin 2 的 LED 连接到的引脚String mydata =" "; // 将传入的串行数据读取到设置为空的变量 stringString myseq =" ";int buttonPress =0; // 用于存储按钮状态的变量/switchint status =WL_IDLE_STATUS;#include "arduino_secrets.h" ///////请在“秘密”选项卡中输入您的敏感数据/arduino_secrets.hchar ssid[] =SECRET_SSID; // 您的网络 SSID (name)char pass[] =SECRET_PASS; // 您的网络密码(用于 WPA,或用作 WEP 的密钥)int keyIndex =0; // 您的网络密钥索引号(仅 WEP 需要)unsigned int localPort =2390; // 本地监听端口 onchar packetBuffer[255]; //缓冲区保存传入的packetchar ReplyBuffer[5] =" "; // 一个返回的字符串String mystring;WiFiUDP Udp;void setup() { //初始化串口并等待端口打开:Serial.begin(9600);//一旦设置就不需要所有串口语句了//while ( !Serial) {// 等待串口连接。仅本地 USB 端口需要} // 检查屏蔽是否存在: if (WiFi.status() ==WL_NO_SHIELD) { Serial.println("WiFi shield not present"); // 不要继续:while (true); } // 尝试连接到 WiFi 网络:while ( status !=WL_CONNECTED) { Serial.print("Attempting to connect to SSID:"); Serial.println(ssid); // 连接到 WPA/WPA2 网络。如果使用开放或 WEP 网络,请更改此行: status =WiFi.begin(ssid, pass); // 等待 10 秒连接:delay(10000); } Serial.println("连接到wifi");打印WiFi状态(); Serial.println("\n开始连接服务器..."); // 如果获得连接,则通过串行报告: Udp.begin(localPort);}void loop() { // 如果有可用数据,则读取数据包 int packetSize =Udp.parsePacket(); if (packetSize) { Serial.print("收到大小的数据包"); Serial.println(packetSize); Serial.print("来自"); IPAddress remoteIp =Udp.remoteIP(); Serial.print(remoteIp); Serial.print(", 端口 "); Serial.println(Udp.remotePort()); // 将数据包读入 packetBufffer int len =Udp.read(packetBuffer, 255); if (len> 0) packetBuffer[len] =0; Serial.println("内容:"); Serial.println(packetBuffer);字符串 mystring(packetBuffer); mydata =mystring.substring(4); myseq =mystring.substring(0,4); Serial.println(mydata); Serial.println(myseq); while (mydata !=" "){ // 测试看看 mydata 是否仍然为空 如果不是检查哪个 bin 应该被点亮 if (mydata =="Bin1"){ // 启动 bin 1 例程 digitalWrite(Bin1) , 高的); // 通过将引脚设置为高电平来点亮 bin 1 的 LED digitalWrite(Bin2, LOW); // 通过将引脚设置为低电平来关闭 bin 2 的 LED while (buttonPress !=HIGH) { // 等待按钮按下循环 buttonPress =digitalRead(OKbutton); //继续检查按钮 mydata =" "; // 将 mydata 设置回空字符串 } digitalWrite(Bin1, LOW);// 关闭 bin 1 的 LED Serial.println("Picked"); //发送消息到PC buttonPress =0; //重置按钮低延迟(1000); } if (mydata =="Bin2"){// 启动 bin 2 例程 digitalWrite(Bin2, HIGH);// 通过将引脚设置为高电平来点亮 bin 2 的 LED digitalWrite(Bin1, LOW); // 通过将引脚设置为低电平来关闭 bin 1 的 LED while (buttonPress !=HIGH) { // 等待按钮按下循环 buttonPress =digitalRead(OKbutton); //继续检查按钮 mydata =" "; //将 mydata 设置回空字符串 } digitalWrite(Bin2, LOW); // 关闭 bin 1 的 LED Serial.println("Picked"); //发送消息到PC buttonPress =0; //重置按钮低延迟(1000); } } // 发送回复,发送给我们收到的数据包的 IP 地址和端口 myseq.toCharArray(ReplyBuffer, 5); //char ReplyBuffer[5] ="0001"; // 仅用于测试 Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); udp.write(ReplyBuffer); udp.endPacket(); Serial.println(ReplyBuffer); }}void printWiFiStatus() { // 打印您连接的网络的 SSID: Serial.print("SSID:"); Serial.println(WiFi.SSID()); // 打印你的 WiFi 盾的 IP 地址:IPAddress ip =WiFi.localIP(); Serial.print("IP 地址:"); Serial.println(ip); // 打印接收到的信号强度:long rssi =WiFi.RSSI(); Serial.print("信号强度(RSSI):");串行打印(RSSI); Serial.println("dBm");}
Python 脚本Python
要运行的 Python 脚本。## 加载必要的库import csvimport socketimport timeimport sysUDP_IP ="192.168.1.119" ## ArduinoUDP_PORT 的 ip =2390 ## 我们希望通信的端口 onprint("UDP target IP:" , UDP_IP) ##向userprint显示ip("UDP target port:", UDP_PORT) ##向usersock显示端口=socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #创建sockettime.sleep(5)##open csv 文件并在一行中读取它 open('sequence1.txt') as csvDataFile:csvReader =csv.reader(csvDataFile) for row in csvReader:##for each line do following myseq =row[0] # #读取序列号mystate =row[1] ##读取bin号myrow =row[0] + row[1] print("当前序列被选取",myseq,"from ", mystate) sock.sendto (bytes(myrow, "utf-8"), (UDP_IP, UDP_PORT)) # send seq and bin number data ="" # 设置数据为空进入 while loop i=until data is received while data =="":# 直到收到数据,一直循环遍历 (data, addr) =soc k.recvfrom(1024) # 将数据设置为从套接字接收的数据 mytest =data.decode( "utf-8") #将 mytest 设置为通过套接字接收的相等值 print ("picked =", mytest) # 打印接收到的值 if mytest !=myseq:# 测试接收到的内容与预期的匹配,即最后发送的 seq 打印(“序列中存在序列错误”,mytest)# 显示消息以指示错误 sys.exit() #end program execution if故障存在
序列纯文本
python程序的序列文件0001,Bin10002,Bin20003,Bin10004,Bin20005,Bin10006,Bin20007,Bin10008,Bin20009,Bin10010,Bin20011,Bin101Bin1Bin1Bin1
示意图
UDP Pick to Light 的连接 picktolightudp_OCbpNt9XPK.fzz制造工艺