Sei sulla pagina 1di 43

Universitatea Politehnica Timisoara

Timisoara, Spring 2019

BikeSide
Rear traffic live streaming and transitory anti-theft bicycle system

Filip Ioan Leonard


Supervisor: prof. Razvan Bogdan

Bachelor thesis, Computer and Information Technology


Major: Computer Science

UNIVERSITATEA POLITEHNICA TIMISOARA


Contents i

Contents
1 Problem Statement 1
1.1 Context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Blind side . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Pit stop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2 Status Quo 5
2.1 Rear Camera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Bike Alarm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

3 Solution Description 7

4 Technologies Used 8
4.1 Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.1.1 Requirements and Constraints . . . . . . . . . . . . . . . . . . . . 8
4.1.2 Raspberry Pi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.1.3 MPU6500 Accelerometer . . . . . . . . . . . . . . . . . . . . . . . 10
4.1.4 Raspberry Pi Camera V2 . . . . . . . . . . . . . . . . . . . . . . . 12
4.2 Software and Technologies . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4.2.1 Development Tools . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.2.2 Multithreading . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.2.3 TCP Protocol and Sockets . . . . . . . . . . . . . . . . . . . . . . 15
4.2.4 JSch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4.2.5 Notify.run . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.2.6 Raspivid and netcat . . . . . . . . . . . . . . . . . . . . . . . . . 16

5 Development and Implementation 18


5.1 BikeSide Android Application . . . . . . . . . . . . . . . . . . . . . . . . 18
5.1.1 MainActivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
5.1.2 VideoActivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
5.1.3 VideoFragment . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
5.2 Raspberry Pi Python Script . . . . . . . . . . . . . . . . . . . . . . . . . 29

6 User Guide 32

7 Conclusion 35

References 38

Appendices 39
ii List of Figures

List of Figures
1.1 Map of bicycle lanes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Road-to-sidewalk transition margins . . . . . . . . . . . . . . . . . . . . 2
1.3 The rear traffic check-up move . . . . . . . . . . . . . . . . . . . . . . . 4
2.1 Rear bicycle cameras and alarms . . . . . . . . . . . . . . . . . . . . . . 6
4.1 Raspberry Pi 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.2 MPU6500 3-axis Accelerometer and Gyroscope . . . . . . . . . . . . . . . 11
4.3 Raspberry Pi Camera V2 . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
5.1 System components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
5.2 BikeSide UML Diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
5.3 MainActivity layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
5.4 MediaCodec [6] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
6.1 BikeSide rear camera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
(a) Close-up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
(b) Side angle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
6.2 Main Activity - Live Streaming . . . . . . . . . . . . . . . . . . . . . . . 33
(a) Set camera parameters . . . . . . . . . . . . . . . . . . . . . . . . 33
(b) Connect and start the stream . . . . . . . . . . . . . . . . . . . . 33
6.3 Main Activity - Locking . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
(a) Check Edit switch . . . . . . . . . . . . . . . . . . . . . . . . . . 34
(b) Notification example . . . . . . . . . . . . . . . . . . . . . . . . . 34
7.1 BikeSide sideview [6] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
1

1 Problem Statement

1.1 Context

Timisoara, Romania. The happy days of light traffic and clear sidewalks are long forgotten
in this city. While the number of vehicles on the streets dramatically increased over the
last years, the amount of parking spots and bicycle lanes has largely remained the same.
Sidewalks have become more crowded and very often illegally parked vehicles transform
them into narrow bottlenecks. With almost 90 lanes that add up to roughly 110 km in
length and cover less than a quarter of the streets [2], Timisoara’s bicycle lane system
is a large, sparse and strongly disconnected graph, Figure 1.1 [14]. Moreover, the law
states that cyclists cannot use the sidewalk unless there exists a bike lane [15]. As a direct
consequence of all previously mentioned, a regular bicycle commuter has to constantly
switch between riding on the sidewalk lanes along with the pedestrians and riding on the
first car lane along with other vehicles.

Figure 1.1: Map of bicycle lanes


2 1.1 Context

To put things into perspective, for a final year student working a full-time job and having
to attend to midday labs and lectures, a regular weekday can become very busy. Take the
following schedule example: a laboratory class at 8AM, a lecture at 12PM and another
laboratory at 4PM. Since the student has to also attend work and be productive in
between these events, he always leaves from the office 10-15 minutes, at most, prior to
the beginning of the class. To cope with this alert rhythm and avoid the unpredictable
traffic, the student uses the bike intensely for all the trips, and more. Moreover, in order
to streamline his riding experience and be more efficient, he mostly uses the first car lane.
By avoiding the sidewalks, a lot less breaking is required and the average riding speed
highly increases. As a side note, the transition between the road and the sidewalk is sharp
and bumpy in most of the crossings, see Figure 1.2. Imagine meeting car speed bumps at
every intersection.

Figure 1.2: Road-to-sidewalk transition margins

Long story short, whether he is riding to or from classes, work, home or any other place,
1.2 Blind side 3

rush hour or midnight, year-round, the student is almost always cautiously and relentlessly
rushing on the first car lane.

1.2 Blind side

One of the greatest concerns of all road cyclists and, in particular, of the student is
the incoming rear traffic. Although, generally, drivers maintain a safe distance while
passing by, a natural instinct of preservation kicks in and the pedaling student reassures
himself by shortly straightening his back and rotating his head over the left shoulder
until the rear traffic is fully observable, see Figure 1.3. This move takes about one second
during which the student is completely unaware of what is happening in front of him.
It is negligible as an individual event but as he constantly and very often performs this
move, the risk of accidents increases. A car backing up from a parking spot, a pedestrian
jumping in front, the loss of balance and so on, all of these accident generating events can
happen during that blind second. Moreover, as the head and, partially, the body rotate
left-wards, it often happens that the bicycle steers left out of inertia and dangerously
approaches a moving car coming from behind.
4 1.3 Pit stop

Figure 1.3: The rear traffic check-up move

1.3 Pit stop

The safety of his bicycle is another big concern for the student. He often deals with
situations in which he has to leave his bike unattended for a couple of minutes such as: a
quick trip inside the grocery store, a quick return inside the house or just a short fast-food
break. Most of the times, the bicycle is left unlocked due to the lack of locking stands or
just out of convenience, highly increasing the risk of it being stolen.
5

