You are on page 1of 10

Software design document

1. Lựa chọn công cụ phần mềm: trình biên dịch, ngôn ngữ, thư viện
- Nhóm sử dụng 2 arduino nano là các node, sử dụng trình biên dịch là Arduino
IDE,ngôn ngữ lập trình là C, và sử dụng 2 thư viên là <SPI.h> để giao tiếp SPI và
<RH_RF95.h> của module Lora.
- Đối với máy tính nhúng Raspberry Pi, nhóm cài đặt cho nó hệ điều hành là Raspbian,
sử dụng trình biên dịch là python3 với ngôn ngữ lập trình là Python. Đầu tiên nhóm sử dụng
thư viện RPi.GPIO để khai báo các chân, tiếp theo là thư viện SX127x.LoRa để có thể giao
tiếp với module LoRa và cuối cùng là thư viện paho.mqtt.client để có thể giao tiếp MQTT
gửi dữ liệu lên server.

2. Lưu đồ giải thuật chính


3. Lưu đồ giải thuật chương trình con

4. Mô tả và lập trình các chương trình con


- Với code Arduino:
Các bước đầu tiên là khai báo thư viện và khai báo các chân GPIO được chọn. Kèm theo đó
là tần số mặc định để phát sóng Lora là 434 MHz.
Trong phần set up, nhóm khai báo các chân được sử dụng là input hay output, đồng thời đưa
điện áp ở chân reset về thấp rồi lên cao để khởi động module Lora. Sau đó là các câu lệnh
kiểm tra kết nối và báo lỗi nếu chưa thành công và nếu thành công thì cài đặt công suất phát
là 20dBm.
Trong phần loop, đọc giá trị analog (0-1024) rồi đưa vào biến counter, nếu counter > 100
nghĩa là có xe, gán biến counter = 1 và ngược lại counter <100 nghĩa là không có xe, gán biến
counter = 0. Tiếp theo, để phân biệt các module Lora khác nhau, ta phải thêm các kí tự nhận
biết vào gói tin. Cụ thể ở đây là thêm “5” vào gói tin nếu gửi từ module 1 và “6” nếu là
module 2. Dùng câu lệnh
data.toCharArray(d, 3);
để chuyển về định dạng theo đúng mà thư viện Lora đã đề ra. Cuối cùng là gửi gói tin đi.
#include <SPI.h> Khai báo thư viện sử dụng
#include <RH_RF95.h>

#define RFM95_CS 10 Khai báo các chân của module Lora


#define RFM95_RST tương ứng
#define RFM95_INT 2

#define RF95_FREQ 434.0 Chọn tần số hoạt động

RH_RF95 rf95(RFM95_CS, RFM95_INT);


int sensor = 3; Khai báo chân cảm biến và điện trở
int pull_up = 4; kéo lên
void setup()
{ Đặt tốc độ baud là 9600
Serial.begin(9600);
pinMode(sensor, INPUT);
pinMode(pull_up, OUTPUT);
digitalWrite(pull_up,HIGH); Cấp nguồn để có điện trở kéo lên
pinMode(RFM95_RST, OUTPUT); Đóng mở để khởi động module Lora
digitalWrite(RFM95_RST, LOW);
delay(10);
digitalWrite(RFM95_RST, HIGH);
delay(10);

while (!rf95.init()) { Kiểm tra kết nối Lora


Serial.println("LoRa radio init failed");
while (1);
}

if (!rf95.setFrequency(RF95_FREQ)) { Kiểm tra tần số


Serial.println("setFrequency failed");
while (1);
}
rf95.setTxPower(18);
} Đặt công suất phát là 18dBm
void loop()
{
delay(1000); Gửi dữ liệu mỗi giây 1 lần
int counter = !digitalRead(sensor); Đọc dữ liệu từ cảm biến
String data = "6" + String(counter); Thêm kí hiệu phân biệt giữa hai node
char d[3];
data.toCharArray(d, 3); Chuyển gói tin thành kiểu mảng
rf95.send(d, sizeof(d)); Truyền gói tin đi
rf95.waitPacketSent();

Serial.print("counter: ");
Serial.println(counter);
}

- Với code Raspberry:


