前言
本章所有代码均已上传至github
https://github.com/Adancurusul/Bedroom_iot/tree/master/door/mqtt
感觉学习网络模块已经有一段时间了,想着给寝室做一个门禁系统顺便当作一个阶段的总结,整个门禁系统还带有指纹识别以及抓拍,但是这里主要讲一下基于mqtt ,利用arduino的c,lua ,和micropython3种方式实现远程控制舵机。
这是门外的实物图用的是一块坏了一部分被闲置的开发板(当时没有注意布局于是很丑。。。)
有关这一部分我后面会陆续更新
基于mqtt的无线控制舵机
发现pyboard中有直接操控舵机转动角度的库函数pyb.servo
使用方法也很详细
但是感觉达不到学习的效果
所以又去看了下有关舵机原理并由此写出相关micropython代码:
驱动舵机转动
舵机原理
控制舵机需要一个20ms左右的时基脉冲,该脉冲的高电平部分为0.5ms-2.5ms范围,总间隔为2ms。脉冲的宽度将决定马达转动的距离。如果是1.5毫秒的脉冲,电机就会停在90度的位置并锁定。如果脉冲宽度小于1.5毫秒,那么电机轴向朝向0度方向转动。如果脉冲宽度大于1.5毫秒反之。
对应的关系大概如下
0.5ms对应0度;
1.0ms对应45度;
1.5ms对应90度;
2.0ms对应135度;
2.5ms对应180度;
舵机驱动
知道原理后,我们便可以着手开始写驱动
micropython中timer的pwm函数可以生成不同占空比的方波
将20ms内的0.5-2.5换成百分比形式就是2.5%-12.5%。7.5即为中间。
这就是我们舵机转动的起始点
我们定义一个变量来控制并初始化
i = 7.5
然后我们初始化pwm控制舵机口对应的timer
频率为50赫兹,x1(STM32的A0)口作为pwm输出
pwm_pin= Pin('X1')
tm3 = Timer(5, freq=50)
a4 = tm3.channel(1, Timer.PWM, pin=pwm_pin)
然后就是给信号转动舵机
我们定义一个定时器来检测引脚值
tim = Timer(4)
#tim.init(period=200, mode=Timer.PERIODIC, callback=check)
tim.init(freq = 100, callback=check)
check函数内可以用iic传字符串来匹配更加稳定,但是我们在调试阶段就用高低电平也无妨
最后控制舵机转动
while True:
if check_p ==1 :
i += 0.01
pyb.udelay(100)
if i > 12.0:
i = 12.0
elif check_p ==3 :
i -= 0.01
pyb.udelay(100)
if i < 3.0:
i = 3.0
a4.pulse_width_percent(i)
这样就可以控制舵机转动了
这一个可以直接用在后面的接入mqtt里面从而只用一个mcu即可
利用micropython接入mqtt
micropython环境搭建以及
公网下mqtt服务器的搭建都在我其他博客写了
在我们搭建好开发环境和服务器之后我们首先用micropython连接到自己搭建的mosquitto服务器,github上面有给出相关库函数以及参考例程https://github.com/micropython/micropython-lib/tree/master/umqtt.simple,
这里我们只将其mqtt文件下的simple通过esplorer或者micropythonfileuploader或者upycraft将文件传入mcu
- 在micropythonfileuploader下我们先连接开发板,然后在com那里找到开发板对应串口,点击open 然后点击文件夹,找到相应的文件点击send即可
如果要查看的话可以import os
然后输入os.listdir(),就会把esp里面的文件全部打印出来
- 当然我们也可以有另一种加入库函数的方式,首先我们利用一串代码让开发板联网
这里给出代码段
def connectWifi(ssid,passwd):
global wlan
wlan=network.WLAN(network.STA_IF)
wlan.active(True)
wlan.disconnect()
wlan.connect(ssid,passwd)
while(wlan.ifconfig()[0]=='0.0.0.0'):
time.sleep(1)
使用时只需传入wifi名和密码即可连接连接wifi
之后import upip 然后upip.install(“upip”)
就可以添加库
upip类似python的pip,这里指向的是在github中的upip库,和直接加载文件效果相同
然后完成后我们import umqtt 发现没有报错
我搭建的服务器主要自己用于是匿名登录时打开的,所以代码中的用户名密码可以随便填入让门禁的密码每一分钟改变一次做一点保护措施
try:
connectWifi(SSID,PASSWORD)
server=SERVER
c=MQTTClient(CLIENT_ID, server,0,username,password)
c.set_callback(sub_cb)
c.connect()
c.subscribe(TOPIC)
key_of_door =str(random.randint(10000,99999))
c.publish(TOPIC2,key_of_door,retain=True)
while True:
if check_p ==1:
check_p =0
key_of_door_r = str(random.randint(1,99999))
m = 5-len(key_of_door)
key_of_door = '0'*m+key_of_door_r
print (key_of_door)
c.publish(TOPIC2,key_of_door,retain=True)
c.wait_msg()
finally:
if(c is not None):
c.disconnect()
wlan.disconnect()
wlan.active(False)
理论上这样就可以连接到mqtt
但是由于门禁系统使用比较少不是随时都在发数据(后期寝室其他监控设备接入可以不用下面一段),长时间无数据会报错,所以我们加一段代码
keepalive = Timer(2)
keepalive.init(period=120000, mode=Timer.PERIODIC, callback=lambda t: c.ping())#保持存活
这里用手机上的mqttdashiboard 软件接入测试测试成功
只用再pub中建立发送对应主题的部分即可
利用lua接入mqtt
在前面文章有关lua环境搭建中我们搭建时的固件含有mqtt库函数
我们先连接wifi
ssid = "adan";
pwd="11223344";
wifi.setmode(wifi.STATIONAP)
wificonfig={}
wificonfig.ssid=ssid
wificonfig.pwd=pwd
wifi.sta.config(wificonfig)
wifi.sta.autoconnect(1)--连接wifi
然后就是连接mqtt服务器
代码库中有两个代码,new版本连接更加稳定同时又比较易懂
tmr.alarm(3, 1000, 1, function()
client:connect(IP, Port,ConnectSuccess,ConnectFailed)
print("connect......");
end)
function ConnectSuccess(client)
tmr.stop(3);
client:subscribe(SubscribeTopic, 0, subscribeSuccess)
print("connected")
mqttConnectedFlage = 1;
end
function ConnectFailed(client,reason)
mqttConnectedFlage = 0;
tmr.start(3)
print("failed reason: " .. reason)
end
function subscribeSuccess(client)
print("subscribeSuccess")
end
client:on("message", function(client, topic, message)
print(topic .. ":" )
if data ~= nil then
print(data)
if data =="open_the_door" then
gpio.write("door_p",1)
print("door_open")
client:publish("state", "door_open", 0,0)
gpio.write(door_p,0)
end
end)
end)
tmr.alarm(2, 1000, 1, function()--定期调用接收函数保持连接
if mqttConnectedFlage == 1 then
client:subscribe("open_the_door", 0, function(client) print("subscribe success") end)
end
end)
这就是基于lua的连接mqtt并控制舵机部分
利用c语言接入mqtt
利用c语言接入这里我们使用arduino来,这样开发速度会更快,首先arduino中下载我们需要用到的库
#include<WiFi.h>
#include<PubSubClient.h>
然后初始化一些连接需要的数据
const char* ssid ="adan";
const char*password = "1122334455";
const char*mqttServer = "113.224.53.24";
const int Port =1883;
const char*User = "whatever";
const char*Password = "nothing";
const char*TOPIC = "opendoor"
const char*TOPIC_R = "state"
int door_pin = 5
WiFiClientespClient;
PubSubClientclient(espClient);
主要wifi连接和mqtt服务器的连接也非常简单
void setup()
{
Serial.begin(115200);
WiFi.begin(ssid,password);
while (WiFi.status()!= WL_CONNECTED)
{
delay(500);
}
Serial.println("wifi connected");
client.setServer(Server,mqttPort);
client.setCallback(callback);
while (!client.connected())
{
if (client.connect("Client",User, Password ))
{
Serial.println("mqtt connected");
}
else
{
Serial.print("error ");
Serial.print(client.state());
delay(2000);
}
}
client.subscribe(TOPIC);
}
随后我们设置一个接收的简单的回调函数
void callback(char*topic, byte* payload, unsigned int length)
{
if((char)payload == 'open')
{
digitalWrite(door_pin,1);
delay(1000);
client.publish(TOPIC_R, "door_open" );
digitalWrite(door_pin,0);
}
最后定期调用函数 保持连接并使数据接收正常
void loop()
{
client.loop()
}
写在最后
本篇用最基本的方法使WiFi模块连接到mqtt服务器
资料最多的还是利用arduino 的,但是如果会micropython或者lua也会使连接变得非常简单
代码也可以自己添加需要部分实现更强的功能
如果有更好的方法或者我代码有不足之处欢迎指出