2 Status Quo
An online search and analysis revealed a good amount of rear traffic live streaming or
antitheft devices. Although having extra features, none of the rear cameras offer antitheft
alarm or movement notifications and the bike alarms are just bike alarms. Moreover, on
a closer look, only some of them have gone into mass production and are available for
purchase.

2.1 Rear Camera

When considering the device used to display the live image, rear bicycle camera systems
come in two categories: only-camera and full-package. The first category is self-explanatory.
These cameras use a smartphone and either a bluetooth or a wireless connection for the
live stream. In Figure 2.1 up-left is the Cyclecam Rearview Wi-Fi Bike Camera [19],
middle-left is Fly 6 Cycliq Rear Camera [20] and middle-right is the HEXAGON Camera
[21]. The Bicycle Rearview Camera from Hammacher [28], top-right, falls in the second
category and it offers both a camera and a TFT monitor connected through a cable.
The cheapest starts at $100 and they all offer, among others, HD audio and video loop
recording.

2.2 Bike Alarm

Most bike alarms on the market function like car alarms. They produce a high pitch
alarm when slightly moved or shaken and usually come with a small remote controller
used for turning them on or off and possibly other settings. Bottom part of Figure 2.1
shows two examples. Average price is $10. Of course, there exist more sophisticated bike
alarms that come with smartphone apps and even GPS tracking but these are way out of
our scope and very expensive to begin with.
6 2.2 Bike Alarm

Figure 2.1: Rear bicycle cameras and alarms

The market offers solid solutions to each of the problems, but not a single device that solely
covers them both. Most of the times these solutions also come with extra unnecessary
features that spike the price up. Since an $100 - $200 price for such devices is more than
most of the cyclists are willing to pay or can afford, a cheaper and complete alternative is
needed.
7

3 Solution Description
BikeSide system is a simple and relatively cheap camera-only solution for plain rear traffic
live streaming and temporary anti-theft notification alarm. The main hardware parts are
a camera module and an accelerometer attached to a Raspberry Pi 3/Zero single board
computer running Raspbian OS. They all sit inside a plastic case and are mounted on the
seatpost under the saddle, with the camera facing the rear of the bike. The software part
is composed, on the Raspberry Pi side, of the out-of-the-box Raspbian operating system
and raspivid and netcat programs that generate the video stream and send it over the
network and a python script that generates the antitheft notifications. On the smartphone
end, a simple Android application displays the video stream read from the same network.
The anti-theft notifications are displayed by the built-in Google Chrome browser. While
riding, the smartphone will be mounted in the middle of the handlebars in a landscape
position. Assuming the Raspberry Pi, whose IP address is known, will auto connect to
the mobile Wi-Fi network created by the smartphone, the whole system can be used as
follows:

• The user powers on the Raspberry and creates a mobile hotspot with the target
smartphone.

• With the Pi connected to the WLAN, the user starts up the app and enters the Pi’s
IP address (first time only) on the main screen.

• Besides the input fields for the IP address and por, the main screen contains two
switch buttons, "Stream" and "Lock"" and a regular button "View.

• To start streaming, the user checks the "Stream" switch and then touches the
"View" button. "Back" to exit the live stream to the main screen.

• While live streaming is on, the user can take a screenshot by tapping the camera
symbol.

• To turn on the alarm notification mode, the user checks the "Lock" switch on the
main screen. To unlock, the user taps on the same button, which is now labeled
"Unlock".
8

4 Technologies Used
This chapter will present the hardware, the software and the most relevant of the
technologies used in the development of this project.

4.1 Hardware

4.1.1 Requirements and Constraints

An initial project analysis yielded three essential hardware subroles or processes needed to
fully cover the requirements: rear traffic video capturing, motion/displacement recognition
for when the bicycle is at rest and a way for sending the data to the Android application. As
none of the existing and easily available hardware components covers all of these processes,
or at least two, three individual parts were decided upon: a camera module, a sensor and
a microcomputer/micro-controller to interface them with the Android application. Some
necessary and equally important constraints had to be considered before purchasing the
items:

• Size of the final assembled product should be minimal. It should be discreet, compact
and not draw the attention when fixed on the seatpost. Also mounting/unmounting
should be easy.

• The total cost of the components should be decently lower than the state-of-the art
products presented earlier and they should be easily procurable.

• Previous experience and rich online community. Whenever possible, previously


used or popular hardware components should be chosen since probable arising
development problems will be hastier to solve.

Next subsections will provide relevant details about the used components.
4.1 Hardware 9

4.1.2 Raspberry Pi

The widely known Raspberry Pi was chosen as the interface between the rest of the
components and the Android application. The decision was a no-brainer as the device is
the most popular single-board computer among do-it-yourself (diy) hobbyists, it has a
rich online community with a huge amount of projects, examples and resolved issues and
on top of everything, it was used as the support hardware platform at the laboratories of
the Microprocessor Systems year 3 course.

The Raspberry Pi is a series of small single-board computers developed in the UK to


promote teaching of basic computer science in schools and developing countries. The
original model became a lot more popular than anticipated, selling outside its target
market for uses such as robotics, Internet of Things (IoT) and diy projects. The main
price point for Raspberry Pi has always been $35 and all models have been $35 or less,
including the Pi Zero which costs at around $5. As of March 2018, sales reached 19 million
units. [29]. For this project, the Raspberry Pi 3 Model B was used. This single-board
computer has a powerful set of hardware components that gives it desktop-computer-like
functionalities and allows the development of complex and demanding applications. Some
of the main features are a Broadcom BCM2837 SoC (System-on-Chip), a 4 x ARM
Cortex-A53 1.2 GHz CPU, a powerful Broadcom VideoCore IV GPU, a 1GB LPDDR2
900 MHz RAM, 10/100 Ethernet and 2.4GHz 802.11n wireless for networking, Bluetooth
Low Energy 4.1 Classic, microSD card slot, a HDMI port to connect a monitor, 4 x
USB 2.0 ports, Camera Serial Interface (CSI), Display Serial Interface(DSI), 3.5 mm
analogue audio-video jack and last but definitely not the least, 40 General Purpose I/O
(GPIO) pins header[26]. Any of these pins can be designated (in software) as an input or
output pin and used for a wide range of purposes. The pinout and all the subcomponents
can be seen in Figure 4.1. I2C, SPI, PWM and UART support are few of the electrical
technologies available. Moreover, it supports and encourages the addition of Hardware
on Top (HAT) such as GPS Modules, RGB Matrixes, Piano keyboard and so on. The
Raspberry Pi operates in the open source ecosystem: it runs Linux (various distributions)
and its main supported operating system, Raspbian, is open source and runs a suite of
open source software. Nonetheless, it can also run Android, RISC OS or Windows 10 and
the available programming languages are the ones present in the Linux Operating System
10 4.1 Hardware