Đầu tiên, ta cũng khai báo các thư viện sử dụng cùng các chân GPIO được chọn và tần số là
434 MHz.
Tiếp theo, ta điền username, password và client id tương ứng các thông tin nhận được khi
truy cập vào tài khoản ở trang web Cayenne. Sau đó ta tạo 2 topic để gửi tin lên server
Tiếp theo ta cũng có các hàm để kiểm tra kết nối và thông báo giống như ở chương trình
Arduino. Sau khi đã kết nối thành công, gói tin bắt đầu được nhận và ta sẽ dùng các câu lệnh
để tách và phân biệt.
Gói tin sẽ bao gồm 8 byte trong đó byte 1 là byte đệm theo như thư viện Lora, byte 2 là byte
dùng để phân biệt xem là từ module nào gửi đến và byte 3 là data cần hiển thị.
Nếu nhận được byte 2 là 5 thì có nghĩa là module 1 gửi đến và nếu là 6 thì có nghĩa là module
2 gửi đến.
Sau đó dùng các câu lệnh để cập nhật đúng định dạng và publish lên server dùng MQTT.
import RPi.GPIO as GPIO Khai báo thư viện
GPIO.setwarnings(False) GPIO, Lora và
from time import sleep MQTT
from SX127x.LoRa import *
from SX127x.board_config import BOARD
import paho.mqtt.client as mqtt
username = "420f9120-bcf4-11ea-b767-3f1a8f1211ba"
password = Bộ 3 thông số để kết
"281c05992bbff24e24744c050ad3eb382f472719" nối với Web
clientid = "5efb48b0-bcf4-11ea-93bf-d33a96695544" Cayenne
mqttc = mqtt.Client(client_id=clientid)
mqttc.username_pw_set(username, password=password)
mqttc.connect("mqtt.mydevices.com", port=1883,
keepalive=60)
mqttc.loop_start()
topic_counter_1 = "v1/" + username + "/things/" + clientid +
"/data/1" Tạo 2 topic để gửi
topic_counter_2 = "v1/" + username + "/things/" + clientid + dữ liệu đến server từ
"/data/2" 2 node
BOARD.setup()
class LoRaRcvCont(LoRa):
def __init__(self, verbose=False):
super(LoRaRcvCont, self).__init__(verbose)
self.set_mode(MODE.SLEEP)
self.set_dio_mapping([0] * 6)
def start(self):
self.reset_ptr_rx()
self.set_mode(MODE.RXCONT)
while True:
sleep(.5)
rssi_value = self.get_rssi_value()
status = self.get_modem_status()
sys.stdout.flush()
def on_rx_done(self):
print ("\nReceived: ")
self.clear_irq_flags(RxDone=1)
payload = self.read_payload(nocheck=True)
data = bytes(payload).decode("utf-8",'ignore') Gói tin nhận được sẽ
select = (data[2:3]) gán vào data
car = (data[3:4])
if select == 5: Tách được kí tự
counter1 = car nhận biết và dữ liệu
mqttc.publish(topic_counter_1, payload=counter1, cần truyền lên server
retain=True) từ data ( có xe là 1,
print ("Counter 1:",counter1,"xe") không có xe là 0)
elif select == 6: Nếu kí tự nhận biết
counter2 = car là 5, thêm thông tin
mqttc.publish(topic_counter_2, payload=counter2, vào topic 1 rồi gửi
retain=True) lên server
print ("Counter 2:",counter2,"xe") Nếu kí tự nhận biết
print ("Sent to Cayenne") là 6, thêm thông tin
self.set_mode(MODE.SLEEP) vào topic 2 rồi gửi
self.reset_ptr_rx() lên server
self.set_mode(MODE.RXCONT)
lora = LoRaRcvCont(verbose=False) Cấu hình các thông
lora.set_mode(MODE.STDBY) số cho Module Lora,
# Medium Range Defaults after init are 434.0MHz, Bw = ở đây dùng những
125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 13 dBm giá trị mặc định.
lora.set_pa_config(pa_select=1)
try:
lora.start()
except KeyboardInterrupt:
sys.stdout.flush()
print ("")
sys.stderr.write("KeyboardInterrupt\n")
finally:
sys.stdout.flush()
print ("")
lora.set_mode(MODE.SLEEP) Đưa về chế độ ngủ
BOARD.teardown() để tiết kiệm năng
lượng

