使用物理设备与IOTA系统集成-汽车物联网第1部分

这是一系列初学者教程,我们将探讨如何将物理设备与IOTA协议集成。这一次,我们将着眼于使用物联网协议简化和自动化典型的汽车相关服务的支付,如停车、收费公路、洗车等。
我决定将此教程分为两部分,因为我认为有多种方法可以解决此用例。每种都有自己的优点和缺点。
在第一个教程中,我们将尝试使用一种通常称为自动车牌识别(Automatic License Plate Recognition,简称ALPR)的技术来解决这个用例。
实践用例
在我们酒店的后面有一个停车场,供酒店客人和员工使用。最近在未支付所需停车费的情况下,使用停车设施的授权人员和未授权人员都出现了问题。我们酒店业主认为,这与目前的人工操作和复杂的停车费处理流程有关。如果有一个自动化系统,可以在不打扰客人或工作人员的情况下收取停车费就好了。
本教程中提出的解决方案基于以下想法:酒店所有者发行IOTA代币并为其客人和员工管理SEEDS。在之前的指南中讨论了这个想法,我们在酒店为各种服务付费时考虑使用RFID技术。
组成部分

在开始研究该项目的编码之前,我们应该退后一步,研究一下总体概念和所使用的各种组件。

使用物理设备与IOTA系统集成-汽车物联网第1部分

在上面,您将看到本教程中提议的用于解决用例的各种组件的简单布局。在继续学习代码之前,让我们一一刹车。
超声波传感器
超声波传感器用于检测车辆何时进入或离开停车场。 超声波传感器通过产生和接收声音脉冲来测量距离。 因此,它基本上只是一个扬声器和麦克风,并将一些其他电子设备组合在一起。 通过测量从扬声器发出脉冲到麦克风接收到脉冲之间的时间,我们可以计算出反射的物体(在这种情况下为车辆)的距离(我们知道声速) 脉冲。
我用于该项目的超声波传感器是流行的HC-SR04。 您应该能够在ebay上获得其中的几美元。

使用物理设备与IOTA系统集成-汽车物联网第1部分

使用以下电路图将HC-SR04连接到Raspberry PI。

使用物理设备与IOTA系统集成-汽车物联网第1部分

注意电路中的两个电阻。 电阻用于降低HC-SR04的5V输出引脚到PI上的3.5 V输入引脚的电压。电路中没有电压电阻器可能会损坏您的Raspberry PI。
当然,您可以使用多种技术来检测车辆何时进入或离开停车场。我为此项目使用超声波传感器的唯一原因是,我已经在上一个项目中放置了一个超声波传感器。
请注意,传感器产生的声音脉冲处于人耳无法检测到的频率范围内,因此当传感器处于活动状态时,您将听不到任何声音。
照相机
摄像机用于进入车位区域时对车牌进行拍照。我正在为此项目使用Raspberry PI摄像头模块V2,但您基本上可以使用任何可以通过Python脚本控制的摄像头。 您应该可以从eBay或从当地的PI商店购买此相机模块。

使用物理设备与IOTA系统集成-汽车物联网第1部分

OpenALPR
OpenALPR是一种自动车牌识别(ALPR)软件,用于从图片或图像中识别车牌号。您可以选择在内部安装OpenALPR SDK,也可以使用那里的云服务执行ALPR。在本教程中,我们将使用云服务。 请注意OpenALPR是许可软件,但您可以注册一个免费帐户,该帐户每月最多可免费执行1000次ALPR。
要注册免费的OpenALPR帐户,请访问https://www.openalpr.com/
登录OpenALPR后,选择Cloud API
在Cloud API页面上,您会找到一个秘密密钥,该秘密密钥会将图像上传到OpenALPR云服务时将在我们的python脚本中使用。

使用物理设备与IOTA系统集成-汽车物联网第1部分