such as C/C++, Python, Node.js, Shell-script, Scratch, Java etc.

Figure 4.1: Raspberry Pi 3

Although a powerful tool, the Raspberry Pi has a few drawbacks such as the absence of a
built in analog-to-digital converter on the GPIO pins, the existence of only one pin that
allows hardware PWM or the lack of fuse protection which could damage the board when
incorrectly connecting the pins. Also, this mighty super micro-computer is an overkill if it
is only used for reading and simply handling some sensor data.

4.1.3 MPU6500 Accelerometer

Accelerometers are devices that measure the rate of change of the velocity of an object
(m/s2 ) on one, two or three axes, with the latter category becoming more common as
production cost decreased over the last years. They are useful for sensing vibrations in
systems or for orientation applications. They generally contain capacitive plates, some of
which are fixed and others are attached to small springs that cause the plates to move
when acceleration forces act upon them. The resulted changes in capacitance between the
plates are used to determine the acceleration. Another technique involves piezoelectric
4.1 Hardware 11

materials (e.g. tiny crystal structures) which output electrical charge upon mechanical
stress. Accelerometers are low-power devices that communicate over either an analog,
digital or pulse-width modulated connection interface. IMUs (Inertial Measurement Units)
include multiple sensors such as accelerometers, gyroscopes and sometimes magnetometers
into a single integrated circuit and are often used in motion tracking applications and
UAV guidance systems [18].

The MPU6500 IMU module, Figure 4.2 integrates a 3-axis accelerometer, a 3-axis gyroscope
and a Digital Motion Processor. The 4096 bit present FIFO reduces traffic through the
serial interface and decreases the total power consumption. It uses the I2C communication
protocol for sending but also receiving information. It also supports SPI communication.

Figure 4.2: MPU6500 3-axis Accelerometer and Gyroscope

The MPU6500’s 3-Axis accelerometer has individual capacitive sensors for each axis
which detect the displacement differentially. Each sensor has a dedicated ADC (Analog-
To-Digital-Converter) for providing digital outputs. The accelerometer has a user-
12 4.1 Hardware

programmable full-scale range of ±2g, ±4g, ±8g, and ±16g where 1g is the acceleration
due to gravity. For measuring Earth’s gravity, a ±1.5g accelerometer would be more than
enough. For the motion of a car, plane or robot, ±2g would suffice and for a project with
very sudden starts and stops, ±5g would easily handle the job [22]. When the device is
placed on a flat surface, the measures will be 0g on the X-axis and Y-axis and 1g on the
Z-axis [23]. Because it is an I2C board, the relevant Linux drivers have to be installed.
This is done by copying i2c-bcm2708 and i2c-dev lines into the file /etc/modules. To be
able to read from the I2C using Python bus the smbus module has to be installed. This
can be acomplished using the shell command sudo apt-get install python-smbus.

4.1.4 Raspberry Pi Camera V2

The Raspberry Camera V2, Figure 4.3, is the new official camera module released by the
Raspberry Pi foundation. A high quality 8 megapixel Sony IMX219 image sensor [27]
custom designed add-on board for Raspberry Pi, the camera features a fixed focus lens
capable of taking 3280 x 2464 pixel static images, and also supports 1080p30, 720p60 and
640x480p60/90 video. It attaches via a 15cm supplied ribbon cable to the dedicated CSI
port of the Pi designed especially for interfaces to cameras. The camera’s size is 25mm x
23mm x 9mm and weights barely over 3 grams [25].
4.2 Software and Technologies 13

Figure 4.3: Raspberry Pi Camera V2

The camera is suitable for beginners since basic functionalities like image and video
capturing are easy to implement but it also offers complex functions for advanced users
such as rapid capture and processing, web streaming or custom outputs to name a few [24].
Popular applications include CCTV security cameras, motion detection and time lapse
photography.

4.2 Software and Technologies

Moving forward, the most relevant software and technologies used in this project will be
presented.
14 4.2 Software and Technologies

4.2.1 Development Tools

The development of the Python scripts were done on the Raspberry Pi machine using
Python 3 IDLE and Shell. One monitor, a keyboard and a mouse connected to the Pi were
used instead of the Putty SSH remote connection alternative. The Android application
was developed using Android Studio and Android SDK Platform Tools for Windows.
Programming was done in Java mainly due to the existing previous experience of the
developer.

4.2.2 Multithreading

Multithreading is a Java feature that allows concurrent execution of two or more parts
of a program for maximum utilization of CPU. Each part of such a program is called a
thread. It is multithreading that allows computers to run multiple applications in the
same time. In Android development, multithreading allows heavy logic to be executed on
a separate helper thread and therefore keeping the main ui thread from blocking. There
are two ways to create a thread in Java, both of which are used in this project. The first
way is to extend the Thread class, override the run() method with the custom execution
code, create a new object from this class and call start() on it. The second method is to
pass an implementation of the Runnable interface to the constructor of Thread then call
start(). Also, following the principles of these methods, threads can be created based on
anonymous classes. HandlerThread class allows the creation of a reusable thread. The
class implements a Looper which runs indefinitely and a handler object used to post
Runnable objects to the looper. Listing 1 offers a glimpse of all previously mentioned and
also check the official documentation for more details [7].
1 //Anonymous Thread c r e a t i o n with an anonymous Runnable
2 new Thread ( new Runnable ( ) {
3 @Override
4 p u b l i c v o i d run ( ) {
5 // custom code t o be run
6 }
7 }) . s t a r t ( ) ;
8

9 //Anonymous t h r e a d c r e a t i o n
4.2 Software and Technologies 15

10 new Thread ( ) {
11 p u b l i c v o i d run ( ) {
12 // custom code t o be run
13 }
14 }. start () ;
15