5. Tổng hợp phần mềm


Dưới đây là code cho Arduino

#include <SPI.h> //Import SPI librarey


#include <RH_RF95.h> // RF95 from RadioHead Librarey

#define RFM95_CS 10 //CS if Lora connected to pin 10


#define RFM95_RST 9 //RST of Lora connected to pin 9
#define RFM95_INT 2 //INT of Lora connected to pin 2

// Change to 434.0 or other frequency, must match RX's freq!


#define RF95_FREQ 434.0

// Singleton instance of the radio driver


RH_RF95 rf95(RFM95_CS, RFM95_INT);
int button = A6;
void setup()
{
Serial.begin(9600);
pinMode(button, INPUT);
pinMode(RFM95_RST, OUTPUT);
digitalWrite(RFM95_RST, LOW);
delay(10);
digitalWrite(RFM95_RST, HIGH);
delay(10);

while (!rf95.init()) {
Serial.println("LoRa radio init failed");
while (1);
}

if (!rf95.setFrequency(RF95_FREQ)) {
Serial.println("setFrequency failed");
while (1);
}

rf95.setTxPower(20);
}

void loop()
{
delay(2000);
int counter = analogRead(button);
if (counter > 100) {counter = 1;}
else {counter = 0;}
String data = "5" + String(counter);
char d[3];
data.toCharArray(d, 3);
rf95.send(d, sizeof(d));
rf95.waitPacketSent();

Serial.print("counter: ");
Serial.println(counter);
}

Dưới đây là code cho Raspberry Pi

import RPi.GPIO as GPIO


GPIO.setwarnings(False)
from time import sleep
from SX127x.LoRa import *
from SX127x.board_config import BOARD
import paho.mqtt.client as mqtt
sleep(30)
username = "420f9120-bcf4-11ea-b767-3f1a8f1211ba"
password = "281c05992bbff24e24744c050ad3eb382f472719"
clientid = "5efb48b0-bcf4-11ea-93bf-d33a96695544"
mqttc = mqtt.Client(client_id=clientid)
mqttc.username_pw_set(username, password=password)
mqttc.connect("mqtt.mydevices.com", port=1883, keepalive=60)
mqttc.loop_start()
topic_counter_1 = "v1/" + username + "/things/" + clientid + "/data/1"
topic_counter_2 = "v1/" + username + "/things/" + clientid + "/data/2"
BOARD.setup()
class LoRaRcvCont(LoRa):
def __init__(self, verbose=False):
super(LoRaRcvCont, self).__init__(verbose)
self.set_mode(MODE.SLEEP)
self.set_dio_mapping([0] * 6)
def start(self):
self.reset_ptr_rx()
self.set_mode(MODE.RXCONT)
while True:
sleep(.5)
rssi_value = self.get_rssi_value()
status = self.get_modem_status()
sys.stdout.flush()
def on_rx_done(self):
print ("\nReceived: ")
self.clear_irq_flags(RxDone=1)
payload = self.read_payload(nocheck=True)
data = bytes(payload).decode("utf-8",'ignore')
select = (data[2:3])
car = (data[3:4])
if select == 5:
counter1 = car
mqttc.publish(topic_counter_1, payload=counter1, retain=True)
print ("Counter 1:",counter1,"xe")
elif select == 6:
counter2 = car
mqttc.publish(topic_counter_2, payload=counter2, retain=True)
print ("Counter 2:",counter2,"xe")
print ("Sent to Cayenne")
self.set_mode(MODE.SLEEP)
self.reset_ptr_rx()
self.set_mode(MODE.RXCONT)
lora = LoRaRcvCont(verbose=False)
lora.set_mode(MODE.STDBY)
# Medium Range Defaults after init are 434.0MHz, Bw = 125 kHz, Cr = 4/5, Sf =
128chips/symbol, CRC on 13 dBm
lora.set_pa_config(pa_select=1)
try:
lora.start()
except KeyboardInterrupt:
sys.stdout.flush()
print ("")
sys.stderr.write("KeyboardInterrupt\n")
finally:
sys.stdout.flush()
print ("")
lora.set_mode(MODE.SLEEP)
BOARD.teardown()

You might also like