Sirui Wang(sw2232) and Yuchen Cai(yc2563)
ECE5725 Final Project
In modern days, the shipment and delivery service industry has grown up rapidly. The number of sales, especially online, is amazing and still increasing every year. But sometimes, the delivery courier meets trouble to carry packages in some rural areas and needs a portable device that can both check and manage the order lists. This project aims to provide a delivery management system for both the customers and couriers in which the customers place their delivery orders and the couriers use a raspberry pi to check and manage the current orders as well as interact with the incoming user orders in real-time. The high-level idea is to design a web application for the user so that they can place their orders together with the details and wait for the courier to collect their items. The server is hosted on a Raspberry Pi solely and runs in parallel with the user interface program, which allows the courier to manage orders. Finally, we have implemented a fully functional multiprocessing delivery system with a portable, flexible and efficient service. A general system design diagram is given in Figure.1.
The design of the front-end website is shown in Figure.3. As shown in the figure, there is a black logo portraying a delivery man in the top. Below that logo, there is a text of ‘Welcome to Delivery’ in a Tangerine style. This style is implemented by using Google font API which is a free and simple API. To add Tangerine style to the text, the user should add a style tag in the HTML file with a proper CSS selector to claim the font family and font size of the text.
When the user fills the boxes of the six items and clicks the register, an HTTP request will be sent. Then the server is waiting for a response and the website page will display a pop-up window telling that ‘Please wait for confirmation’ and keeps waiting until the courier makes reactions. If the courier accepts the incoming order, the website pop-up window will display a new text of ‘Your order has been accepted’. If the courier declines the order, the website pop-up window will display a new text of ‘Your order has been rejected’.
The RaspberryPi owns a Linux kernel which is the most common operating system on embedded machines. In this project, Django is used, which is a free and open-source web application framework using python . For the database, the open-source relational database PostgreSQL is used instead of SQLite3, which is an embedded database in Django. When the request comes, Django will extract useful information from the request and invoke a request on the courier user interface so that the request can be either accepted or rejected. If the order is accepted, the server will save the order to the database and return a message to the front-end.
2. Django and PostgreSQL Setup
Before installing PostgreSQL and Django, python3 and pip3 are required as a prerequisite. virtualenv is an optional choice, which creates a virtual environment that separates from the system environment. The packages installed in the virtual environment will be invisible to the outside world.
Under Debian Buster, the PostgreSQL can be installed using this command:
apt-get install postgresql-11
After installation, we can create a superuser and run the database on the localhost at port 5432. The second thing is to install a library named psycopg2, which allows python to access the database:
pip3 install psycopg2
These links  are helpful to create users and databases using postgresql. A graphical tool called pgAdmin III can be installed to visualize the database. The database after configuration should look like which is shown in Figure.5.
To install Django systemwide, use this command:
pip3 install Django
Once it is successfully installed, you should be able to see the Django version using:
python3 -m django --version
This command will start a new project:
django-admin startproject deliveree
If it shows “command not found:django-admin”, this page might be helpful. The issue may be because django-admin has not been added to the system path. This can be fixed by symlinking django-admin in Your_python_path/site-packages/django/bin/ folder to /usr/local/bin. If this does not fix the problem, just use the absolute path to run this command:
Your_python_path/site-packages/django/bin/django-admin startproject deliveree
Once this is finished there will be a folder including setting files for the server. Then you can create an app that actually runs the services using:
python3 manage.py startapp deliveree
This will create another folder. In this folder, models.py defines the schema of the database. For example, for User Table, there are fields like name, contact, address, order status, latitude, longitude etc. In order to connect Django with postgresql, the path, name, password need to be specified in setting.py. After connection, whenever the model changes, the database will change accordingly. To apply these setting and database model, use these commands:
python3 manage.py makemigrations
python3 manage.py migrate
3. Handle Requests
View.py is the actual file that handles all requests according to different end-points. As mentioned, the front-end request is sent through ajax, which does not require refreshing the whole page. The requested data is wrapped in a json file and encoded using utf-8. When the submit button is pressed, it will send the data to the “/submit” end point through POST method, which matches the form() function in view.py. There is one issue when dealing with POST requests. Django keeps showing an error at first: Forbidden (403) CSRF verification failed. Request aborted. The issue is that CSRF token is missing. But the token is not actually needed in this application, so this error can be avoided by simply putting a @csrf_exempt before the function which handles the request. Afterward, all fields in json can be decoded accordingly. Notice that the foreground also sends the latitude and longitude of the user. Before saving them into DB, the distance between the courier and the customer will be calculated and put into DB as well for sorting purposes.
4. Communication between processes
The server can be launched using this command:
python3 manage.py runserver &
This will allow the server to run in the background, so that it can make some space for the user-interface in the foreground. Now comes the tricky part. Since the foreground and the background are two separate processes, how can the courier in the foreground know a new order has arrived? One naive option is to add the order to the database before asking for the courier’s permission, and make the courier query the number of items in the DB in a polling loop. When the number of items changes, it means a new order has come. However, this method will make the database and system vulnerable to attacks, since anyone can add an arbitrary number of items to the database until it crashes. This is also inefficient since the item would have to be deleted if it is rejected by the courier, which could have been avoided.
Another solution is to use communication between two processes, so that whenever a request arrives, the background server will invoke some form of interrupt on the courier’s UI. The first idea is to use a signal function, which maps a user-defined signal to a signal handler. When the server receives a request, it finds the pid of the foreground process which runs UI, and sends a signal to it. Then the UI will bring up a page asking the courier to confirm the new order. However, the signal function doesn’t work on Django because the function in view.py doesn't run in the main thread. A second choice is to use a FIFO file. Whenever a new request comes, it writes the contents into the file. Meanwhile the foreground UI keeps polling the file and reads the content when it is not empty. However, the issue is that the fifo file doesn’t clear its contents after being read during the test, which makes it hard to tell whether it is a new order or an old order.
In the end, TCP is used for communication between the two processes. The server binds to a specific local port when the request arrives and waits for the UI process to respond. The UI process keeps polling for the port until it finds it is bound. Then a connection between two processes sets up. The server will then send the information of the order to the UI process. Since TCP usually sends string in binary form, a module that can encode and decode data structures like list or dictionary can be helpful. Here the module named pickle is installed:
pip3 install pickle
And it can encode and decode the message using methods like pickle.dumps(message) and pickle.loads(data).
In order to make the server accessible to users in the public, the server should be run with this command:
python3 manage.py runserver 0.0.0.0:8000
This allows other users to access the website using the IP address of the raspberry pi. The setting.py will also need to be changed. Another option is to configure the network using Nginx and wsgi, which allows the website to be public.
In this project, a 320x240 piTFT designed by Adafruit owning a touchscreen is used as the display terminal for the courier. To achieve visualization and a graphic user interface, a python libraries PyGame is used. In order for better code maintenance and debugging, we use object-oriented programming and create one class for each page. There are home.py, order.py, item.py, confirm.py which correspond to different pages.
First of all, a welcoming page shows up when the system is booted. Figure.x demonstrates the view of the home page. Then the order list page will show up. The order list will contain the items saved in the database whose status is “false”, which means it has not yet been completed. Generally this is implemented by firstly querying the entire database and then sorting all the items by date, time and geo-location with a descending priority. Then four items will be drawn at a time on the page. For the next page, it will draw the next four items.
There are four physical buttons on piTFT, which were set to be GPIO input for the system with pull up resistors. These buttons can be used to move the cursor and select one of the items to enter the item page. On the item page, the details will be displayed. The courier can finish the order (update the status field to “True”) or cancel the order (delete the item from DB). When the back button is selected and it switches to the order page, the order page will reload the database and update the list.
Another important feature as mentioned earlier is to display the new order in real-time. In the main loop, the program basically does two tasks: draw UI and detect TCP connection. When a TCP connection is successful, it will call the confirm page, which shows the order detail. When the Accept/Reject button is hit, it will send back a message to the server through TCP. The server will then respond to the front-end accordingly.
To see the system performance, a load test was carried out using Apache Jmeter to see how many requests the system can handle every second. It can be seen from the table that when there are 300 threads(user) the maximum throughput for the system is about 37.6 query per second (qps).
In the end, we put these two lines in the .bashrc file so that the service runs automatically when the system is booted:
python3 manage.py runserver 0.0.0.0:8000 &
Generally, we did better than expected and added many features to the system. In the first two weeks, we worked on the front-end and configured some basic settings on Django. In the third week, we finished the interfaces between front-end and Django and postgresql. In the last two weeks, we finished the courier UI pages as well as the communication. We also added features like geolocation-based sorting in the end. A video of our project is shown below.
At the end of this project, our team successfully built an end-to-end delivery management system on Raspberry Pi as well as a user-interface on piTFT. Any user can place a delivery order and get a response from the web application. The courier can manage orders saved in DB on piTFT screen and respond to new orders accordingly. This server is portable and can be carried with easily. Whenever it is powered, the server will be working. We also applied a load test in the end and found that the Raspberry has the maximum throughput of 37.6 qps when there are 300 threads.
If time permits, some new features could be added into this delivery management system. First of all, it is possible to create an authentication system where the user can sign in to their own accounts on the website, and see the current status of their historical orders. Secondly, as shown in the Results section, the maximum throughput of the website is around 300 threads(users). Therefore the bottleneck of the system is the number of couriers, since each order has to be processed by the number of courier. We might think about the way to scale up the system and improve its capacity to handle more user requests.
Raspberry Pi 3 $35
piTFT screen $35
SD card $5.8
Wijesinghe, M. (2019). What happens when you type an URL in the browser and press enter?. [online] Medium. Available at: https://email@example.com/what-happens-when-you-type-an-url-in-the-browser-and-press-enter-bb0aa2449c1a [Accessed 12 Dec. 2019].
Docs.djangoproject.com. (2019). Templates | Django documentation | Django. [online] Available at: https://docs.djangoproject.com/en/2.2/topics/templates/ [Accessed 12 Dec. 2019].
Google Fonts. (2019). Google Fonts. [online] Available at: https://fonts.google.com/specimen/Tangerine [Accessed 12 Dec. 2019].
Youtube.com. (2019). YouTube. [online] Available at: https://www.youtube.com/watch?v=Axh8rNKgvmk&list=PLzXscUBmhxmpv6k3WMp7A0sYoZsSG_FB1&index=2 [Accessed 12 Dec. 2019].
Youtube.com. (2019). YouTube. [online] Available at: https://www.youtube.com/watch?v=_qUpvRTqK0Y [Accessed 12 Dec. 2019].
The image for the background is credited to this source
The codes of our project can be found in here