16 // C r e a t i o n o f r e u s a b l e HandlerThread
17 HandlerThread handlerThread = new HandlerThread ( " MyHandlerThread " ) ;
18 handlerThread . s t a r t ( ) ;
19 Handler h a n d l e r = new Handler ( handlerThread . g e t L o o p e r ( ) ) ;
20

21 h a n d l e r . p o s t ( new Runnable ( ) {
22 @Override
23 p u b l i c v o i d run ( ) {
24 // custom code t o be run
25 }
26 }) ;

Listing 1: Multithreading

4.2.3 TCP Protocol and Sockets

TCP is a transport protocol that delivers the stream of data in a reliable, ordered and
error-checked way. It is perfectly suited for applications that require guaranteed delivery
of packets, such as video streaming or internet banking services. Processes that run on
separate machines communicate with each other by sending messages into sockets, over a
TCP connection, just as if there was a direct channel/pipe btween client and server. For
details on how to establish a TCP connection over sockets refer to [8].

4.2.4 JSch

Java Secure Channel, JSch [11], allows a connection to a remote Secure Shell (SSH),
providing support for secure remote login, secure file transfer and so on. It can
automatically encrypt, authenticate and compress transmitted data. The JSch library can
be used to connect to cloud machines in a secure way automatically. For this project, it is
16 4.2 Software and Technologies

used in the Android application to connect to the Raspberry Pi over the local network
and send shell commands to run the python scripts, see Listing 2.
1 JSch j s c h = new JSch ( ) ;
2 S e s s i o n s e s s i o n = j s c h . g e t S e s s i o n ( " pi " , " 1 9 2 . 1 6 8 . 4 3 . 2 1 7 " , 22) ;
3 s e s s i o n . setPassword ( " raspberry " ) ;
4 // Avoid a s k i n g f o r key c o n f i r m a t i o n
5 P r o p e r t i e s prop = new P r o p e r t i e s ( ) ;
6 prop . put ( " S t r i c t H o s t K e y C h e c k i n g " , "no" ) ;
7 s e s s i o n . s e t C o n f i g ( prop ) ;
8 s e s s i o n . connect () ;
9 // SSH Channel
10 ChannelExec c h a n n e l s s h = ( ChannelExec ) s e s s i o n . openChannel ( " e x e c " ) ;
11 ByteArrayOutputStream baos = new ByteArrayOutputStream ( ) ;
12 c h a n n e l s s h . setOutputStream ( baos ) ;
13 // Execute command
14 c h a n n e l s s h . setCommand ( " sudo python3 s e n s o r . py" ) ;
15 channelssh . connect () ;
16 channelssh . disconnect () ;
17 // Get r e s p o n s e
18 r e t u r n baos . t o S t r i n g ( ) ;

Listing 2: Python script execution over JSch connection [4]

4.2.5 Notify.run

notify.run [3] makes it easy to programmatically send notifications to a phone or a


desktop. It uses standard APIs for both sending and subscribing to notifications, which
means that it can be used without installling any software. It has a built-in command-line
tool and Python package for a better integration. For this project, notify.run is used to
send alarm notifications from the Raspberry Pi to the Chrome browser of the Android
smartphone whenever the accelerometer accelerates over a threshold.

4.2.6 Raspivid and netcat

The Raspberry Pi’s built in raspivid program is used to generate a raw H.264 video stream
which is then sent out over the network as a TCP/IP stream using netcat utility. Listing
4.2 Software and Technologies 17

3 shows the full command.

1 r a s p i v i d −n −i h −t 0 −r o t 0 −w 1280 −h 720 −f p s 15 −b 1000000 −o − | nc −


l k v 4 5001

Listing 3: Generating the stream using raspivid and netcat

The raspivid parameters are -n to not show the video on the Raspberry Pi display, -ih
to insert H.264 headers into the stream, -t 0 to keep streaming forever, -rot 0 to not
rotate the stream, -o – to send the stream to stdout while the netcat parameters are -l
5001 listen to listen on port 5001, -k to connect repeatedly, -v to produce verbose error
messages, -4 to use IPv4 addresses only.
18

5 Development and Implementation


This chapter will present all the work acomplished for the development of the system,
mainly including the Android application and the Raspberry Pi scripts. Figure 5.1 shows
the entire system pieces.

Figure 5.1: System components

5.1 BikeSide Android Application

The application was developed in Android Studio using the Android SDK tools and the
Android Support Libraries for Java. The core functionality, that is, the processing of the
input stream of bytes coming over the network from the Raspberry Pi was imported from
the open source RPICameraViewer Android application git repository [1], Copyright ©
2016-2019 Shawn Baker using the MIT License [12] and the entire BikeSide application
was developed on top and around this functionality.

Figure 5.2 contains the application’s UML diagram offering a preview on its simplistic
architecture. Two activities, one fragment and six helper classes make up the components
of the app. Also, the fragment and one of the activities each contain a private inner class.
5.1 BikeSide Android Application 19

The next subsections will present the roles and functionalities of the most relevant of
these components.

Figure 5.2: BikeSide UML Diagram

5.1.1 MainActivity

An activity is a single screen with a user interface and represents the bridge between the
user and the application, similar to a window in a desktop application. An Android app
may contain one or more activities, with one of them, the main activity, being the entry
point of the application. An activity is created and initialized before being displayed on
the screen, therefore it goes through different states. The Activity class provides a number
20 5.1 BikeSide Android Application

of callbacks that allow the activity to know that a state has changed: that the system is
creating, stopping or resuming an activity, or destroying the process in which the activity
resides. Within the lifecycle callback methods, you can declare how your activity behaves
when the user leaves and re-enters the activity [5].

The entry point of this application, MainActivity, Figure 5.3 contains the following
components arranged on top of a ConstraintLayout:

• A Switch view Stream and a Button view VIEW that handle the streaming part.

• A Switch view Lock that handles the notification alarm locking part.

• Two TextView labels, IP Address and Port, and two EditText views for editing
the two network parameters and a Switch view Edit that enables/disables input on
the EditTexts.

The Stream switch has a CompoundButton.OnCheckedChangeListener attached to it.


