Tại thử nghiệm này, ta sẽ kết nối LED với chân GPIO 23 để điều khiển đèn LED bật tắt. Sau đó ta có thể điều khiển LED bật tắt đèn bằng code sau:
import RPi.GPIO as GPIO import time
GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(23,GPIO.OUT) print "LED on"
GPIO.output(23,GPIO.HIGH) time.sleep(1)
print "LED off"
GPIO.output(23,GPIO.LOW)
3.3.1.1.2. Kết nối với Mô-tơ bước:
Đối với mô-tơ bước, em lựa chọn mô-tơ bước 28BYJ-48 cùng với bộ điều khiển ULN2003 đi kèm.
Nguyễn Tiến Hải – D17CQVT08B 44 Hình 3. 12. Mơ-tơ bước 28BYJ-48 và với bộ điều khiển ULN2003
Bộ điều khiển ULN2003 gồm có 4 chân đầu vào và 2 chân nguồn 5-12V Kết nối bộ điều khiển ULN2003 với Raspberry Pi:
- Kết nối IN1 với GPIO Port 17 - Kết nối IN2 với GPIO Port 18 - Kết nối IN3 với GPIO Port 27 - Kết nối IN4 với GPIO Port 22
- Đầu vào nguồn âm nối với cổng GND
- Đầu vào nguồn dương nối với Đầu ra nguồn 5V của Raspberry Pi
Nguyễn Tiến Hải – D17CQVT08B 45 Hình 3. 14. Kết nối thực tế với Mơ-tơ bước
Sau đó ta có thể điều khiển được các mơ-tơ bằng code:
#!/usr/bin/python3 import RPi.GPIO as GPIO import time in1 = 17 in2 = 18 in3 = 27 in4 = 22 step_sleep = 0.002
step_count = 4096 # 5.625*(1/64) per step, 4096 steps is 360°
direction = False # True for clockwise, False for counter-clockwise
step_sequence = [[1,0,0,1], [1,0,0,0], [1,1,0,0], [0,1,0,0],
Nguyễn Tiến Hải – D17CQVT08B 46 [0,1,1,0], [0,0,1,0], [0,0,1,1], [0,0,0,1]] # setting up GPIO.setmode( GPIO.BCM ) GPIO.setup( in1, GPIO.OUT ) GPIO.setup( in2, GPIO.OUT ) GPIO.setup( in3, GPIO.OUT ) GPIO.setup( in4, GPIO.OUT )
# initializing
GPIO.output( in1, GPIO.LOW ) GPIO.output( in2, GPIO.LOW ) GPIO.output( in3, GPIO.LOW ) GPIO.output( in4, GPIO.LOW ) motor_pins = [in1,in2,in3,in4] motor_step_counter = 0 ; def cleanup():
GPIO.output( in1, GPIO.LOW ) GPIO.output( in2, GPIO.LOW ) GPIO.output( in3, GPIO.LOW ) GPIO.output( in4, GPIO.LOW ) GPIO.cleanup() try: i = 0 for i in range(step_count):
for pin in range(0, len(motor_pins)):
GPIO.output( motor_pins[pin], step_sequence[motor_step_counter][pin] ) if direction==True: motor_step_counter = (motor_step_counter - 1) % 8 elif direction==False: motor_step_counter = (motor_step_counter + 1) % 8 else: # defensive programming
print( "uh oh... direction should *always* be either True or False" ) cleanup() exit( 1 ) time.sleep( step_sleep ) except KeyboardInterrupt: cleanup() exit( 1 )
Nguyễn Tiến Hải – D17CQVT08B 47
cleanup() exit( 0 )
Kết quả khi chạy ta sẽ thấy mô-tơ quay theo chiều kim đồng hồ, mỗi bước mô-tơ sẽ chạy được 5.625*(1/64) = 0.087890625 độ. Do đó khi ta chạy 4096 bước, mơ-tơ sẽ chạy trịn 1 vịng.
Hình 3. 15. Bộ điều khiển và Mô-tơ đang hoạt động
3.3.1.1.3. Kết nối với cảm biến nhiệt độ, độ ẩm:
Đối với cảm biến nhiệt độ, độ ẩm, em sử dụng SHT31-D để đo nhiệt độ cũng như độ ẩm trong phòng. SHT31-D gồm 4 chân kết nối:
- Chân Vin: Cấp nguồn dương
- Chân GND: Cấp nguồn âm (GND-mass) - Chân SCL: Chân xung I2C
Nguyễn Tiến Hải – D17CQVT08B 48 Hình 3. 16. Cảm biến nhiệt độ, độ ẩm SHT31-D
Để kết nối SHT31-D và Raspberry Pi, ta cần kích hoạt chế độ I2C của Raspberry Pi, sau đó kết nối chân Vin và chân GND với chân nguồn 3V và GND của Raspberry Pi. Chân SCL và SDA lần lượt nối với chân GPIO 2 và GPIO 3 (hỗ trợ I2C).
Nguyễn Tiến Hải – D17CQVT08B 49 Hình 3. 18. Kết nối thực tế với SHT31-D
Sau đó ta có thể nhận thơng số nhiệt độ, độ ẩm bằng code:
import smbus import time # Get I2C bus
bus = smbus.SMBus(1) # SHT31 address, 0x44(68) bus.write_i2c_block_data(0x44, 0x2C, [0x06]) time.sleep(0.5) # SHT31 address, 0x44(68)
# Read data back from 0x00(00), 6 bytes
# Temp MSB, Temp LSB, Temp CRC, Humididty MSB, Humidity LSB, Humidity CRC data = bus.read_i2c_block_data(0x44, 0x00, 6)
Nguyễn Tiến Hải – D17CQVT08B 50
# Convert the data
temp = data[0] * 256 + data[1]
cTemp = -45 + (175 * temp / 65535.0) fTemp = -49 + (315 * temp / 65535.0)
humidity = 100 * (data[3] * 256 + data[4]) / 65535.0 # Output data to screen
print "Temperature in Celsius is : %.2f C" %cTemp print "Temperature in Fahrenheit is : %.2f F" %fTemp print "Relative Humidity is : %.2f %%RH" %humidity
Hình 3. 19. Kết quả thu được từ cảm biến
3.3.1.2. Toàn bộ hệ thống
Kết nối toàn bộ hệ thống lại, ta được 1 hệ thống hồn chỉnh có Raspberry Pi điều khiển hệ thống đèn và mô-tơ cũng như nhận dữ liệu từ cảm biến
Nguyễn Tiến Hải – D17CQVT08B 51 Hình 3. 20. Hình ảnh thực tế của hệ thống
3.3.1.2. Kết nối với Server qua MQTT
Sau khi lấy được thông số từ cảm biến, ta sử dụng MQTT để gửi dữ liệu về cho người dùng.
Tin gửi đi được chia thành các chủ đề. Nếu ta muốn nhận tin về một chủ đề nhất định, ta cần MQTT Broker biết ta muốn đăng ký chủ đề này.
Mặt khác, nếu ta muốn tạo một tin cho một chủ đề cụ thể, ta trực tiếp gửi nó đến MQTT Broker.
Tại đây em sử dụng thư viện MQTT.js là một thư viện dành cho Node.js để có thể kết nối được với MQTT.
Trước hết ta cần kết nối với MQTT Broker:
transmitter.connect = function connect(cb) { const connectOptions = { port: config.mqtt.port, host: config.mqtt.broker, rejectUnauthorized: false, protocol: 'mqtts', username: config.mqtt.username, password: config.mqtt.password,
Nguyễn Tiến Hải – D17CQVT08B 52
};
log.info(`Trying to connect to the MQTT broker at ${config.mqtt.broker} on port ${config.mqtt.port}`);
transmitter.client = mqtt.connect(connectOptions); transmitter.client.on('connect', () => {
log.info(`Connected successfully to the MQTT broker at ${config.mqtt.broker} on port ${config.mqtt.port}`);
cb(); });
transmitter.client.on('error', (err) => { log.error(`An error occurred. ${err}`); });
};
MQTT Broker sẽ sử dụng username và password để xác thực người dùng. Thông số của cảm biến về nhiệt độ và độ ẩm sẽ được gửi lên bằng hàm ”publish” của thư viện mqtt.js. Chuyển đổi thông tin về dạng chuỗi bằng hàm JSON.stringify sau đó gửi lên như sau:
transmitter.send = function send(temperature, humidity, cb) { const message = { temperature, humidity, timeStamp: moment().unix(), }; transmitter.client.publish(“house/sensors”, JSON.stringify(message), (err) => { if (err) {
log.error(`An error occurred while trying to publish a message. Err: ${err}`);
} else {
log.debug('Successfully published message'); }
cb(err); });
};
Khi đó, hệ thống sẽ gửi đi một tin đến chủ đề “house/sensors”
Nguyễn Tiến Hải – D17CQVT08B 53 Tại đây, ta sử dụng thư viện Aedes, một thư viện dành cho Node.js tạo khung chính cho kết nối MQTT với các chức năng cơ bản và có thể phát triển thêm bằng cách sử dụng các tiện ích ngồi.
Để bắt đầu, ta khởi tạo Aedes và bắt đầu lắng nghe các gói tin MQTT tại các cổng đã được cài đặt:
broker.listen = function listen(cb) { broker.aedes = aedes();
const options = {
key: fs.readFileSync('./certificates/broker-private.pem'), cert: fs.readFileSync('./certificates/broker-public.pem'), };
broker.server = tls.createServer(options, broker.aedes.handle); log.info(`Starting MQTT broker on port:${config.mqtt.port}`); broker.server.listen(config.mqtt.port);
cb(); };
Tiếp theo, các máy khách cũng cần được xác thực bằng một tên đăng nhập và mật khẩu. Ta cần thiết lập xác thực cho Aedes như sau:
broker.setupAuthentication = function setupAuthentication() {
broker.aedes.authenticate = (client, username, password, cb) => { if (username && typeof username === 'string' && username === config.mqtt.username) {
if (password && typeof password === 'object' && password.toString() === config.mqtt.password) {
cb(null, true);
log.info(`Client: ${client} authenticated successfully`); } } else { cb(false, false); } }; };
Để nhận được gói tin về thơng số nhiệt độ và độ ẩm bên trên, ta cần đăng kí tại Server lắng nghe gói tin “house/sensors” như sau:
Nguyễn Tiến Hải – D17CQVT08B 54
receiver.client.on('connect', () => {
log.info(`Connected successfully to the MQTT broker at ${config.mqtt.broker} on port ${config.mqtt.port}`);
receiver.client.subscribe(config.mqtt.topic);
receiver.client.on('message', (topic, message) => { if (topic === config.mqtt.topic) { const parsedMessage = helper.parseJsonToObject(message.toString()); messageCallback(parsedMessage); } }); connectCallback(); });
Như vậy ta đã hồn thành việc nhận thơng số từ các gói tin được gửi lên. Tương tự với việc gửi và nhận các gói tin về thơng số cảm biến, server và hệ thống phần cứng cũng có thể trao đổi để kích hoạt các lệnh liên quan như bật tắt đèn, mở đóng cửa, rèm cửa,…
3.3.3. Cơ sở dữ liệu lưu trữ các thông số
Để lưu lại các thông số, thuận tiện cho việc kiểm tra, tại đây em sử dụng hệ thống cơ sở dữ liệu InfluxDB. Để tương tác với InfluxDB, em sử dụng thư viện node-influx dành cho Node.js và kết nối với cơ sở dữ liệu như sau:
storage.connect = function connect(cb) { storage.influx = new Influx.InfluxDB({ host: config.database.host, database: config.database.name, username: config.database.user, password: config.database.password, schema: [ { measurement: 'temperature', fields: { temperature: Influx.FieldType.FLOAT, }, tags: ['host'], }, ], });
Nguyễn Tiến Hải – D17CQVT08B 55 storage.influx.getDatabaseNames().then((names) => { if (!names.includes(config.database.name)) { return storage.influx.createDatabase(config.database.name); } return null; }).then(cb); };
Sau đó, ta lưu lại dữ liệu bằng hàm save :
storage.save = function save(message, cb) {
log.info(`Storing message: ${message.temperature} ${message.timeStamp}`); storage.influx.writePoints([ { measurement: 'sensors', fields: { temperature: message.temperature, humidity: message.humidity, }, timestamp: message.timeStamp, }, ]).then(cb); }; 3.3.4. Thiết kế ứng dụng Rsmart
Các tính năng sẽ được sử dụng trong ứng dụng Rsmart: - Đăng nhập
- Màn hình chính gồm thông tin thông số nhiệt độ, độ ẩm, cùng với bảng điều khiển đèn và rèm cửa
- Nhận diện lệnh bằng giọng nói
3.3.4.1. Tính năng đăng nhập:
Để đảm bảo tính bảo mật do người dùng, người dùng sẽ cần phải đăng nhập bằng tên đăng nhập và mật khẩu của mình. Hàm requestSignIn bên dưới giúp ứng dụng liên hệ với Server để đăng nhập:
async requestSignIn( username: string, password: string,
): Promise<{ jwt: string; user: User }> { return Axios.post(this.baseUrl, {
identifier: username, password,
})
Nguyễn Tiến Hải – D17CQVT08B 56
console.log(res.data)
Axios.defaults.headers.Authorization = `Bearer ${res.data.jwt}` return res.data }) .catch(err => { console.log(err) showMessage({ message: 'Error!',
description: 'No active account found with the given credentials!', type: 'danger', }) return null }) }
Phần giao diện của màn hình đăng nhập:
<Box flex={1} alignItems="center" justifyContent="center"> <Image source={images.LOGO} style={{ width: WIDTH(30), height: WIDTH(30), borderRadius: WIDTH(15), }} />
<Box marginTop={15} alignItems="center"> <Text bold h1>
Welcome back </Text>
<Input
label="Username"
icon={{ pack: 'Ionicons', name: 'person' }}
containerStyle={{ width: WIDTH(90), marginTop: 20 }} />
<Input
label="Password"
icon={{ pack: 'Ionicons', name: 'key' }}
containerStyle={{ width: WIDTH(90), marginTop: 20 }} /> <Button text="Login" color="#091826" containerStyle={{ marginTop: 20 }} /> </Box>
Nguyễn Tiến Hải – D17CQVT08B 57 Hình 3. 21. Màn hình đăng nhập của ứng dụng
3.3.4.2. Màn hình chính của ứng dụng
Màn hình chính sẽ bao gồm 2 phần: Thông số cơ bản và bảng điều khiển cho các phịng
Đối với thơng số cơ bản, ta sẽ sử dụng các thông số được Server trả về bằng thư viện Axios, hoạt động trên React Native và phục vụ gửi, xử lý Restful API.
Hàm getOverview dưới đây phục vụ việc lấy các thông số cơ bản từ cảm biến tại Server:
async getOverview(): Promise<SensorData[]> { return Axios.get(this.baseURL + 'sensors') .then(res => { console.log(res.data) return res.data }) .catch(err => { console.log(err) showMessage({ message: 'Error!',
description: 'Check your Internet Connection!', type: 'danger',
}) }) }
Nguyễn Tiến Hải – D17CQVT08B 58 Phần giao diện của thông số cơ bản:
<Box horizontal marginTop={15}> <Box flex={1} card color="#091826" alignItems="center" justifyContent="center" padding={20} borderRadius={20} marginHorizontal={10}> <Text>
<Text bold style={{ fontSize: 35, lineHeight: 40 }}> {sensorsData.temperature} ° </Text> <Text bold h1> C </Text> </Text> <Text h3>Temperature</Text> </Box> <Box flex={1} card color="#091826" alignItems="center" justifyContent="center" padding={20} borderRadius={20} marginHorizontal={10}> <Text>
<Text bold style={{ fontSize: 35, lineHeight: 40 }}> {sensorsData.humidity} </Text> <Text bold h1> % </Text> </Text> <Text h3>Humidity</Text> </Box> </Box>
Đối với phần bảng điều khiển, người dùng có thể thao tác bật tắt các thiết bị mong muốn chỉ bằng một lần chạm.
Nguyễn Tiến Hải – D17CQVT08B 59 Hình 3. 22. Màn hình chính của ứng dụng
3.3.4.3. Tính năng nhận diện lệnh bằng giọng nói
Ở màn hình chính, ta có một nút microphone, khi ấn vào nút này sẽ kích hoạt chế độ nhận diện bằng giọng nói. Khi đó, người dùng có thể ra lệnh cho ứng dụng bật tắt các thiết bị trong nhà bằng giọng nói. Tại đây em sử dụng thư viện nhận diện giọng nói react-native-voice của React Native để hỗ trợ nhận diện giọng nói. Thư viện này sẽ sử dụng bộ chuyển đổi giọng nói thành văn bản có sẵn của hệ điều hành. Sử dụng hàm onSpeechResults để nhận được dữ liệu sau khi chuyển đổi thành ký tự.
onSpeechResults = (e: SpeechResultsEvent) => { console.log('onSpeechResults: ', e.value); this.setState({
results: e.value, });
Nguyễn Tiến Hải – D17CQVT08B 60 Hình 3. 23. Giao diện nhận diện giọng nói của ứng dụng
Ví dụ khi ta muốn ra lệnh tắt đèn 1 tại phịng khách, ta có thể nói: “ Turn off light one in living room”
Sau khi nhận diện giọng nói, sẽ cho ra kết quả là một mảng ký tự như sau: [ “Turn”, “off”, “light”, “one”, “in”, “living”, “room” ]
Kết quả này sẽ được ứng dụng gửi lên server để xử lý và đưa ra lệnh phù hợp với yêu cầu của người dùng. Tại đây, server xử lý mảng ký tự trên bằng cách kiểm tra xem nó có chứa các từ khóa chính và đưa ra lệnh phù hợp với yêu cầu của người dùng.
Nguyễn Tiến Hải – D17CQVT08B 61 Hình 3. 24: Tổng quan hệ thống xử lý lệnh tại Server
Để bắt đầu, hệ thống sẽ kiểm tra dữ liệu đầu vào bằng 4 bộ từ cho sẵn
Nguyễn Tiến Hải – D17CQVT08B 62 Tại đây sẽ có 4 bộ từ được kiểm tra, hệ thống sẽ kiểm tra chính xác phải có duy nhất 1 từ trong một bộ từ được sử dụng trong câu lệnh. Nếu sai, hệ thống ngay lập tức trả về phản hồi lỗi thực hiện câu lệnh. Nếu đúng, hệ thống sẽ tiến đến phân tích câu lệnh. Tại đây, có 4 bộ từ, mỗi bộ 2 từ sẽ tương ứng với 16 trường hợp xảy ra.
Hình 3. 26. Các trường hợp xảy ra khi hệ thống xử lý đèn
Ví dụ với mảng ký tự bên trên, hệ thống sẽ kiểm tra và nhận thấy xuất hiện các từ khóa như “off”, “light”, “one”, “living”, rồi đưa ra kết quả cần thực hiện hành động tắt đèn 1 tại phòng khách. Hệ thống sẽ gửi tới Raspberry Pi 1 gói tin MQTT với chủ đề house/living/light, nội dung sẽ gồm có: “index: 1” chỉ đèn số 1, “status”: false thể hiện cần tắt đèn.
Nguyễn Tiến Hải – D17CQVT08B 63 Hình 3. 27. Luồng xử lý tại Raspberry Pi
Sau khi gửi thơng tin tới Raspberry Pi, nó sẽ tiếp nhận, xử lý và trả về gói tin MQTT tương ứng với trạng thái của hành động. /house/action/success cho trạng thái thành công và /house/action/failed cho trạng thái thất bại. Cuối cùng tại Server sau khi nhận được trạng thái thành công hoặc thất bại tại Raspberry Pi sẽ gửi lại thông tin cho ứng dụng thông báo kết quả của hành động.
Log từ server khi xử lý hành động:
[LOG] onReceiveCommand [“off”, “light”, “one”, “living”] [LOG] Command approved
[LOG] Sending /house/living/light [LOG] /house/action/success triggered
[LOG] Sending response and close connection
Nguyễn Tiến Hải – D17CQVT08B 64 Hình 3. 28. Kết quả sau khi nhận diện giọng nói và thực hiện lệnh
3.4. KẾT LUẬN CHƯƠNG
Chương này đã trình bày được thực nghiệm về hệ thống IoT cơ bản điều khiển nhà thơng minh, có áp dụng cơng nghệ nhận diện, chuyển đổi giọng nói thành văn bản trong ứng dụng di động. Qua đó có thể hình dung một cách cụ thể về một hệ thống IoT, nhà thông minh cơ bản nhất.
Nguyễn Tiến Hải – D17CQVT08B 65
KẾT LUẬN
IoT, nhà thông minh và trí tuệ nhân tạo đều là những xu hướng của thế giới hiện nay. Đồ án cũng đã chỉ ra được những đặc điểm của các cơng nghệ này cũng như trình bày một hệ thống thực nghiệm để dễ hình dung hơn về một hệ thống nhà thơng minh cơ bản.
Trong thời gian tới, để đồ án có thể phát triển hơn, em dự định phát triển hệ thống nhận diện giọng nói, nhận diện câu lệnh áp dụng các cơng nghệ về trợ lý ảo mới như Google Assistant. Từ đó giúp việc nhận dạng, xử lý giọng nói và ra lệnh cho hệ thống trở nên đơn giản hơn, thông minh hơn.
Nguyễn Tiến Hải – D17CQVT08B 66
DANH MỤC TÀI LIỆU THAM KHẢO
[1] Samuel Greengard; The Internet of Things; March 20, 2015.
[2] Adam Juniper; The Smart Smart Home Handbook: Control Your Home With Your
Voice; November 6, 2018.
[3] Steven Goodwin; Smart Home Automation with Linux and Raspberry Pi; June 10,
2013
[4] Dong Yu, Automatic Speech Recognition: A Deep Learning Approach (Signals and
Communication Technology), 2015th edition (November 28, 2014);
[5] Vishal Passricha, Rajesh Aggarwal; Convolutional Neural Networks for Raw
KẾT QUẢ KIỂM TRA TRÙNG LẶP TÀI LIỆU
THÔNG TIN TÀI LIỆU
Tác giả Nguyễn Tiến Hải
Tên tài liệu Đồ án - Nguyễn Tiến Hải - B17DCVT112
Thời gian kiểm tra 24-12-2021, 04:56:29
Thời gian tạo báo cáo 24-12-2021, 04:58:20
KẾT QUẢ KIỂM TRA TRÙNG LẶP
Điểm 8
Nguồn trùng lặp tiêu biểu [text.123doc.org, 123doc.org, viblo.asia]