The Plate/SEED DB
“Plate/SEED数据库”是对某种类型的集中式存储的引用,其中每个车牌号均与将用作IOTA价值交易的发送方的IOTA SEED配对。 在本教程中,我将使用一个简单的逗号分隔的文本文件(或CSV)文件,该文件存储在Raspberry PI的本地文件中。 但是,在任何以安全性为重中之重的现实生活中,SEED都应存储在访问受限的某种加密数据库中。
汽车
我们还需要一些代表汽车本身的对象。 从本教程的图像中可以看到,我正在使用在附近跳蚤市场上发现的玩具车。 对于构建和测试,您只需要一个简单的盒子,盒子的一侧印有牌照,如下所示。 甚至更低的温度,使用真实的汽车和车牌在预期的环境中设置系统。

使用物理设备与IOTA系统集成-汽车物联网第1部分

确保在车牌号周围画一个边框,如上所示。 否则,OpenALPR算法将无法识别车牌在图片中的位置。
怎么运行的
在查看这个项目的Python代码之前,让我们一步一步地查看当一辆新车进入酒店停车场时发生的事件。
1. 一辆新车进入酒店停车场,挡住了超声波传感器。
2. 摄像头拍下了汽车牌照区域的照片。
3. 图片被上传到OpenALPR Cloud服务,该服务以json对象的形式返回标识的车牌号。
4. 在搜索Plate / SEED DB进行匹配之前,我们将车牌号从json对象转换为字符串。
5. 如果找到匹配项,则使用返回的SEED作为交易的发送者,在将有价交易发送到纠结之前,我们将返回相关的IOTA SEED。
以供参考:
这是当汽车进入停车场并阻挡超声传感器时从PI摄像机拍摄的照片。

使用物理设备与IOTA系统集成-汽车物联网第1部分

这是OpenALPR解码的图片

使用物理设备与IOTA系统集成-汽车物联网第1部分

请注意,OpenALPR未将开头的两个T识别为车牌号的一部分。 这可能与这是一辆没有有效车牌号语法的玩具车有关。 我使用实际车牌号进行的其他测试似乎运行良好。
所需软件和库
在开始为这个项目编写Python代码之前,我们需要确保在Raspberry PI上安装了所有必需的软件和库。对于本教程,除了PyOTA本身之外,还需要以下库:
PiCamera库(已与Raspbian一起安装)
请求(pip安装请求)
Python代码
这是这个项目的python代码。。
# Imports some required PyOTA libraries
import iota
from iota import Address
# Imports some libraries required by OpenALPR communication
import requests
import base64
import json
# Imports the CSV library used for DB comm. 
import csv
# Import PiCamera library
from picamera import PiCamera
# Setup the camera
camera = PiCamera()
# Rotate the image so that the lisence plate is placed horizontaly within the picture
# Depends on how you monted the camera
camera.rotation = 270
# Import the GPIO library
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
# URL to IOTA fullnode used when interacting with the Tangle
iotaNode = “https://nodes.thetangle.org:443”
# Hotel owner recieving address, replace with your own recieving address
hotel_address = b’GTZUHQSPRAQCTSQBZEEMLZPQUPAA9LPLGWCKFNEVKBINXEXZRACVKKKCYPWPKH9AWLGJHPLOZZOYTALAWOVSIJIYVZ’
# Price of the parking service (10 IOTA)
price = 10
# Specify GPIO pins used by ultrasonic sensor
TRIG = 23 
ECHO = 24
# Variable used for monitoring when car enters/exits the sensor area
car_found = False
print “Distance Measurement In Progress”
# Setup the GPIO pins
GPIO.setup(TRIG,GPIO.OUT)
GPIO.setup(ECHO,GPIO.IN)
# Function for capturing image using the Raspberry PI camera
def capture_image():
    image_file = “/home/pi/Desktop/image.jpg”
    print(“Capturing image…”)
    camera.start_preview()
    time.sleep(1)
    camera.capture(image_file)
    camera.stop_preview()
    get_plate_id(image_file)