When the switch is checked, a JSch (Java Secure Channel) object is created. Using
this object and the Raspberry Pi’s network parameters (static IP address and port) a
new Session object is created on the Raspberry Pi and from that Session object, a SSH
ChannelExec object is instantiated. The preiously mentioned raspivid command 3 is set
on the channel object and finally connect() is called on it which starts the stream on the
Raspberry side. At this point, the VIEW button becomes enabled. When the switch
is unchecked, the channel is disconnected, set to null, instantiated again, set with the
command sudo pkill raspivid; sudo pkill nc and connected and then disconnected. This
eventually kills all the processes related to the streaming on the Raspberry side and disables
the VIEW button. Both parts are implemented in anonymous Runnable instances and
posted by the thread Handler object to be executed on the helper HandlerThread instance.
Listing 4 exemplifies the first part.
1 pri vate void streamStart ( ) {
2

3 // Post t h e work on t h e h e l p e r t h r e a d
4 t h r e a d H a n d l e r . p o s t ( new Runnable ( ) {
5 @Override
6 p u b l i c v o i d run ( ) {
7 // C r e a t e a new s e s s i o n u s i n g t h e Raspberry Pi ' s network
parameters
5.1 BikeSide Android Application 21

8 i f ( s e s s i o n == n u l l ) {
9 try {
10 S t r i n g a d d r e s s = e d i t T e x t I P . getText ( ) . t o S t r i n g ( ) .
trim ( ) ;
11 s e s s i o n = j s c h . g e t S e s s i o n ( " pi " , address , 22) ;
12 } c a t c h ( JSchException e ) { . . . }
13 s e s s i o n . s e t P a s s w o r d ( " 1993 leoA / " ) ;
14 ...
15 try {
16 s e s s i o n . connect () ; // c o n n e c t t o t h e s e s s i o n
17 } c a t c h ( JSchException e ) { . . . }
18 }
19

20 // open t h e SSH Channel


21 i f ( c h a n n e l s s h == n u l l ) {
22 try {
23 c h a n n e l s s h = ( com . j c r a f t . j s c h . ChannelExec ) s e s s i o n .
openChannel ( " e x e c " ) ;
24 } c a t c h ( JSchException e ) { . . . }
25 }
26 // s e t t h e r a s p i v i d −n e t c a t command t h a t s t a r t s t h e stream
27 c h a n n e l s s h . setCommand (RASPIVID) ;
28 try {
29 channelssh . connect () ;
30 } c a t c h ( JSchException e ) { . . . }
31

32 buttonStream . s e t E n a b l e d ( t r u e ) ;
33 }
34 }) ;
35 }

Listing 4: JSch for starting the stream

In a similar way, the Lock switch starts and terminates the Raspberry Pi Python script
that listens to the accelerometer movement and sends notifications using notify.run [3].
22 5.1 BikeSide Android Application

Figure 5.3: MainActivity layout

A prerequisite for the system to work is the common connection of both the Raspberry
Pi and the smartphone to the same network. This will be achieved by connecting the Pi
to the mobile hotspot created by the phone while using the application. The Raspberry
Pi will always be streaming over the local network on port 5001 and since its static IP
address will never change, these two values should be saved between usage sessions. The
application does this by means of SharedPreferences. A SharedPreferences object points
to a file containing key-value pairs and provides simple methods to read and write them.
Each SharedPreferences file is managed by the application, and can be private or shared
[17]. The EditText components of the MainActivity are set with the IP address and port
values from the SharedPreferences inside the onCreate() callback. If edited, the values
are saved inside the run() method of the local private class CheckDataRunnable which
implements the Runnable interface. This is done upon unchecking the Switch view, after
the input validation, on a separate helper thread so that the main thread doesn’t block,
see Listing 5.
1 p r o t e c t e d v o i d onCreate ( Bundle s a v e d I n s t a n c e S t a t e ) {
2 ...
3 prefsApp = g e t S h a r e d P r e f e r e n c e s (PREFS_SETTINGS, Context .MODE_PRIVATE) ;
4 e d i t T e x t I P . s e t T e x t ( prefsApp . g e t S t r i n g (ADDRESS, " 1 9 2 . 1 6 8 . 4 3 . 2 1 7 " ) ) ;
5.1 BikeSide Android Application 23

5 e d i t T e x t P o r t . s e t T e x t ( prefsApp . g e t S t r i n g (PORT, " 5001 " ) ) ;


6 ...
7 s w i t c h E d i t . setOnCheckedChangeListener ( new CompoundButton .
OnCheckedChangeListener ( ) {
8 @Override
9 p u b l i c v o i d onCheckedChanged ( CompoundButton buttonView , b o o l e a n
isChecked ) {
10 t h r e a d H a n d l e r . p o s t ( new CheckDataRunnable ( i s C h e c k e d ) ) ;
11 }
12 }) ;
13 }
14

15 p r i v a t e c l a s s CheckDataRunnable implements Runnable {


16 ...
17 @Override
18 p u b l i c v o i d run ( ) {
19 // i n p u t v a l i d a t i o n on IP a d d r e s s and p o r t
20 ...
21 // Switch unchecks i f v a l u e s a r e v a l i d
22 ...
23 i f ( ! switchEdit . isChecked ( ) ) {
24 ...
25 prefsApp . e d i t ( ) . p u t S t r i n g (ADDRESS, a d d r e s s ) . apply ( ) ;
26 prefsApp . e d i t ( ) . p u t S t r i n g (PORT, I n t e g e r . t o S t r i n g ( p o r t ) ) .
apply ( ) ;
27 }
28 ...
29 }
30 }

Listing 5: SharedPreferences and input validation

The Camera class has four attributes, network, name, address and port, with the last
two being mandatory for the network socket connection. Although it simply contains
these network parameters, the Camera class abstractly models the camera attached to
the Raspberry Pi and it opens the possibility to scale the system and model the use of
more cameras in the same time.

Coming back to the MainActivity, a click listener on the STREAM button creates an
24 5.1 BikeSide Android Application

instance of the Camera class using the valid IP address and port values from the EditText
views. It then attaches this instance to an intent and uses it to start the VideoActivity.

5.1.2 VideoActivity

The entire logic related to the decoding of the input byte stream and displaying it on
the screen is implemented inside VideoFragment. VideoActivity is the activity that hosts
this fragment. It contains a single layout component, FrameLayout, on top of which
the fragment will be displayed. onCreate() and onBackPressed() callbacks have been
overridden as follows: when the activity is created, the Camera object is retrieved from the
intent, a listener for the system status bar changes is set on the FrameLayout which calls
a method of the fragment that generates smooth fade in animation, then the FrameLayout
is set to full screen and finally a VideoFragment object is initialized with the Camera
object and added to a transaction which is then committed. At this point, the lifecycle
of the fragment starts. When the back button is pressed, the fragment is stopped. See
Listing 6.
1 @Override
2 p r o t e c t e d v o i d onCreate ( Bundle s a v e d I n s t a n c e S t a t e ) {
3 ...
4 // g e t t h e camera o b j e c t
5 Camera camera = g e t I n t e n t ( ) . g e t E x t r a s ( ) . g e t P a r c e l a b l e (CAMERA) ;
6 ...
7 // h a n d l e system bar v i s i b i l i t y c h a n g e s
8 frameLayout . s e t O n S y s t e m U i V i s i b i l i t y C h a n g e L i s t e n e r ( new View .
OnSystemUiVisibilityChangeListener () {
9 @Override
10 public void onSystemUiVisibilityChange ( i n t v i s i b i l i t y ) {
11 i f ( ( v i s i b i l i t y & View .SYSTEM_UI_FLAG_FULLSCREEN) == 0 ) {
12 videoFragment . s t a r t F a d e I n ( ) ;
13 }
14 }
15 }) ;
16 ...
17 // c r e a t e t h e v i d e o fragment
18 videoFragment = VideoFragment . n e w I n s t a n c e ( camera , t r u e ) ;
5.1 BikeSide Android Application 25

19 FragmentTransaction f r a g T r a n = getSupportFragmentManager ( ) .
beginTransaction () ;
20 f r a g T r a n . add (R. i d . video , videoFragment ) ;
21 f r a g T r a n . commit ( ) ;
22 }
23 ...
24 @Override
25 p u b l i c v o i d onBackPressed ( ) {
26 videoFragment . s t o p ( ) ;
27 s u p e r . onBackPressed ( ) ;
28 }

Listing 6: VideoActivity

5.1.3 VideoFragment

VideoFragment is the core module of the streaming part of the application. It is


imported from the earlier mentioned MIT licensed open source RPICameraViewer Android
application [1] and used as a black box component. On a high level, it takes a Camera
object as input and it produces the video on the mobile screen as output. On a lower
level, VideoFragment component starts a separate thread where it creates and connects to
a TCP/IP socket using the port and IP address attributes of the Camera object received
from the VideoActivity. It then starts reading, processing and rendering the byte stream
from the socket as long as the thread remains uninterrupted. This all happens inside
the run() method of the private inner class DecoderThread that extends Thread class.
The decoder thread started and stopped inside onStart() and onStop() VideoFragment
callback methods, see Listing 7.

1 ...
2 p r i v a t e DecoderThread d e c o d e r ;
3 ...
4 @Override
5 public void onStart ( ) {
6 super . onStart () ;
7 d e c o d e r = new DecoderThread ( ) ;
8 decoder . s t a r t () ;
9 }
26 5.1 BikeSide Android Application

10

11 @Override
12 p u b l i c v o i d onStop ( ) {
13 s u p e r . onStop ( ) ;
14 i f ( d e c o d e r != n u l l ) {
15 decoder . i n t e r r u p t () ;
16 decoder = n u l l ;
17 }
18 }
19 ...

Listing 7: Decoder thread lifecycle

The most relevant instance attributes of the DecoderThread private class are a MediaCodec
decoder object, a Surface instance and a TcpIpReader instance.

In broad terms, the MediaCodec object processes input data to generate output data. It
processes data asynchronously and uses a set of input and output buffers. At a simplistic
level, an empty input buffer is requested (or received), filled up with and sent to the codec
for processing. The codec uses up the data and transforms it into one of its empty output
buffers. Finally, a filled output buffer is requested (or received), consumed and released
back to the codec [6], see Figure 5.4.

Figure 5.4: MediaCodec [6]

The Surface object is created from the SurfaceTexture (private field of the VideoFragment)
which is the consumer of the image buffers and is handed to the MediaCodec object which
5.1 BikeSide Android Application 27

acts as a producer of image buffers. The Raspberry Pi generates a H.264 stream so the
MediaCodec object is instantiated using the type "video/avc" to be able to decode the
stream. The TcpIpReader class uses a Camera object to create a socket and then an
InputStream object based on that socket. It also implements a read(byte[] buffer) method
that reads from the InputStream object.

1 p u b l i c v o i d run ( ) {
2 ...
3 try {
4 // c r e a t e t h e d e c o d e r
5 d e c o d e r = MediaCodec . createDecoderByType ( " v i d e o / avc " ) ;
6

7 // c r e a t e t h e r e a d e r
8 r e a d e r = new TcpIpReader ( camera ) ;
9 i f ( ! reader . isConnected () ) {
10 throw new E x c e p t i o n ( ) ;
11 }
12

13 // r e a d u n t i l we ' r e i n t e r r u p t e d
14 while ( ! isInterrupted () ) {
15 // r e a d from t h e stream i n t o b u f f e r
16 i n t readLength = r e a d e r . r e a d ( b u f f e r ) ;
17 i f ( i s I n t e r r u p t e d ( ) ) break ;
18

19 // p r o c e s s t h e i n p u t b u f f e r
20 ...
21 // send an output b u f f e r t o t h e s u r f a c e
22 i f ( format != n u l l && d e c o d i n g ) {
23 i f ( i s I n t e r r u p t e d ( ) ) break ;
24 MediaCodec . B u f f e r I n f o i n f o = new MediaCodec .
BufferInfo () ;
25 i n t index ;
26 do {
27 i n d e x = d e c o d e r . dequeueOutputBuffer ( i n f o , 0 ) ;
28 i f ( i s I n t e r r u p t e d ( ) ) break ;
29 i f ( i n d e x >= 0 ) {
30 d e c o d e r . r e l e a s e O u t p u t B u f f e r ( index , t r u e ) ;
31 }
32 } w h i l e ( i n d e x >= 0 ) ;
28 5.1 BikeSide Android Application

33 }
34 }
35 } c a t c h ( E x c e p t i o n ex ) {
36 // r e a d e r i s empty
37 }
38

39 // c l o s e t h e r e a d e r
40 ...
41 // s t o p t h e d e c o d e r
42 ...
43 }
44

45