# Function for getting the plate ID from image using the OpenALPR Cloud API service 
def get_plate_id(image_file):
    # Replace with your OpenALPR secret key
    SECRET_KEY = ‘PutYourOpenALPRSecretKeyHere’
    with open(image_file, ‘rb’) as image_file:
        img_base64 = base64.b64encode(image_file.read())
    # Send image to the OpenALPR Cloud service for decoding
    url = ‘https://api.openalpr.com/v2/recognize_bytes?recognize_vehicle=1&country=us&secret_key=%s’ % (SECRET_KEY)
    r = requests.post(url, data = img_base64)
    # Convert returned json to string 
    r_str = json.loads(json.dumps(r.json(), indent=2))
    # Search the Plate/SEED DB for a matching lisence plate
    # If found, get the related SEED
    try:
        if ‘plate’ in r_str[‘results’][0]:
            plate_id = r_str[‘results’][0][‘plate’]
            print(plate_id)
            get_seed(plate_id)
    except:
        print(‘OpenALPR did not return a plate ID’)       
# Function for getting the seed used for IOTA payment
def get_seed(plate_id):
    plate_found = False
    with open(‘plates.csv’) as csv_file:
        csv_reader = csv.reader(csv_file, delimiter=’,’)
        for row in csv_reader:
            if row[0] == plate_id:
                seed=row[1]
                plate_found = True
    if plate_found == True:
        print(“Plate was found in DB, seed: ” + seed)
        send_transaction(hotel_address, price, plate_id, seed)
    else:
        print(“Plate was not found in DB”)
# Function for sending the IOTA value transaction
def send_transaction(hotel_address, price, plate_id, seed):
    # Define api object
    api = iota.Iota(iotaNode, seed=seed)
    # Create transaction object
    tx1 = iota.ProposedTransaction( address = iota.Address(hotel_address), message = None, tag = iota.Tag(iota.TryteString.from_unicode(plate_id)), value = price)
    # Send transaction to tangle
    print(“\nSending transaction… Please wait…”)
    SentBundle = api.send_transfer(depth=3,transfers=[tx1], inputs=None, change_address=None, min_weight_magnitude=14)       
    # Display transaction sent confirmation message
    print(“\nTransaction sent…”)

# Check (every 2 sec.) for new cars entering or exiting the parking lot..
try:
    while True:
        GPIO.output(TRIG, False)
        print “Waiting For Sensor To Settle”
        time.sleep(2)
        GPIO.output(TRIG, True)
        time.sleep(0.00001)
        GPIO.output(TRIG, False)
        while GPIO.input(ECHO)==0:
          pulse_start = time.time()
        while GPIO.input(ECHO)==1:
          pulse_end = time.time()
        pulse_duration = pulse_end – pulse_start
        # Convert distance to cm
        distance = pulse_duration * 17150
        distance = round(distance, 2)
        # If distance between sensor and car is less than 10 cm
        if distance < 10:
            if car_found == False:
                capture_image()
                car_found = True
        else:
            car_found = False
except KeyboardInterrupt: # If there is a KeyboardInterrupt (when you press ctrl+c), exit the program and cleanup
    print(“Cleaning up!”)
    GPIO.cleanup()
现在,您应该看到python脚本开始每2秒检查一次传入的汽车。使用超声波传感器。当发现新车时,我们将按照“工作原理”一章中的说明启动序列。随着序列的进行,检查树莓终端的状态。
注意!
在现实生活中,您可能需要某种类型的指示器来告诉车主是否以及何时接受(或不接受)交易/付款。这可以通过将指示灯从红色切换为绿色来完成,甚至可以移除物理屏障。
在我的示例中,当新车进入停车场时,Raspberry PI完成了有关创建和签署所需IOTA价值交易的所有工作。您很快就会注意到,由于PI的资源有限,这是一个相当缓慢的过程。在现实生活中,这可能是不可接受的,我们必须寻找其他选择。一种选择是将这些活动外包给具有有效执行这些活动资源的集中式实体。
下一步是什么?
尽管本教程中提出的解决方案可能适用于某些本地用例。对于其他用例,控制SEEDS的集中实体(在这种情况下为酒店所有者)的概念将不切实际或不可接受。对于真正的全球性和分散式解决方案,我们可能需要采用其他方法,下次再说。