46 p u b l i c c l a s s TcpIpReader {
47 ...
48 p u b l i c TcpIpReader ( Camera camera ) {
49 try {
50 s o c k e t = g e t C o n n e c t i o n ( camera . a d d r e s s , camera . port ,
CONNECT_TIMEOUT) ;
51 s o c k e t . setSoTimeout (IO_TIMEOUT) ;
52 inputStream = s o c k e t . g e t I n p u t S t r e a m ( ) ;
53 } c a t c h ( E x c e p t i o n ex ) {
54 }
55 }
56

57 // g e t t h e s o c k e t c o n n e c t i o n
58 p u b l i c s t a t i c S o c k e t g e t C o n n e c t i o n ( S t r i n g baseAddress , i n t port , i n t
timeout ) {
59 Socket socket ;
60 try {
61 s o c k e t = new S o c k e t ( ) ;
62 I n e t S o c k e t A d d r e s s s o c k e t A d d r e s s = new I n e t S o c k e t A d d r e s s (
baseAddress , p o r t ) ;
63 socket . connect ( socketAddress , timeout ) ;
64 } c a t c h ( E x c e p t i o n ex ) {
65 ...
66 }
67 return socket ;
68 }
5.2 Raspberry Pi Python Script 29

69 // r e a d from t h e i n p u t stream
70 p u b l i c i n t r e a d ( byte [ ] b u f f e r ) {
71 try {
72 r e t u r n ( inputStream != n u l l ) ? inputStream . r e a d ( b u f f e r ) : 0 ;
73 } c a t c h ( IOException ex ) {
74 return 0;
75 }
76 }
77 ...
78 }

Listing 8: DecoderThread

A built-in functionality of the VideoFragment is the ability to take snapshots while


streaming. It uses the getBitmap() method of TextureView class to save a Bitmap image
which then it stores on the external memory.

5.2 Raspberry Pi Python Script

The idea is simple: whenever the user checks the Lock main activity switch, a Python
script has to run on the Raspberry and start reading the individual 3-axes accelerometer
values. If the values go over a certain threshold, Notify.run sends a notification to the
smartphone’s Chrome browser.

The sensor has a number of registers which have different functionality as documented
in this datasheet [23]. The registers we are interested in for the acceleromter data are
0x3b, 0x3d, 0x3f and these hold the raw data in 16 bit two’s complement format. Listing
9 exemplifies the reading.
1 #r e a d a byte from t h e t a r g e t r e g i s t e r
2 d e f read_byte ( r e g ) :
3 r e t u r n bus . read_byte_data ( a d d r e s s , r e g )
4 #r e a d two b y t e s and ' c o n c a t e n a t e s ' them i n t o a word
5 d e f read_word ( r e g ) :
6 h = bus . read_byte_data ( a d d r e s s , r e g )
7 l = bus . read_byte_data ( a d d r e s s , r e g +1)
8 v a l u e = ( h << 8 ) + l
9 return value
30 5.2 Raspberry Pi Python Script

10 #c o n v e r t s t h e word from 2 ' s complement


11 d e f read_word_2c ( r e g ) :
12 v a l = read_word ( r e g )
13 i f ( v a l >= 0 x8000 ) :
14 r e t u r n −((65535 − v a l ) + 1 )
15 else :
16 return val

Listing 9: Reading accelerometer values

Since the bicycle and implicitly the accelerometer can be left hanging in different positions,
the threshold values have to be dynamically computed every time before locking the system.
This is achieved by reading the 3-axis values calibration rounds times and updating the
minimum and maximum value for each axis. Three intervals, one for each axis, are yielded
at the end of the calibration. From that point on, any future reading that falls outside
those intervals triggers the Notify.run notification. The intervals are extended with a
sensor tolerance constant which gives the programmer full control over the notification
threshold, see Listing 10.

1 def calibrateAcc () :
2 f o r i in range ( calibration_rounds ) :
3 x_acc = read_word_2c ( accel_x )
4 i f ( x_acc > x_max) :
5 x_max = x_acc
6 e l i f ( x_acc < x_min ) :
7 x_min = x_acc
8 c a l i b r a t e d = True
9

10 d e f checkMotion ( ) :
11 motion = F a l s e
12 x_acc = read_word_2c ( accel_x )
13 #s e n s o r _ t o l e r a n c e i s a c o n s t a n t t h a t e x t e n d s t h e t h r e s h o l d i n t e r v a l
14 i f ( x_acc > x_max + s e n s o r _ t o l e r a n c e o r x_acc < x_min −
sensor_tolerance ) :
15 motion = True
16 p r i n t ( ' Motion d e t e c t e d o v e r X a x i s ' )
17 #r e p e a t f o r Y−a x i s and Z−a x i s
5.2 Raspberry Pi Python Script 31

18 r e t u r n motion

Listing 10: Calibration and Motion Check


32

(a) Close-up (b) Side angle

Figure 6.1: BikeSide rear camera

6 User Guide
The following steps explain the usage of the BikeSide system.

The user creates a personal hotspot using the smartphone and turns on the Raspberry Pi
which is attached to the bicycle, facing the rear traffic. The Pi recognizes and connects to
the wireless network.

To stream the rear traffic, on the main activity, the user checks the Edit switch to enable
the input boxes and types in the camera network parameters, see Figure 6.2a, only if
the existing ones don’t match the target Raspberry machine. Input validation will throw
a warning if the formats are incorrect. Next, providing the parameters are correct, the
user checks the Stream switch. When the VIEW button becomes enabled, the stream is
running and the screen is ready to display it, see Figure 6.2b. Touching the VIEW button
will open the video activity and display the live stream. To exit the live stream, the user
has to click on the back button.

To lock the system, the user simply checks the Lock switch, see Figure 6.3a. In case the
33

(a) Set camera parameters (b) Connect and start the stream

Figure 6.2: Main Activity - Live Streaming


34

(a) Check Edit switch (b) Notification example

Figure 6.3: Main Activity - Locking

system, therefore the bicycle, is stressed (displaced, moved, shaken etc), a notification
pops in, see Figure 6.3b. Unchecking the same switch unlocks the system.
35

7 Conclusion
This project is the result of a randomly occurred idea on a busy, heavy-traffic day while
the student was riding in a rush towards the university. The idea was "what if instead of
always turning and double-checking for what’s happening behind me I could just look at
my smartphone’s screen on the handlebar and see everything?". As Android Development
and Microprocessor Systems were both subjects of study in the university, the natural
decision was to build a system composed of a Raspberry Pi microcomputer and an Android
application. As the problem solved by the system is a very particular or personal one,
one that many would think is not actually a problem, the development mindset was never
focused around a comercial purpose. The Android application is simple and the system
doesn’t offer extra features. The system only does two things: it streams the rear traffic
while in streaming mode and it sends push notifications while in lock mode, if the bicycle
is stressed. The image on the stream is sometimes ’shaky’ uninterrupted. There is almost
zero latency and the rear traffic is distinguishable also in mid day sun. An interesting
feature to work on in the future would be to add a ’speedometer’ functionality by correctly
interpreting the MPU6500 gyro-accelerometer values while riding.

On a personal note, regardless of the whole project’s simplicity, of the low number of
software modules and few general features, it felt very rewarding when it was finalized
and it opened an appetite for Raspberry Pi projects and also Android apps.
36

Figure 7.1: BikeSide sideview [6]


Listings 37

Listings
1 Multithreading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2 Python script execution over JSch connection [4] . . . . . . . . . . . . . . 16
3 Generating the stream using raspivid and netcat . . . . . . . . . . . . . . 17
4 JSch for starting the stream . . . . . . . . . . . . . . . . . . . . . . . . . 20
5 SharedPreferences and input validation . . . . . . . . . . . . . . . . . . . 22
6 VideoActivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
7 Decoder thread lifecycle . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
8 DecoderThread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
9 Reading accelerometer values . . . . . . . . . . . . . . . . . . . . . . . . 29
10 Calibration and Motion Check . . . . . . . . . . . . . . . . . . . . . . . . 30
38 References

References
[1] Baker, S. (2019). RPi Camera Viewer. https://github.com/ShawnBaker/
RPiCameraViewer [Accessed: Whenever].
[2] Both, S. (2018). Inventarul celor 106 kilometri de piste
de biciclete din Timişoara. https://adevarul.ro/locale/timisoara/
inventarul-celor-106-kilometri-piste-biciclete-timisoara-este-cadou-administratia-locale-ocazia-intervina-pun
5be03458df52022f752e4ebe/index.html [Accessed: Whenever].
[3] Butler, P. (2019). http://notify.run [accessed: 2019].
[4] COLOMA, M. D. (2019). https://eridem.net/android-tip-021-ssh-execute-remote-
commands-with-android [accessed: 2019].
[5] developer.android.com (2019). Understand the Activity Lifecycle. https://developer.
android.com/guide/components/activities/activity-lifecycle [Accessed: Whenever].
[6] Documentation, A. (2019a). https://developer.android.com/reference/android/media/MediaCodec
[accessed: 2019].
[7] Documentation, A. (2019b). https://developer.android.com/training/multiple-threads
[accessed: 2019].
[8] Documentation, J. (2019c). https://developer.android.com/training/multiple-threads
[accessed: 2019].
[9] Greenacre, M. J. (1984). Theory and applications of correspondence analysis.
[10] James, G., Witten, D., Hastie, T., and Tibshirani, R. (2013). An introduction to
statistical learning, volume 112. Springer.
[11] jcraft.inc (2019). http://www.jcraft.com/jsch/ [accessed: 2019].
[12] opensource.org (2019). The MIT License. https://opensource.org/licenses/MIT
[Accessed: Whenever].
[13] Pearson, E. S. (1931). The test of significance for the correlation coefficient. Journal
of the American Statistical Association, 26(174):128–134.
[14] pentru Biciclete, V. (2019a). Bike Map Timisoara. https://pedaleaza.ro/vrempiste/
[Accessed: Whenever].
[15] pentru Biciclete, V. (2019b). Legislatie Biciclete. https://pedaleaza.ro/
legislatie-privind-mersul-pe-bicicleta-actualizata-in-21-ianuarie-2017/ [Accessed:
Whenever].
[16] The International Energy Agency (2018). Global ev outlook 2018, towards cross-modal
electrification.
[17] Topirceanu, A. (2019). https://sites.google.com/site/alexandrutopirceanu/teaching/msa/lab6
[accessed: 2019].
[18] Website, O. (2019a). Accelerometers. https://learn.sparkfun.com/tutorials/
accelerometer-basics/all [Accessed: Whenever].
References 39

[19] Website, O. (2019b). Cyclecam Rearview Wi-Fi Bike Camera. https://www.amazon.


com/Streetwise-Security-Products-CRVWBC-Cyclecam/dp/B01MXYFBEV [Accessed:
Whenever].
[20] Website, O. (2019c). Fly 6 Cycliq Rear Camera. https://cycliq.com/bike-cameras/
fly6ce/fly6-ce-tech-specs/ [Accessed: Whenever].
[21] Website, O. (2019d). HEXAGON - Camera, Signals, & Sensors for Cyclists. https:
//www.indiegogo.com/projects/hexagon-camera-signals-sensors-for-cyclists#/ [Accessed:
Whenever].
[22] Website, O. (2019e). Introduction in Accelerometers. https://www.
dimensionengineering.com/info/accelerometers [Accessed: Whenever].
[23] Website, O. (2019f). MPU6500 Datasheet. https://www.openimpulse.com/blog/
wp-content/uploads/wpsc/downloadables/MPU_6500_Rev1.0.pdf [Accessed: Whenever].
[24] Website, O. (2019g). Pi Camera Python documntation. https://picamera.readthedocs.
io/en/release-1.13/recipes2 [Accessed: Whenever].
[25] Website, O. (2019h). Raspberry Pi Camera Module V2. https://thepihut.com/products/
raspberry-pi-camera-module [Accessed: Whenever].
[26] Website, O. (2019i). Raspberry Pi Specs. https://www.raspberrypi.org/magpi/
raspberry-pi-3-specs-benchmarks/ [Accessed: Whenever].
[27] Website, O. (2019j). Sony IMX219PQ Sensor. https://www.sony-semicon.co.jp/
products_en/new_pro/april_2014/imx219_e.html [Accessed: Whenever].
[28] Website, O. (2019k). The Bicycle Rearview Camera. https://www.hammacher.com/
product/bicycle-rearview-camera-1?PID=5314042&source=cj&utm_source=Affiliate&
utm_medium=CPA&utm_campaign=CJ [Accessed: Whenever].
[29] Wikipedia (2019). Raspberry Pi. https://en.wikipedia.org/wiki/Raspberry_Pi [Accessed:
Whenever].

Potrebbero piacerti anche