Riderless Self-Balancing Bicycle
Riderless Self-Balancing Bicycle
Riderless Self-Balancing Bicycle
Riderless self-balancing
bicycle
Derivation and implementation of a time variant
linearized state space model for balancing a
bicycle in motion by turning the front wheel
ARTHUR GRÖNLUND
CHRISTOS TOLIS
Derivation and implementation of a time variant linearized state space model for
balancing a bicycle in motion by turning the front wheel
TRITA-ITM-EX 2018:58
Abstract
Syftet med detta projekt har varit att ta fram och imple-
mentera en linjäriserad tidsvarierande tillståndsmodell för
balansreglering av en elcykel genom vridning av framhjulet.
För att testa modellen konstruerades en liten demonstrator
med vilken experiment och tester utfördes.
Den slutsats som drogs var att modellen mycket väl skulle
kunna vara en lösning för balansering av en elcykel, men
att fortsatta undersökningar bör genomföras på en större
skala för att en mer definitiv slutsats skall kunna dras.
Acknowledgements
We would like to thank the staff and students working at the M building at KTH
for showing enthusiastic interest in our project and engaging in discussions during
our test runs. The discussions led to further insights about the project and were
very helpful.
Thank you also to our fellow FiM students and assistants for showing interest in
the project and suggesting improvements, both during seminars and off-schedule.
A special thank you goes to Staffan Qvarnström for pointing us in the right direction
whenever a problem arose. A thank you also to Stefan Ionescu for initially helping
us out with the 3D-printing. Finally, a thank you to Kayla Kearns for proof-reading
our report.
Contents
1 Introduction 1
1.1 Background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 General method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2 Theory 3
2.1 The Arduino Uno board . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.2 DC motors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3 H-bridges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.4 Potentiometers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.5 Accelerometers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.6 Gyroscopes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.7 Complementary filter . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.8 Mechanics of an electric bicycle . . . . . . . . . . . . . . . . . . . . . 7
2.8.1 Acceleration and braking . . . . . . . . . . . . . . . . . . . . 8
2.8.2 Relating the steering angle to the radius of curvature . . . . . 9
2.8.3 Turning and instability . . . . . . . . . . . . . . . . . . . . . 10
2.9 Automatic control . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.9.1 Balance regulator . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.9.2 Steering motor . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.9.3 Driving motor . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.10 The Runge-Kutta 4-method . . . . . . . . . . . . . . . . . . . . . . . 15
2.11 Approximating second order ODEs . . . . . . . . . . . . . . . . . . . 15
3 Demonstrator 17
3.1 Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.2 Component selection . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.3 Electronics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.4 Construction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.5 Experimental setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4 Results 25
Bibliography 33
Appendices 34
B CAD drawings 38
B.1 Frame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
B.2 Rear frame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
B.3 Fork . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
B.4 Drive motor mount . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
B.5 Drive motor cover . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
B.6 Steer motor cover . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
B.7 Pulse code wheel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
B.8 Exploded bicycle assembly . . . . . . . . . . . . . . . . . . . . . . . . 46
D Arduino C code 59
List of Figures
3.1 Simulating the bicycle system with different events and bicycle com-
mands. Created using MATLAB. . . . . . . . . . . . . . . . . . . . . . . 18
3.2 Photograph of the box housing the electronics. . . . . . . . . . . . . . . 20
3.3 CAD model of the steer assembly. Created using Solid Edge ST9. . . . . 21
3.4 CAD model of the rear part of the bicycle. Created using Solid Edge ST9. 21
3.5 CAD model of the completed bicycle. Created using Solid Edge ST9.
Rendered in KeyShot 6.3. . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.6 Photograph of the bicycle. . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.1 A typical experimental result where the bicycle loses friction. Created
using MATLAB. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.2 A typical experimental result where the bicycle managed to keep itself
balanced. Created using MATLAB. . . . . . . . . . . . . . . . . . . . . 26
4.3 Results of simulating the bicycle, matching the initial values of the ex-
perimental run in Figure 4.2. Created using MATLAB. . . . . . . . . . 27
Abbreviations
DC direct current. 2, 4, 20
PI proportional integral. 14
PLA polylactic acid. 22
PWM pulse-width modulation. 3, 23, 25, 31
A State matrix
B Input vector
C Output vector
ρ Air density
θ Steer angle
Cd Drag coefficient
FB Braking force
FD Driving force
m Bicycle mass
v Bicycle speed
Introduction
1.1 Background
With self driving vehicles such as cars and buses becoming more of a reality daily,
the creation of smaller and consequently less energy consuming vehicles is becoming
more and more relevant. Self driving motorcycles, and two-wheeled vehicles in gen-
eral, could prove to be a more effective way of self driven transportation because of
their advantage of taking up less space and energy for single person transportation.
For these vehicles to be usable, a good and energy efficient balancing system needs
to be implemented. Usually, one of three different stabilizing methods are used. The
first method uses a gyroscope with motors attached to the gimbals and flywheel.
This is called control moment gyroscope (CMG) [1]. The second method uses a
displaceable weight to shift the bicycle’s centre of gravity [2]. The third method
utilizes the centrifugal force that arises when a bicycle is steered in a certain direc-
tion. This is referred to as "dynamic stabilization" [1]. An example of this method
being used can be found in [3], where it was used to balance a full-sized electric
bicycle, albeit with a fairly complicated system for regulation. Of these methods,
the third method has been the subject of research in this project.
There are some obvious advantages to the CMG method and the displaceable weight
method, as they can be active when the bicycle is standing still. The steering method
only works when the bicycle has a forward speed. However, energy is required to
keep a flywheel spinning at high speed or have the ability to move around a heavy
mass. Turning a steering handle should be quite energy-efficient in comparison.
Another problem using the steering method is that the bicycle will steer off its
intended path.
1
CHAPTER 1. INTRODUCTION
1.2 Purpose
The purpose of this project has been to develop and evaluate whether a linearized
time-variant state-space model can be utilized in balancing a bicycle using a dynamic
stabilization technique.
Before the construction was carried out, a program for simulating the mechanics of
the bicycle with and without automatic control was created. The purpose of the
simulation was to tune the control variables without risking damage to hardware,
and to determine the approximate requirements of parts used in construction of the
prototype.
After constructing the demonstrator experiments were carried out to fine-tune the
system and determine its feasibility.
2
Chapter 2
Theory
The Uno also has the capability to communicate with other connected devices using
the I2 C bus [4]. The I2 C bus uses two bus lines for communication, these are called
serial data (SDA) and serial clock (SCL). It is possible to connect multiple devices
along these lines by giving each device a unique address [5]. On revision 3 of the
Uno, there are two separate pins for SDA and SCL. However, these are connected
in parallel to the analog pins 4 and 5 respectively. This means that once I2 C is
activated those pins cannot be used for other purposes [4].
One more way the Uno can communicate with other devices is via the serial periph-
eral interface (SPI) protocol. This interface uses 3 lines for communication called
master out slave in (MOSI), master in slave out (MISO) and serial clock (SCK).
One additional line, usually called slave select (SS) or chip select (CS), is also re-
quired for each connected device. On the Uno there are separate pins for the 3
communication lines but these are shared with digital pins 11, 12 and 13. Similar
to the I2 C case, once SPI is activated these pins cannot be used for other purposes
[6].
3
CHAPTER 2. THEORY
2.2 DC motors
DC motors are controlled by adjusting the voltage supplied to the motor. The
relation between the speed of the motor and supplied voltage is given by the equation
UA = k2 Φω + RA IA , (2.1)
M = k2 ΦIA . (2.2)
Here, M denotes the torque [7]. Combining equations (2.1), (2.2) and using the
rotational version of Newton’s second law results in the second order ordinary dif-
ferential equation (ODE)
k2 Φ (k2 Φ)2
θ̈ = UA − θ̇ (2.3)
JRA JRA
describing the rotation of the motor, where J is the moment of inertia of the motor
axle. As can be seen by studying equation (2.3) closely, supplying a negative voltage
to the motor will accelerate the motor in the opposite direction.
2.3 H-bridges
4
2.4. POTENTIOMETERS
𝑆𝑆1 𝑆𝑆3
𝑈𝑈𝐷𝐷
+ 𝑈𝑈𝐴𝐴
𝑆𝑆2 𝑆𝑆4
If switches S1 and S4 are the only ones conducting current, the motor will spin
in the normal direction, but if these are turned off and S2 and S3 are turned on,
the motor will spin in the opposite direction. The switching is actually done with
transistors which can be turned on or off by sending a signal [7].
2.4 Potentiometers
5
CHAPTER 2. THEORY
The outer terminals (1) and (2) connected to the resistive element in Figure 2.2
are connected to power and ground respectively when used in applications such
as rotated angle measurements. For these applications, the middle terminal (3) is
connected to the wiper acting as the data port from which voltage readings are
made. Depending on the output voltage, the angle of the wiper, and thus the angle
of the shaft, can be calculated.
2.5 Accelerometers
Accelerometers are electromechanical components that measure the acceleration
that acts on their assigned axis. This means that an accelerometer at rest with an
axis of measurement trained straight up would measure an acceleration of 1G, equal
to the gravitation of the Earth. Note however that the direction of the acceleration
is not the same as the attacking force, but rather the direction of the normal force
due to the attacking one. As such, all measurements need to have their sign switched
if the direction of attacking forces, and consequently acceleration, is required.
6
2.6. GYROSCOPES
2.6 Gyroscopes
Traditional gyroscopes are spinning discs whose orientation due to the law of con-
servation of angular momentum are unaffected by any rotation of the mount on
which it sits. Because of this, they can be utilized to determine a change in ori-
entation of, for example, an airplane. In addition to measuring the actual tilt of
the device, a gyroscope can also be employed to measure the rate of rotation. This
can be achieved by restricting the gyroscopes’ freedom of movement , which due to
the Coriolis effect results in a force where the gyro is restricted. By measuring this
force the rate of rotation can then be derived.
In modern smaller scale electronics, the gyroscope usually takes the form of a
MEMS, utilizing a similar, although modified, setup as the accelerometers in the
above section. Instead of using a rotating disk, these MEMS use a vibrating mass
to achieve the same effect [10].
For example, in the case of angular measurements using a gyroscope and an ac-
celerometer, the gyroscope only produces data that is good in the short term. This
is due to the drift in the long term which is caused by the integration of errors,
whilst the accelerometer only produces usable data in the long term, due to the
low-pass filtering it has to go through [12]. Combining these two signals in such
a way that the sum of their respective contribution equals to one, a measurement
that is both fast and drift free is achieved.
7
CHAPTER 2. THEORY
This differential equation was needed for later use in creating the automatic control
system in charge of balancing the bicycle, and also to analyze the physical limits
involved.
The following analysis has been kept fairly simple, meaning a more in-depth anal-
ysis of the system could lead to better results. For example, the whole bicycle is
considered to be rigid, and the self-balancing force originating from the wheels’ ro-
tation has been left out of the analysis. Therefore, their effects have not been taken
into consideration in the derived equations.
𝑙𝑙𝑏𝑏 𝑙𝑙𝑓𝑓
𝑧𝑧
𝑦𝑦
𝑥𝑥
𝐹𝐹𝐿𝐿
ℎ𝑔𝑔
𝑁𝑁𝐵𝐵 𝑚𝑚𝑚𝑚 𝑁𝑁𝐹𝐹
Figure 2.3. Forces acting on a bicycle during acceleration or braking, as seen from
the side. Created using Microsoft PowerPoint.
↑: Nf + Nb − mg = 0 (2.4)
G : hg FD + lf NF − 2hg FR − hg FB = 0 (2.6)
8
2.8. MECHANICS OF AN ELECTRIC BICYCLE
FR = CR N (2.8)
where N is the normal force against the ground and CR is the coefficient of rolling
resistance.
𝑟𝑟𝑏𝑏
Figure 2.4. Geometry relating the different tracks of a bicycle. Created using
Microsoft PowerPoint.
rb
tan (90° − θ) = ⇒ rb = L cot θ, (2.9)
L
where L = lf + lb is the total length between the ground contact points of the tyres.
The radius of curvature for the bicycle’s centre of mass is now easily calculated
9
CHAPTER 2. THEORY
q
rg = lb2 + L2 cot2 θ. (2.10)
q
lb2 + L2 − lb2 cos2 θ
rg = . (2.11)
sin θ
Now, rg will be negative for negative values of θ, indicating a left turn, and positive
for positive values of θ, indicating a right turn.
𝑧𝑧
𝑥𝑥
𝑦𝑦
ℎ𝑔𝑔
𝐹𝐹𝐶𝐶
𝜑𝜑
𝑁𝑁𝐹𝐹 + 𝑁𝑁𝐵𝐵
𝑚𝑚𝑚𝑚
𝐹𝐹𝑓𝑓𝑓𝑓 + 𝐹𝐹𝑓𝑓𝑓𝑓
Figure 2.5. Forces acting on a bicycle during a left turn, as seen from behind.
Created using Microsoft PowerPoint.
10
2.9. AUTOMATIC CONTROL
Using the rotational version of Newton’s second law at the point where the tyre
contacts the ground yields
where ϕ is the lean angle, JL is the moment of inertia of the bicycle around the
ground contact point and
ẏ 2
FC = −m (2.13)
rg
is the centrifugal force due to the bicycle having a circular motion. The reason for
the negative sign in equation (2.13) is to make sure that the centrifugal force points
in the right direction. Since the bicycle in Figure 2.5 is turning to the left, rg will
be negative because of how the steering angle was defined. The reasoning behind
defining the angles this way is so that positive values on both θ and ϕ means "to
the right". Combining equations (2.11), (2.12) and (2.13) results in
hg mg hg m
ϕ̈ = sin ϕ − q ẏ 2 sin θ cos ϕ. (2.14)
JL JL lb + L2 − lb cos2 θ
2 2
An analysis of the above equations leads to the realization that in order to balance
the bicycle when it is tilting, it needs to turn in the same direction as the tilt. This
will cause a centrifugal force with a magnitude that depends on bicycle speed and
steer angle, pointing in the opposite direction. By choosing the right combination
of steer angle and bicycle speed, the tilting acceleration can be canceled out or
reversed.
d2 ϕ hg mg v 2 mhg
≈ T1 (v) = ϕ − θ. (2.15)
dt2 JL JL L
The error of this model is shown in Figure 2.6, where there are large relative errors
for some combinations of ϕ and θ.
11
CHAPTER 2. THEORY
20 30 4050 0 0
80 150
67
20
0
100
90000
435000
60 0
90
15
0
120
80
18
7
70
60
50
40
60 30
20
10 05000
1
5 021761590800000 10
0
40 2 4300
1 1
30
1 20
10
20 20 1
10 10
30
20
Phi (deg)
1
0
-20 1 10
30 1 1 20
10
1 1
20 2 0
0 1
10
-40 340 0
0
560700000 025
30
10 1
18910520 10
70605040 30 0
2
20
-60 30
40
50
60
100
90 70
87000
3200
80
5400
0
190
100
0
0
15
-80 50 20 150
300 2 200
250
300
-80 -60 -40 -20 0 20 40 60 80
Theta (deg)
Figure 2.6. Relative error due to linearization for different combinations of lean (ϕ)
and steer angle (θ). Created using MATLAB.
Using the linearized model, a simple state space model can be derived using the
following method [13]:
x1 = ϕ (2.16)
x2 = ϕ̇, (2.17)
then
x˙1 = ϕ̇ = x2 (2.18)
mhg g mhg v 2
x˙2 = ϕ̈ = x1 − θ, (2.19)
JL JL L
12
2.9. AUTOMATIC CONTROL
0 1
" #
A= mhg g (2.20)
JL 0
0
" #
B (v) = mhg v 2 (2.21)
− JL L
h i
C= 1 0 . (2.22)
where x is our state vector, ϕref is the desired lean angle and L is the feedback
vector which will be constructed by choosing the placement of the poles. The poles
of the closed system is given by the eigenvalues of the matrix A − BL and therefore
the poles are the solution to the equation
s
mhg v 2 m2 h2g v 4 2 mhg g mhg v 2
λ= l2 ± i − l − − l1 . (2.25)
2JL L 4JL2 L2 2 JL JL L
mhg v 2
Re(λ) = l2 , (2.26)
2JL L
therefore
2JL L
l2 = Re(λ). (2.27)
mhg v 2
13
CHAPTER 2. THEORY
s
mhg g mhg v 2
Im(λ) = −Re(λ)2 − − l1 . (2.28)
JL JL L
JL L mhg g
l1 = − Im(λ)2 + Re(λ)2 + (2.29)
mhg v 2 JL
h i
mhg g
L = − mh
JL L
gv
2 Im(λ)2 + Re(λ)2 + JL
2JL L
mhg v 2
Re(λ) , (2.30)
where the 2 poles λ can be chosen and v is the current speed of the bicycle.
0 1
" #
AS = (k Φ)2 , (2.31)
0 − JS2RASS
0
" #
BS = (k2 Φ)S , (2.32)
JS RAS
h i
CS = 1 0 , (2.33)
where the subscript S specifies that the variables belong to the motor controlling the
steering. As this regulator is time-invariant, the feedback vector LS was calculated
by usage of MATLAB’s place() function.
14
2.10. THE RUNGE-KUTTA 4-METHOD
y 0 = f (t, y)
(
(2.34)
y (0) = y0
h
yi+1 = yi + (k1 + 2k2 + 2k3 + k4 ) (2.35)
6
k1 = f (ti , yi ) , (2.36)
h h
k2 = f ti + , yi + k1 , (2.37)
2 2
h h
k3 = f ti + , yi + k2 , (2.38)
2 2
y = f (t, y, y )
00 0
y(0) = y 0 (2.40)
y 0 (0) = y 0
0
15
CHAPTER 2. THEORY
let
" #
y
u= , (2.41)
y0
then
" # " #
du y0 u2
= 00 = = F (u) , (2.42)
dt y f (t, u1 , u2 )
dt = "
F (u)
du
(2.43)
#
y(0)
u0 = y 0 (0)
has been given, which can be solved using the Runge-Kutta 4 method.
16
Chapter 3
Demonstrator
A prototype unit was constructed in order to verify the theory and to perform
experiments to answer the research questions.
3.1 Simulation
A simulation was carried out by solving equations (2.14) and (2.3) numerically using
the Runge-Kutta 4 method in MATLAB. One more differential equation was also
solved describing the bicycle’s forward acceleration. The written MATLAB code
can be found in appendix C. The developed regulators were implemented in the
simulation to test them in theory. The simulation was also used to test if different
motors available for purchase would have adequate performance.
Figure 3.1 shows the outcome of different events and bicycle commands. In this
simulation, the bicycle is already up to speed (7 km/h) at t = 0. At t = 1 s, the
bicycle is given the command to turn left by changing the lean angle reference to
−15°. At t = 2 s, randomly distributed disturbing forces are introduced for the
rest of the simulation. These are biased to the left for 3 seconds and to the right
thereafter, creating a simplified model of shifting wind. At t = 3 s, the bicycle is
commanded to increase speed to 12 km/h. At t = 6 s, the bicycle is commanded
to turn to the right. As can be seen in the forces plot, the simulation predicts that
tyres will be a problem as the friction exceeds the limit when the random forces are
introduced.
17
CHAPTER 3. DEMONSTRATOR
6
)
1 3000
2
10
Speed (km/h)
4
y (m)
0.5 2000
5
2
0 1000
Speed
Reference speed
0
-0.5 0 0
0 2 4 6 8 0 2 4 6 8 -2 0 2 4 0 2 4 6 8
Angles
40
Lean angle
20 Steer angle
Reference steer angle
Reference lean angle
Angles (deg)
-20
-40
0 1 2 3 4 5 6 7
Time (s)
Forces
20
Disturbance
15 Friction front tire
Friction rear tire
-5
0 1 2 3 4 5 6 7 8
Time (s)
Figure 3.1. Simulating the bicycle system with different events and bicycle com-
mands. Created using MATLAB.
For the accelerometer and the gyroscope, the GY-521 MPU 6050 breakout board
was chosen, as it combines both components in a small package for a relatively low
price. The MPU 6050 chip also only requires two ports for transferring data from
18
3.3. ELECTRONICS
all six axes, meaning the freed up ports can be used for other purposes. As for
the specific break out board, the GY-521 was chosen due to it having the AD0-pin
included, which makes it possible to change the I2 C address, which is needed in
order to use more than one.
To measure the angle of the front wheel, the potentiometer WAL305 5K from Con-
telec was chosen because of its resolution of 0.3 degrees. The hole in its center was
also large enough for the motor shaft of the steering motor above to fit.
A simple photo micro sensor was used along with a 3D-printed encoder wheel to
measure the velocity of the bicycle.
Finally, the pulley and driving belt were chosen after some simulation and estimation
of the required speeds of the bicycle, which resulted in a desired drive ratio of 4.
3.3 Electronics
In addition to the sensors, motor drivers and the Arduino Uno, two simple circuit
boards were constructed. One power supply board which distributes the power to
all components and one user interface board which has two buttons and five LEDs.
The circuitry for both boards and the wiring of all the electrical components are
available in appendix A.
The power supply board has three 12 V output connectors which supply power
to the motors and nine 5 V output connectors that supply power to the sensors
and the Arduino. The input to the board is 12 V from the battery bank, and an
LM7805 regulates the voltage down to 5 V. On each side of the LM7805 there are
capacitors that help with stability and transient responses. It is the same circuit as
recommended in the data sheet [15], except that a 47 µF capacitor was used on the
input side instead of 33 µF, as there was one readily available during construction.
The interface board was created to be able to turn on or off the program at a given
time. This is done with the two buttons available on the board. The board also
contains five LEDs to be able to receive some sort of feedback, which for example
could be helpful when troubleshooting code.
19
CHAPTER 3. DEMONSTRATOR
3.4 Construction
Once the components needed were identified a prototype was modeled in Solid Edge
ST9. First, the size of the bicycle was decided on by choosing appropriate wheel
sizes, where limitations in the manufacturing process had to be considered. It was
decided that the wheel sizes would be 160 mm in diameter. The modeling then
started with an idea that the batteries should be located in the frame to keep the
center of mass around the middle of the bicycle. Mounts for a box to contain the
electronics were modeled at the top of the frame. Due to size limitations in 3D-
printing, the frame was split into two parts, and the rear part that holds the rear
wheel and driving motor was modeled later.
Focus was then shifted to finishing the steer assembly while considering availability
and price of components such as ball bearings. The result is shown in Figure 3.3,
where the steering DC motor is mounted on top of the steer assembly, held in place
by a cover. The angle sensor (linear potentiometer) that is mounted on the motor
axle is also visible.
20
3.4. CONSTRUCTION
Figure 3.3. CAD model of the steer assembly. Created using Solid Edge ST9.
After the steer assembly was finished, the rear part of the the frame was modeled,
shown in Figure 3.4, along with a mount for the driving motor. This mount included
rails so that the driving motor’s position could be adjusted to ensure proper tension
in the timing belt that transfers the torque to the rear axle.
Figure 3.4. CAD model of the rear part of the bicycle. Created using Solid Edge
ST9.
21
CHAPTER 3. DEMONSTRATOR
The completed CAD model is shown in Figure 3.5. For drawings of the 3D-printed
parts and an exploded assembly, refer to appendix B.
Figure 3.5. CAD model of the completed bicycle. Created using Solid Edge ST9.
Rendered in KeyShot 6.3.
All the brown parts and the black electronic box in the figure were 3D-printed on
an Ultimaker 2 with polylactic acid (PLA) as material. The wheels were created
by laser cutting acrylic, and the tyres were simply made by gluing rubber directly
onto the wheels. The torque transfer from the rear axle to the rear wheel is via two
collars glued to each side of the wheel. The same method was used to attach and
fix the pulley and the pulse code wheel to the rear axle. This method was probably
not ideal to create a long lasting or a serious construction, but the decision was
made to decrease model complexity, cost and save time. In all cases the glue used
was cyanoacrylate, usually called "super glue". The final construction is shown in
Figure 3.6.
22
3.5. EXPERIMENTAL SETUP
To reduce the risk of the demonstrator breaking during testing, mainly from falling
over and/or driving into walls, two thin ropes were fastened to the frame of the
bicycle. One rope was was attached at the front of the bicycle and another at the
back, both seen in Figure 3.6 above. This ensured that the bicycle could be lifted
in the case of danger. A section of code was also added to the Arduino, where one
of the accelerometers was utilized in such a way that a quick pull in the vertical
direction of the bicycle would turn off all motors.
Because of the nature of the chosen way of balancing, the bicycle had to reach a
sufficient velocity before any actual balancing could realistically be performed. The
initial idea was to simply use the above mentioned ropes to keep the bicycle upright
until a hard coded velocity had been reached. However, this particular approach
was harder than initially estimated due to the difficulties with keeping the bicycle
upright while maintaining an appropriate amount of friction against the ground.
23
CHAPTER 3. DEMONSTRATOR
To solve this issue, a single support wheel was constructed and installed on the
right outermost part of the rear axle. This wheel was made to be slightly smaller
than the regular wheels, so that when the bicycle reached a sufficient velocity and
balance regulation was initiated, it could drive without the support wheel touching
the ground. The resulting size of the wheel was such that when resting on the
support wheel, the bicycle tilted slightly below 10 degrees.
The experiments were mainly conducted in a corridor with plastic flooring, with a
few test runs being done on stone flooring as well as asphalt.
For the most part, the testing was done in groups of a few test drives at a time,
after which the data was analyzed in MATLAB. Potential problems and areas of
improvement both when it comes to construction and regulator variables were de-
termined. Improvements were implemented on these areas and another group of
tests were conducted. When the Arduino code was finished and most parameters
were tweaked, the support wheel could be removed. The bicycle was then held
upright for approximately one second while it accelerated up to speed, after it was
released to balance on its own.
24
Chapter 4
Results
The results from the experiments were mixed. On some occasions, the bicycle man-
aged to keep itself balanced. On others it seemed that tyre friction was a limiting
factor. Some times the Arduino locked up, which caused the PWM signals to stop
working. This set the motor speeds to either be fully on or fully off, sometimes
resulting in damage to the bicycle fork.
Figure 4.1 shows a typical run where the bicycle exceeds the frictional limit between
the tyres and the flooring. This was verified by a frame-by-frame analysis of a
recording of the test run. This particular test run was conducted on dusty plastic
flooring. The bicycle was lifted at approximately 1.5 seconds to prevent damage,
hence the increase in speed. The lean angle starts at approximately 8 degrees due
to the fact that this run utilized the support wheel on the right side of the bicycle
until it got up to speed. The steer reference angle was initially -4 degrees, as a
counter measure to the support wheel dragging the bicycle to the right.
25
CHAPTER 4. RESULTS
Angles
40
Angles (deg) 20
0
Lean angle
-20
Lean reference
Steer angle
-40
Steer reference
-60
0 0.5 1 1.5 2 2.5 3
Time (s)
Speed
15
Speed (km/h)
10
5
Speed
Speed reference
0
0 0.5 1 1.5 2 2.5 3
Time (s)
Figure 4.1. A typical experimental result where the bicycle loses friction. Created
using MATLAB.
Figure 4.2 below shows data from one of the longest test runs conducted where
the bicycle managed to balance itself. The test was carried out on parquet flooring
without the use of the support wheel. The bicycle was held upright until the balance
regulator was turned on. This was programmed to happen when the speed passes
6 km/h, as can be seen at around the 0.8 second mark in the plot.
Angles
60
Lean angle
40 Lean reference
Angles (deg)
Steer angle
20 Steer reference
-20
0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5
Time (s)
Speed
8 15
Speed (km/h)
6 Speed
Voltage (V)
Speed reference 10
4 Drive motor voltage
5
2
0 0
0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5
Time (s)
Figure 4.2. A typical experimental result where the bicycle managed to keep itself
balanced. Created using MATLAB.
26
Figure 4.3 below is a simulation using the same initial conditions as the experimental
setup used in Figure 4.2 for comparison.
Angles
40
Lean angle
Lean reference
20
Angles (deg)
Steer angle
Steer reference
0
-20
-40
0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5
Time (s)
Speed
10 15
Speed (km/h)
Voltage (V)
10
5 Speed
Speed reference
5
Drive motor voltage
0 0
0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5
Time (s)
Figure 4.3. Results of simulating the bicycle, matching the initial values of the
experimental run in Figure 4.2. Created using MATLAB.
27
Chapter 5
5.1 Discussion
Firstly, the general outcome of testing (focusing on Figure 4.1) will be addressed.
In this figure, the bicycle fell a few moments after the regulator was initiated. After
filming a few cases of this occurring and doing a frame by frame analysis of what
was happening, the most likely cause of this issue was insufficient friction between
the wheels and the ground. In order to straighten itself up from leaning on the
support wheel, the bicycle needed to turn right first so as to create a centrifugal
force to pull the bicycle up. To stop the bicycle from tipping over too much on the
other side, it naturally had to turn left which can also be seen in aforementioned
figure. When examining this and similar cases in the video material, the bicycle
can be seen to continue traveling in whatever direction it was heading prior to the
change in steer angle, solidifying the suspicion that friction is the main problem in
these cases.
The wheels were a challenge to construct in general, not only in terms of trying to
mimic the friction of an actual tire. When laser cutting them from plexiglas, the
rim of the wheels ended up with a slight sloped face, as the laser did not cut through
the entire 5 mm thickness at once. While this might not be a major issue, it might
very well still be a contributing factor to the issues of the system. Another possible
issue with the wheels is the fastening of rubber on them. This rubber fastening
proved to be more difficult than anticipated which resulted in a somewhat uneven
amount of glue being placed around the edge, making the wheels not as smooth as
they ought to be. Another possible reason is that the wheels do not have proper
tires. As such they are not filled with air as actual bicycle tires are, meaning they
do not provide any dampening of vibrations from the ground, but rather transfer
them straight to the rest of the bicycle and consequently the sensors.
29
CHAPTER 5. DISCUSSION AND CONCLUSIONS
design, it flexes upward more than can be considered reasonable due to the weight
of the demonstrator. Not only does this lead to a lot of unnecessary vibrations due
to it flexing back and forth during driving, but it also broke three times during
testing.
Despite the wheels not providing any dampening, there were other sources of vibra-
tions. For example, the drive and steering motor contribute to a lot of vibrations,
both of which could have been isolated better. The overall small size of the demon-
strator also contributed to more severe vibrations. This is because any smaller
cavities or bumps in the flooring were much bigger in relation to the demonstrator
as opposed to what would be the case with an actual bicycle. All of these vibrations
combined with general sensor noise led to a need to filter some signals. However,
the signals were still quite noisy even after processing them, which in turn might
have led to increased instability of the bicycle.
Despite the above problems, the bicycle did manage to balance itself sometimes, as
can be seen in test runs such as Figure 4.2. Of course, this particular test was fairly
short, as the bicycle had to be stopped before it crashed into a wall. Regardless,
given the behavior of the system in the graph as well as the observations of how it
looked from the outside, it seems very likely that it would have continued balancing a
fair bit longer, given enough free space to drive on. This points toward the regulator
and the underlying idea being correct. Something that might prove problematic in
the regulator is the spots in the domain with large relative errors visible in Figure
2.6. These unfortunately seem to coincide with the desired lean angles and their
appropriate steer angles. However, because the system won’t stay in any lean/steer
angle configuration for more than a very short moment, these errors should not
have too big of an impact for small values of steer and lean angles. In Figure 3.1,
showing a simulation of the system, the bicycle can be seen passing one of these
spots around the 2 second mark. The error spikes but quickly reduces again.
The biggest issue in determining the feasibility of the constructed system, even if
the above problems are ignored and only the good test runs are considered, is the
unfortunately short distances the bicycle has been allowed to run in. This is in
part another byproduct of the small stature of the demonstrator. As stated earlier,
even relatively small imperfections in the ground had a much bigger impact on the
system than they would have had on an actual real-sized bicycle. Because of this,
the location in which testing could have been conducted became limited, as large
halls with clear floors made of a material with good friction, were hard to come by.
Using a real bicycle for the testing was unfortunately not possible however, because
of the restricted nature of the available budget of around 1000 Swedish crowns. This
budget was slightly exceeded to create this demonstrator.
30
5.2. CONCLUSION
Arduino via USB during testing, an SD card (as stated in Section 3.5) for data to be
written onto had to be installed. The problem with this particular solution was that
the library needed to write onto the card takes up around 30-40 % of the dynamic
memory of the Arduino Uno. This led to memory issues and possibly instability of
the microcontroller.
Another component that caused problems was the MPU 6050, particularly the one
assigned as the lean angle measurer, which caused the Arduino to freeze fairly
frequently. The reason behind this isn’t entirely clear, but we suspect that it is
caused by disturbances in the data transfer between the Arduino and MPU through
the I2 C bus. This bus is designed primarily for short distance communication only.
The disturbances in question could originate from the PWM signals sent to the
drive motor, whose cables lie close to the communication cables of the MPU.
The final issue that made testing and tweaking of the system difficult was the batter-
ies and their supplied voltage. Because the bicycle in its current state pulls current
straight from the batteries without a voltage regulator in-between, the voltage sup-
plied to the motors changes as the batteries become increasingly drained. Voltage
supply variation affects the speed of the motors, which in turn affects the system
as a whole, and thus, seemingly promising regulator parameters would have to be
changed after a while.
5.2 Conclusion
The system has quite a few issues that makes balancing difficult, mainly the friction
with the ground. This stemmed from bad wheels and a low weight of the system.
The actual regulator however, does seem to work fairly well. This is because when
the bicycle did keep its balance, it seemingly would have continued to do so given
enough space for it to move in. More testing has to be conducted before a more
decisive conclusion can be drawn, preferably done on a larger demonstrator.
Firstly, and perhaps most importantly, simply using an actual bicycle, or at least
a bigger demonstrator for testing could fix a lot of the bigger problems with the
system. The increased weight of the system would increase its grip with the ground
significantly, potentially eliminating or at least decreasing the risk of the wheels
slipping. Having proper wheels with air-filled tires would not just provide some
well needed damping, but would decrease the system vibrations caused by smaller
31
CHAPTER 5. DISCUSSION AND CONCLUSIONS
Electronics wise, the components used in this demonstrator should work fine for the
most part even in an up-scaled model. One exception would be the potentiometer
used for angular readings on the front wheel which would have to be replaced by
a larger version. It is technically possible to use the accelerometer/gyro already
situated on the front wheel to calculate the steer angle, which is something that
was initially tested on this demonstrator. This is not recommended however, as the
implementation of this was prone to a lot of errors on top of having a restricted
domain of allowed steer and lean angles. Some kind of potentiometer or encoder
solution would therefore be preferred. Also, to avoid memory issues in the micro
controller, a board such as the Arduino Mega or a Raspberry Pi would be recom-
mended, even though a Uno does seem to work, albeit barely with the SD library
installed.
Regarding the issues with the Arduino freezing due to the MPU, a simple up-
scaling of the system could possibly fix this as well. That is, if the issue is related to
disturbances in the communication due to PWM signals. An upscaling would mean
that the wires could be more easily separated. Otherwise, using shielded cables
could solve these issues.
Finally, software wise, there might be room for further optimization in the code.
In its current state however, it has been stripped of most, if not all, unnecessary
processes. Also, a change from the complementary filter to a Kalman filter would
likely help to improve the overall accuracy of the measured lean angle.
32
Bibliography
33
BIBLIOGRAPHY
[14] T. Sauer, Numerical analysis, second edition, pearson new international edi-
tion.. ed. Harlow, Essex: Pearson, 2014.
34
35
Driving motor Photomicro-
GY-521 GY-521 SD card
WAL 305 sensor
module
2
1
3
Appendix A
M
GND
OUT
VCC
GND
INT
GND
INT
VCC
VCC
SCL
SCL
SDA
XDA
XCL
AD0
SDA
XDA
XCL
AD0
GND
VCC
MISO
MOSI
SCK
CS
0 A5
VIN
A4
GND
1
ICSP
2 A3
Motor B
Motor A
~3 A2 Interface board
Olimex 4 A1
~5 A0
BB-VNH3SP30 ~6 WHITE 100 Ω
100 Ω
2
8
1
BLUE
3
4
5
6
7
7 Vin
GND GREEN 150 Ω
12 V out connections
8 GND YELLOW 150 Ω
9 5V
RED 150 Ω
3.3V
36
10
11 RESET
Arduino Uno R3
7
6
5
4
3
1
8
2
AREF OK
IN GND OUT SDA +5V
+
SCL 10 kΩ
BB-VNH3SP30
connector
47 µF
On/off switch
100 nF
10 kΩ
Olimex
DC Jack
USB Port
Motor A
Motor B
VIN
GND
12 V in connector
GND pins
GND
+12V
+5V D-
GND D+
Electrical circuits and wiring
+
Steering motor Riderless self-balancing bicycle
Battery bank Electrical circuits and wiring
Appendix B
CAD drawings
B.1 Frame
38
B.1. FRAME
39
APPENDIX B. CAD DRAWINGS
40
B.3. FORK
B.3 Fork
41
APPENDIX B. CAD DRAWINGS
42
B.5. DRIVE MOTOR COVER
43
APPENDIX B. CAD DRAWINGS
44
B.7. PULSE CODE WHEEL
45
APPENDIX B. CAD DRAWINGS
46
Appendix C
47
APPENDIX C. MATLAB-CODE FOR SIMULATION
48
102 figure ;
103 abs_lin_error = abs ( f2 (x , y , v_test ) - T1 (x , y , v_test ) ) ;
104 rel_lin_error = abs_lin_error ./ abs ( f2 (x , y , v_test ) ) * 100;
105 contour ( x *180/ pi , y *180/ pi , rel_lin_error , ’ Showtext ’ , ’ on ’ , ’ Levellist ’ , [1 10 20 30 40
50 60 70 80 90 100 150 200 250 300]) ;
106 title ([ ’ Relative linearization error at v = ’ num2str (3.6* v_test ) ’ kph (%) ’ ]) ;
107 xlabel ( ’ Theta ( deg ) ’) ;
108 ylabel ( ’ Phi ( deg ) ’) ;
109 zlabel ( ’ Error ’) ;
110 grid on ;
111
112 % % Controller stuff
113 s = tf ( ’s ’) ;
114
115 % Cykel
116 A_cykel = [0 , 1;
117 m * g * h_g /( J_L ) , 0];
118 B_cykel = @ ( v ) [0;
119 -m * v ^2* h_g / ( J_L * L ) ];
120 C_cykel = [1 0];
121
122 PP_Im = 6;
123 PP_Re = -7;
124
125 L_cykel = @ ( v ) [ - J_L * L /( m * h_g * v ^2) * ( PP_Im ^2 + PP_Re ^2 + h_g * m * g / J_L ) , 2* J_L * L * PP_Re /
( m * h_g * v ^2) ];
126 l0_cykel = @ ( v ) - J_L * L / ( m * h_g * v ^2) * ( PP_Im ^2 + PP_Re ^2) ;
127 sys_cykel_pp = @ ( v ) ss ( A_cykel - B_cykel ( v ) * L_cykel ( v ) , B_cykel ( v ) , C_cykel , 0) *
l0_cykel ( v ) ;
128
129 v_vec = [5/3.6 7/3.6 9/3.6 10/3.6 15/3.6];
130
131 figure ;
132 t_cykel = 0:0.01:15;
133
134 for n = 1: length ( v_vec )
135 [ phi_cykel , t_cykel , x_cykel ] = lsim ( sys_cykel_pp ( v_vec ( n ) ) , 5* pi /180* ones (1 , length
( t_cykel ) ) , t_cykel ) ;
136 info_cykel = stepinfo ( phi_cykel , t_cykel ) ;
137
138 thet aref_cyk el = zeros ( length ( t_cykel ) , 1) ;
139 for j = 1: length ( theta ref_cyke l )
140 theta ref_cyk el ( j ) = - L_cykel ( v_vec ( n ) ) * x_cykel (j , :) ’ + l0_cykel ( v_vec ( n ) ) ;
141 end
142
143 subplot (2 , 3 , n ) ;
144 plot ( t_cykel , phi_cykel * 180/ pi ) ;
145 hold on ;
146 plot ( t_cykel , th etaref_ cykel * 180/ pi ) ;
147 title ([ ’ Step response of bike system at v = ’ num2str ( v_vec ( n ) * 3.6) ’ km / h ’ ]) ;
148 grid on ;
149 xlabel ( ’ Time ( s ) ’) ;
150 ylabel ( ’ Angle ( degrees ) ’) ;
151 plot ([ info_cykel . SettlingTime info_cykel . SettlingTime ] , [ info_cykel . SettlingMin
info_cykel . SettlingMax ] , ’k ’) ;
152 text ( info_cykel . PeakTime , info_cykel . Peak * 1.05 * 180/ pi , [ ’ Overshoot : ’ num2str (
info_cykel . Overshoot , 4) ’ % ’ ]) ;
153 text ( info_cykel . RiseTime , 0.5 , [ ’ Rise time : ’ num2str ( info_cykel . RiseTime , 4) ’ s ’ ])
;
154 text ( info_cykel . SettlingTime , info_cykel . SettlingMin * 180/ pi , [ ’ Settling time (2%) :
’ num2str ( info_cykel . SettlingTime , 4) ’ s ’ ]) ;
155 legend ( ’ Phi ( lean angle ) ’ , ’ Requested theta ( steer angle ) ’ , ’ location ’ , ’ southeast ’)
;
156 end
157
158 subplot (2 , 3 , 6) ;
159 pzmap ( sys_cykel_pp ( v_vec (1) ) ) ;
160 title ( ’ Pole placement of bike system ’) ;
161
162 % Motor , steering
163 A_motor_s = [0 , 1;
164 0 , - i_s ^2* k2phi_S ^2/( J_S * R_AS ) ];
165 B_motor_s = [0;
166 i_s * k2phi_S /( J_S * R_AS ) ];
49
APPENDIX C. MATLAB-CODE FOR SIMULATION
50
232 % Variables - initial values
233 U_AD = 0.0001; % Voltage over driving motor ( if set to 0 things
break ....)
234 U_AS = 0; % Voltage over steering motor
235 theta_ref = 0; % Desired steering angle
236 FDist = 0; % Disturbing force
237 Cr = 0.004; % Rolling resistance ( set to 0 to not simulate )
238 s i m u l a t e _ p h i _ a c c e l e r a t i o n = 1; % Indicates whether we should simulate falling over
or not
239 s i m u l a t e _ a i r _ r e s i s t a n c e = 1; % Indicates whether we should simulate air
resistance or not
240 s i m u l a t e _ d r i v e _ f o r c e = 1; % Indicates whether we should simulate driving force
241 phi_ref = 0; % Desired lean angle
242 v_ref = 7/3.6; % Desired speed ( m / s )
243 regulat e S t e e ri n g = 0; % Don ’ t regulate steering initially
244 ti meA tt a i n e d S p e e d = 9999999; % Variable for logging the time that the bicycle
attained a certain speed
245
246 % Functions that remain constant throughout simulation
247 r_g = @ ( theta ) sqrt ( l_b ^2 + cos ( theta ) .^2*( L ^2 - l_b ^2) ) ./ sin ( theta ) ; % Curve
radius
248 F_D = @ ( U_AD , v ) i_d * eta / r_d *( k2phi_D * ( U_AD - k2phi_D * i_d * v / r_d ) / ( R_bank + R_AD +
R_FET ) ) ; % Driving force
249 F_B = 0; %
Braking force
250 F_L = @ ( v ) 1/2* rho * A_f * C_d * v ^2; % Air
resistance
251 N_B = @ ( U_AD , v ) l_f / L * m * g + h_g / L * F_D ( U_AD , v ) ; % Normal
force , rear tire
252 N_F = @ ( U_AD , v ) l_b / L * m * g - h_g / L * F_D ( U_AD , v ) ; % Normal
force , front tire
253 F_Rb = @ ( U_AD , v ) sign ( v ) * Cr * N_F ( U_AD , v ) ; %
Rolling resistance , rear tire
254 F_Rf = @ ( U_AD , v ) sign ( v ) * Cr * N_B ( U_AD , v ) ; %
Rolling resistance , front tire
255 F_C = @ (v , theta ) -m * v ^2/ r_g ( theta ) ; %
Centrifugal force
256 F_G = m * g ; %
Gravitational force
257
258 % Runge - Kutta -4 setup
259 h = 0.015; % Step length Runge - Kutta 4
260 t = 0: h :8; % Simulation time vector
261 s0 = 0; % Initial position
262 v0 = 7/3.6; % Initial speed
263 phi0 = 0; % Initial lean angle
264 omega_phi0 = 0; % Initial lean rotational speed
265 theta0 = 0; % Initial steer angle
266 omega_theta0 = 0; % Initial steer rotational speed
267
268 U = zeros (6 , length ( t ) ) ; % Allocate memory for the solution
269 U (: , 1) = [ s0 ; v0 ; phi0 ; omega_phi0 ; theta0 ; omega_theta0 ;];
270
271 % Allocate vectors that store information about the simulation
272 Acceleration = zeros (1 , length ( t ) ) ;
273 Speed = zeros (1 , length ( t ) ) ;
274 PhiSpeed = zeros (1 , length ( t ) ) ;
275 Gamma = zeros (1 , length ( t ) ) ;
276 GammaSpeed = zeros (1 , length ( t ) ) ;
277 Distance = zeros (1 , length ( t ) ) ;
278 Phi = zeros (1 , length ( t ) ) ;
279 PhiAcce l er at io n = zeros (1 , length ( t ) ) ;
280 Theta = zeros (1 , length ( t ) ) ;
281 ThetaSpeed = zeros (1 , length ( t ) ) ;
282 Th eta Ac c e l e r a t i o n = zeros (1 , length ( t ) ) ;
283 L in e ar i z a t i o n E r r o r = zeros (1 , length ( t ) ) ;
284 XPos = zeros (1 , length ( t ) ) ;
285 YPos = zeros (1 , length ( t ) ) ;
286 Beta = zeros (1 , length ( t ) ) ;
287 ForceDriving = zeros (1 , length ( t ) ) ;
288 ForceBraking = zeros (1 , length ( t ) ) ;
289 ForceDisturb = zeros (1 , length ( t ) ) ;
290 ForceAirResi st = zeros (1 , length ( t ) ) ;
291 F o r c e R o l l i n g R e s i s t F r o n t = zeros (1 , length ( t ) ) ;
51
APPENDIX C. MATLAB-CODE FOR SIMULATION
52
361 Fo r c e F r i c t i o n R e a r ( j ) = F_fb ( U_AD , Speed ( j ) , Theta ( j ) ) ;
362 F ri c t i o n L i m i t F r o n t ( j ) = N_F ( U_AD , Speed ( j ) ) * my_d ;
363 Fr i c t i o n L i m i t R e a r ( j ) = N_B ( U_AD , Speed ( j ) ) * my_d ;
364 V o l t a g e S t e e r i n g M o t o r ( j ) = U_AS ;
365 T o r q u e S t e e r i n g M o t o r ( j ) = i_s * k2phi_S / R_AS * ( U_AS - k2phi_S * ThetaSpeed ( j ) ) ;
366 C u r r e n t S t e e r i n g M o t o r ( j ) = T o r q u e S t e e r i n g M o t o r ( j ) / k2phi_S ;
367 P ow e r S t e e r i n g M o t o r ( j ) = T o r q u e S t e e r i n g M o t o r ( j ) * ThetaSpeed ( j ) ;
368 V o l t a g e D r i v i n g M o t o r ( j ) = U_AD ;
369 Torq ueRearAx le ( j ) = i_d * k2phi_D / R_AD * ( U_AD - k2phi_D * GammaSpeed ( j ) ) ;
370 T o r q u e D r i v i n g M o t o r A x l e ( j ) = k2phi_D / R_AD * ( U_AD - k2phi_D * GammaSpeed ( j ) ) ;
371 C u r r e n t D r i v i n g M o t o r ( j ) = T o r q u e D r i v i n g M o t o r A x l e ( j ) / k2phi_D ;
372 Po w e r D r i v i n g M o t o r ( j ) = T o r q u e D r i v i n g M o t o r A x l e ( j ) * GammaSpeed ( j ) ;
373 Refe renceSpe ed ( j ) = v_ref ;
374 ReferencePhi ( j ) = phi_ref ;
375 Refe renceThe ta ( j ) = theta_ref ;
376 SpeedError ( j ) = v_ref - Speed ( j ) ;
377
378 % Simulation logic begins here
379 if ( abs ( Phi ( j ) ) > pi /2) % Vehicle fell over
380 FD = 0; % There is no longer a driving force
381 Cr = 1; % Increase the rolling resistance so the vehicle comes
to a halt
382 s i m u l a t e _ p h i _ a c c e l e r a t i o n = 0; % Stop simulating the leaning part
383 U (4 , j ) = 0; % Alpha speed is now zero
384 end
385
386 % Check if friction was lost
387 % if ( F o r c e F r i c t i o n R e a r ( j ) > N_B ( U_AD , Speed ( j ) ) * my_d ) % Rear wheel traction
was lost
388 % break ;
389 % end
390 % if ( F o r c e F r i c t i o n F r o n t ( j ) > N_F ( U_AD , Speed ( j ) ) * my_d ) % Front wheel traction
was lost
391 % break ;
392 % end
393
394 % Automatic control begins here
395 delta_t = ( t ( j ) - t ( j - 1) ) ;
396
397 % Balancing regulator
398 theta_ref = - L_cykel ( Speed ( j ) ) *[ Phi ( j ) ; PhiSpeed ( j ) ] + l0_cykel ( Speed ( j ) ) * phi_ref
;
399 if theta_ref > 60* pi /180 % Dont request steering angles higher than a set
value
400 theta_ref = 60* pi /180;
401 elseif theta_ref < -60* pi /180
402 theta_ref = -60* pi /180;
403 end
404
405 % Steer motor regulator
406 U_AS = - L_motor_s *[ Theta ( j ) ; ThetaSpeed ( j ) ] + l0_motor_s * theta_ref ;
407
408 % Speed regulator ( cruise control )
409 U_AD = Kp * SpeedError ( j ) + Ki * delta_t * sum ( SpeedError ) + Kd *( SpeedError ( j ) -
SpeedError ( j - 1) ) / delta_t ;
410
411 if U_AS > 12 % Maximum voltage available for motors is U_bank
412 U_AS = 12;
413 elseif U_AS < -12
414 U_AS = -12;
415 end
416 if U_AD > U_bank
417 U_AD = U_bank ;
418 elseif U_AD < 0
419 U_AD = 0;
420 end
421
422 % Change some parameters over time
423 if ( t ( j ) > 1)
424 phi_ref = -15* pi /180;
425 end
426
427 if ( t ( j ) > 6)
428 phi_ref = 15* pi /180;
53
APPENDIX C. MATLAB-CODE FOR SIMULATION
429 end
430
431 if ( t ( j ) > 3)
432 v_ref = 12/3.6;
433 end
434
435 % Introduce some disturbances
436 if ( t ( j ) > 2 && t ( j ) < 5)
437 FDist = -1 + 0.5* rand () ;
438 elseif ( t ( j ) > 5)
439 FDist = 0.5 + rand () ;
440 else
441 FDist = 0;
442 end
443
444 end
445
446 % Plot results
447 figure ;
448 subplot (3 , 4 , 1) ;
449 plot (t , Acceleration ) ;
450 title ( ’ Acceleration ’) ;
451 ylabel ( ’ Acceleration ( m / s ^2) ’) ;
452 xlabel ( ’ Time ( s ) ’) ;
453 grid on ;
454
455 subplot (3 , 4 , 2) ;
456 plot (t , Speed * 3.6) ;
457 hold on ;
458 plot (t , Ref erenceSp eed * 3.6) ;
459 title ( ’ Speed ’) ;
460 xlabel ( ’ Time ( s ) ’) ;
461 ylabel ( ’ Speed ( km / h ) ’) ;
462 legend ( ’ Speed ’ , ’ Reference speed ’ , ’ location ’ , ’ southeast ’) ;
463 grid on ;
464
465 subplot (3 , 4 , 3) ;
466 line ( XPos , YPos , t ) ;
467 title ( ’ Position ’) ;
468 xlabel ( ’x ( m ) ’) ;
469 ylabel ( ’y ( m ) ’) ;
470 grid on ;
471 axis equal ;
472
473 subplot (3 , 4 , 4) ;
474 plot (t , L i n e a r i z a t i o n E r r o r ) ;
475 title ( ’ Linearization error ’) ;
476 xlabel ( ’ Time ( s ) ’) ;
477 ylabel ( ’ Relative error (%) ’) ;
478 grid on ;
479
480 subplot (3 , 4 , [5 6 7 8]) ;
481 plot (t , Phi *180/ pi ) ;
482 hold on ;
483 plot (t , Theta *180/ pi ) ;
484 plot (t , Ref erenceTh eta *180/ pi ) ;
485 plot (t , ReferencePhi *180/ pi ) ;
486 axis ([ t (1) t ( end ) -55 45]) ;
487 title ( ’ Angles ’) ;
488 xlabel ( ’ Time ( s ) ’) ;
489 ylabel ( ’ Angles ( deg ) ’) ;
490 grid on ;
491 legend ( ’ Lean angle ’ , ’ Steer angle ’ , ’ Reference steer angle ’ , ’ Reference lean angle ’ , ’
location ’ , ’ southeast ’) ;
492
493 subplot (3 , 4 , [9 10 11 12]) ;
494 % plot (t , ForceDriving ) ;
495 hold on ;
496 % plot (t , ForceBraking ) ;
497 plot (t , ForceDisturb , ’ Color ’ , [0 0.7 0]) ;
498 % plot (t , For ceAirRes ist ) ;
499 plot (t , ForceFrictionFront , ’ Color ’ , [0 0.3 0.7]) ;
500 plot (t , ForceFrictionRear , ’ Color ’ , [0.7 0 0]) ;
501 plot (t , FrictionLimitFront , ’ Color ’ , [0 0.3 1]) ;
54
502 plot (t , FrictionLimitRear , ’ Color ’ , [1 0 0]) ;
503 title ( ’ Forces ’) ;
504 xlabel ( ’ Time ( s ) ’) ;
505 ylabel ( ’ Force ( N ) ’) ;
506 grid on ;
507 legend ( ... % ’ Driving force ’ , ’ Braking force ’ ,
508 ’ Disturbance ’ , ...
509 ’ Friction front tire ’ , ’ Friction rear tire ’ , ...
510 ’ Friction limit front ’ , ’ Friction limit rear ’) ;
511
512
513 % Steering motor info
514 figure ;
515 subplot (3 , 3 , 1) ;
516 plot (t , V o l t a g e S t e e r i n g M o t o r ) ;
517 title ( ’ Voltage , Steering Motor ’) ;
518 xlabel ( ’ Time ( s ) ’) ;
519 ylabel ( ’ Voltage ( V ) ’) ;
520 grid on ;
521
522 subplot (3 , 3 , 4) ;
523 plot (t , C u r r e n t S t e e r i n g M o t o r ) ;
524 title ( ’ Current , Steering Motor ’) ;
525 xlabel ( ’ Time ( s ) ’) ;
526 ylabel ( ’ Current ( A ) ’) ;
527 grid on ;
528
529 subplot (3 , 3 , 7) ;
530 plot (t , V o l t a g e S t e e r i n g M o t o r .* C u r r e n t S t e e r i n g M o t o r ) ;
531 title ( ’ Electrical Power , Steering Motor ’) ;
532 xlabel ( ’ Time ( s ) ’) ;
533 ylabel ( ’ Power ( W ) ’) ;
534 grid on ;
535
536 subplot (3 , 3 , 2) ;
537 plot (t , T o r q u e S t e e r i n g M o t o r ) ;
538 title ( ’ Torque , Steering Axle ’) ;
539 xlabel ( ’ Time ( s ) ’) ;
540 ylabel ( ’ Torque ( Nm ) ’) ;
541 grid on ;
542
543
544 subplot (3 , 3 , 5) ;
545 plot (t , ThetaSpeed * 60 / (2* pi ) ) ;
546 title ( ’ Angular speed , Steering Axle ’) ;
547 xlabel ( ’ Time ( s ) ’) ;
548 ylabel ( ’ Angular speed ( rpm ) ’) ;
549 grid on ;
550
551 subplot (3 , 3 , 8) ;
552 plot (t , P o w e r S t e e r i n g M o t o r ) ;
553 title ( ’ Power , Steering Axle ’) ;
554 xlabel ( ’ Time ( s ) ’) ;
555 ylabel ( ’ Power ( W ) ’) ;
556 grid on ;
557
558 % Driving motor info
559 figure ;
560 subplot (3 , 3 , 1) ;
561 plot (t , V o l t a g e D r i v i n g M o t o r ) ;
562 title ( ’ Voltage , Driving Motor ’) ;
563 xlabel ( ’ Time ( s ) ’) ;
564 ylabel ( ’ Voltage ( V ) ’) ;
565 grid on ;
566
567 subplot (3 , 3 , 4) ;
568 plot (t , C u r r e n t D r i v i n g M o t o r ) ;
569 title ( ’ Current , Driving Motor ’) ;
570 xlabel ( ’ Time ( s ) ’) ;
571 ylabel ( ’ Current ( A ) ’) ;
572 grid on ;
573
574 subplot (3 , 3 , 7) ;
575 plot (t , V o l t a g e D r i v i n g M o t o r .* C u r r e n t D r i v i n g M o t o r ) ;
55
APPENDIX C. MATLAB-CODE FOR SIMULATION
56
649 sub2 . YAxis (2) . Color = [1 0 1];
57
Appendix D
Arduino C code
59
APPENDIX D. ARDUINO C CODE
60
104 // # define L_motor_s1 4 5 . 8 4 1 1 6 6 4 3 5 1 8 3 9 4 3 // Steer motor controller - Pole placement :
Im 15 , Re 30
105 // # define L_motor_s2 2 . 4 2 4 4 4 5 5 4 3 2 0 9 8 1 0 // Steer motor controller - Pole placement :
Im 15 , Re 30
106 // # define L_motor_s1 75.3833 // Steer motor controller - Pole placement :
Im 25 , Re 35
107 // # define L_motor_s2 2.8319 // Steer motor controller - Pole placement :
Im 25 , Re 35
108 # define L_motor_s1 1 0 1 . 8 6 9 2 5 8 7 4 4 8 5 3 2 // Steer motor controller - Pole placement :
Im 30 , Re 40
109 # define L_motor_s2 3 .2 3 9 39 9 61 3 16 8 6 // Steer motor controller - Pole placement :
Im 30 , Re 40
110 # define l0_motor_s L_motor_s1 // Static gain
111
112 // Other constants
113 # define l e a n _ g y r o _ p e r c e n t a g e 0.98 // Complementary filter setting ,
accelerometer contribution factor will be 1 - l e a n _ g y r o _ p e r c e n t a g e
114
115 // Data logging ( SD card ) objects
116 SdFat sd ;
117 SdFile dataFile ;
118
119 // Buffers for converting numerical values to strings when logging to file
120 char vBuffer [9];
121 char v_refBuffer [9];
122 char st e e r A n g l e B u f f e r [9];
123 char s t e e r A n g l e _ r e f B u f f e r [9];
124 char U_ASBuffer [9];
125 char U_ADBuffer [9];
126 char lea nA ng l eB uf fe r [9];
127 char l e a n A n g l e _ r e f B u f f e r [9];
128 char ssxBuffer [9];
129 char lsyBuffer [9];
130 char laxBuffer [9];
131 char lazBuffer [9];
132 char dtBuffer [9];
133
134 // State variables , initial values
135 float leanAngle = 0; // Lean angle
136 float steerAngle = 0; // Steer angle
137 volatile float v = 0; // Bicycle speed . Needs to be volatile
since it can change unexpectedly due to interrupts , otherwise compiler optimizations
might make wrong assumptions about this variable .
138 float U_AS = 0; // Steer motor voltage
139 float U_AD = 0; // Drive motor voltage
140 float s p e e d E r r o r H i s t o r y = 0; // Accumulative . If this gets very large
the PI - controller will get sluggish , and this might need clearing . ( Aka integral
windup )
141 int state = STATE_STARTUP ; // Current state of the program
142 bool okPressed = false ; // True when OK button is pressed
143 bool cancelPressed = false ; // True when Cancel button is pressed
144 bool re g u l a t e S t e e r i n g = false ; // Determines if steering should be
regulated or not
145
146 // References , initial values
147 float leanAngle_ref = 0; // Desired lean angle
148 float v_ref = 7/3.6; // Desired bicycle speed
149 float ste erAngle_ ref = 0; // Desired steer angle
150
151 // Sensor objects
152 MPU6050 leanSensor (0 x69 ) ; // Lean angle sensor
153 MPU6050 steerSensor (0 x68 ) ; // Steer angle sensor , has AD0 set to HIGH .
154
155 // Filter objects , second argument is cutoff frequency in Hz for one pole filters .
156 FilterOnePole steerR efFilter ( LOWPASS , 5) ; // Filter the steer ref angle cause of
the noise in the gyro data . This will cause a delay in the regulator and the cutoff
should therefore not be set too low .
157 FilterOnePole l i f t D e t e c t i o n F i l t e r ( LOWPASS , 2) ; // Filter for the lift detection code so
the unit doesn ’t shut off due to simple vibrations .
158 FilterOnePole d r i v e M e a s u r e F i l t e r ( LOWPASS , 5) ; // Smooths out speed measurements a bit .
159
160
161 // Raw measurement variables from sensors
162 int lean_acc_x , lean_acc_z ;
61
APPENDIX D. ARDUINO C CODE
62
230 sp eed E r r o r H i s t o r y += speedError ;
231 float U_AD = Kp * speedError + Ki * dt * s p e e d E r r o r H i s t o r y ;
232
233 if ( U_AD > U_bank ) // Makes sure the regulator doesn ’t request higher voltages
than the battery bank can provide .
234 U_AD = U_bank ;
235 else if ( U_AD < 0)
236 U_AD = 0;
237
238 return U_AD ;
239 }
240
241 // Creates a new file on the SD card , with increasing trailing numbers in the file name .
242 void createFile () {
243 int filenumber = 1;
244 char filename [9];
245
246 strcpy ( filename , " 1. csv " ) ;
247 while ( sd . exists ( filename ) ) {
248 filenumber += 1;
249 itoa ( filenumber , filename , 10) ;
250 strcat ( filename , " . csv " ) ;
251 }
252
253 dataFile . open (( const char *) filename , O_CREAT | O_WRITE ) ;
254 }
255
256 void co l l e c t S e n s o r D a t a () {
257 int trashMemory ; // Dummy variable
258 leanSensor . getMotion6 (& lean_acc_x , & trashMemory , & lean_acc_z , & trashMemory , &
lean_speed_y , & trashMemory ) ; // This was slightly faster than getting the values
separately .
259 steer_speed_x = steerSensor . getRotationX () ;
260
261 steerAngle = - ( float ) ( analogRead ( S T E E R _ A N G L E _ S E N S O R ) - 504) * 0.00579503;
262
263 // Convert to SI units and switch direction on steer angular velocity ( it is mounted "
upside down ")
264 lax = (( float ) lean_acc_x + c a l i b _l e a n _ a c c _ x ) * 0.000599365;
265 laz = (( float ) lean_acc_z + c a l i b _l e a n _ a c c _ z ) * 0.000599365;
266 lsy = (( float ) lean_speed_y + c a l i b _ l e a n _ s p e e d _ y ) * 1.33231 E -4;
267 ssx = - (( float ) steer_speed_x + c a l i b _ s t e e r _ s p e e d _ x ) * 0.00106526;
268 }
269
270 void calcLeanAngle ( float dt ) {
271 float leanAngleAcc = - atan2 ( lax , laz ) ; // Lean angle according to accelerometer
272 float l e a n A n g l e G y r C h a n g e = lsy * dt ; // Change in lean angle according to gyro
273 leanAngle = l e a n _ g y r o _ p e r c e n t a g e *( leanAngle + l e a n A n g l e G y r C h a n g e ) + (1 -
l e a n _ g y r o _ p e r c e n t a g e ) * leanAngleAcc ; // Complementary Filter
274 }
275
276 void logData ( float dt ) {
277 // Convert floats to C strings
278 dtostrf (v , 8 , 3 , vBuffer ) ;
279 dtostrf ( v_ref , 8 , 3 , v_refBuffer ) ;
280 dtostrf ( steerAngle , 8 , 3 , s t e e r A n g l e B u f f e r ) ;
281 dtostrf ( steerAngle_ref , 8 , 3 , s t e e r A n g l e _ r e f B u f f e r ) ;
282 dtostrf ( U_AS , 8 , 3 , U_ASBuffer ) ;
283 dtostrf ( U_AD , 8 , 3 , U_ADBuffer ) ;
284 dtostrf ( leanAngle , 8 , 3 , le a nA ng le B uf fe r ) ;
285 dtostrf ( leanAngle_ref , 8 , 3 , l e a n A n g l e _ r e f B u f f e r ) ;
286 dtostrf ( ssx , 8 , 3 , ssxBuffer ) ;
287 dtostrf ( lsy , 8 , 3 , lsyBuffer ) ;
288 dtostrf ( lax , 8 , 3 , laxBuffer ) ;
289 dtostrf ( laz , 8 , 3 , lazBuffer ) ;
290 dtostrf ( dt , 8 , 3 , dtBuffer ) ;
291
292 // File structure : [v , v_ref , leanAngle , leanAngle_ref , steerAngle , steerAngle_ref ,
U_AS , U_AD , ssx , lsy , lax , laz , dt ]
293 dataFile . print ( vBuffer ) ; dataFile . print ( " ," ) ; dataFile . print ( v_refBuffer ) ; dataFile .
print ( " ," ) ; dataFile . print ( l ea nA ng l eB uf fe r ) ; dataFile . print ( " ," ) ; dataFile . print (
l e a n A n g l e _ r e f B u f f e r ) ; dataFile . print ( " ," ) ;
294 dataFile . print ( s t e e rA n g l e B u f f e r ) ; dataFile . print ( " ," ) ; dataFile . print (
s t e e r A n g l e _ r e f B u f f e r ) ; dataFile . print ( " ," ) ; dataFile . print ( U_ASBuffer ) ; dataFile .
63
APPENDIX D. ARDUINO C CODE
print ( " ," ) ; dataFile . print ( U_ADBuffer ) ; dataFile . print ( " ," ) ;
295 dataFile . print ( ssxBuffer ) ; dataFile . print ( " ," ) ; dataFile . print ( lsyBuffer ) ; dataFile .
print ( " ," ) ; dataFile . print ( laxBuffer ) ; dataFile . print ( " ," ) ; dataFile . print (
lazBuffer ) ; dataFile . print ( " ," ) ;
296 dataFile . print ( dtBuffer ) ;
297
298 dataFile . println ( " " ) ;
299
300 /* One could do the logging by letting the sd library convert the floats , such as :
301 *
302 * dataFile . print (v , 3) ; dataFile . print (" ,") ; dataFile . print ( v_ref , 3) ; dataFile .
print (" ,") ; dataFile . print ( leanAngle , 3) ; dataFile . print (" ,") ; dataFile . print (
leanAngle_ref , 3) ; dataFile . print (" ,") ;
303 * dataFile . print ( steerAngle , 3) ; dataFile . print (" ,") ; dataFile . print ( steerAngle_ref ,
3) ; dataFile . print (" ,") ; dataFile . print ( U_AS , 3) ; dataFile . print (" ,") ; dataFile .
print ( U_AD , 3) ; dataFile . print (" ,") ;
304 * dataFile . print ( ssx , 3) ; dataFile . print (" ,") ; dataFile . print ( lsy , 3) ; dataFile .
print (" ,") ; dataFile . print ( lax , 3) ; dataFile . print (" ,") ; dataFile . print ( laz , 3) ;
dataFile . print (" ,") ; dataFile . print ( dt , 3) ;
305 * dataFile . println ("") ;
306 *
307 * This method might save some RAM ( since the buffers / char arrays aren ’t needed ) , but
takes about 4 -5 ms longer to execute .
308 */
309 }
310
311 // System setup , run once when unit is turned on .
312 void setup () {
313 // Pin c onfigura tions
314 pinMode ( LED_RED , OUTPUT ) ;
315 pinMode ( MOTOR_DRIVE_A , OUTPUT ) ;
316 pinMode ( MOTOR_DRIVE_B , OUTPUT ) ;
317 pinMode ( MOTOR_DRIVE_PWM , OUTPUT ) ;
318 pinMode ( MOTOR_STEER_A , OUTPUT ) ;
319 pinMode ( MOTOR_STEER_B , OUTPUT ) ;
320 pinMode ( MOTOR_STEER_PWM , OUTPUT ) ;
321
322 pinMode ( SPEED_SENSOR_INTERRUPT , INPUT_PULLUP ) ;
323 pinMode ( BUTTON_OK , INPUT ) ;
324 pinMode ( BUTTON_CANCEL , INPUT ) ;
325
326 // Join I2C bus
327 Wire . begin () ;
328
329 // Initialize MPU6050 sensors
330 leanSensor . initialize () ;
331 steerSensor . initialize () ;
332
333 // Configure sensors
334 leanSensor . setDLPFMode (4) ; // Activates the internal lowpass filter :
Cutoffs at 20 Hz , 8.3 ms delay .
335 steerSensor . setDLPFMode (4) ;
336 steerSensor . s e t F u l l S c a l e G y r o R a n g e (3) ; // Uses the full range of the gyroscope for
steering , 0 - 2000 deg / s .
337
338 // Test connections to sensors , if successful light up LED for half a second .
339 if ( leanSensor . testCo nnection () && steerSensor . tes tConnect ion () ) ;{
340 digitalWrite ( LED_RED , HIGH ) ;
341 }
342 delay (500) ;
343 digitalWrite ( LED_RED , LOW ) ;
344
345 if (! sd . begin ( SD_CARD_CS , SD_SCK_MHZ (50) ) ) {
346 sd . initErrorHalt () ;
347 }
348
349 // Attach interrupt function to speed sensor pin
350 PCintPort :: a tt a ch In te r ru pt ( SPEED_SENSOR_INTERRUPT , speedCodeWheelPass , CHANGE ) ;
351
352 // Calibrate gyros and a ccelerom eters .
353 lean_acc_x = leanSensor . g e t A c c e l e r a t i o nX () ;
354 lean_acc_z = leanSensor . g e t A c c e l e r a t i o nZ () ;
355 lean_speed_y = leanSensor . getRotationY () ;
356 steer_speed_x = steerSensor . getRotationX () ;
64
357
358 c al ib _ l e a n _ s p e e d _ y = 0 - lean_speed_y ;
359 c a l i b _ s t e e r _ s p e e d _ x = 0 - steer_speed_x ;
360 calib _ l e a n _ ac c _ x = 0 - lean_acc_x ; // Calibration without support wheel ( unit
should be straight up and not moving )
361 calib _ l e a n _ ac c _ z = 16384 - lean_acc_z ; // Calibration without support wheel ( unit
should be straight up and not moving )
362 // cali b _ l e a n _ a c c _ x = -2394 - lean_acc_x ; // Calibration with support wheel
363 // cali b _ l e a n _ a c c _ z = 16209 - lean_acc_z ; // Calibration with support wheel
364 }
365
366 // Main loop when unit was just started or a program was shut off
367 // Flashes red LED every second
368 void loopStartup () {
369 // Check any input from buttons
370 bool okValue = digitalRead ( BUTTON_OK ) ;
371
372 if ( okValue == HIGH )
373 okPressed = 1;
374 else if ( okValue == LOW && okPressed ) {
375 okPressed = 0;
376 sp e e d E r r o r H i s t o r y = 0;
377 v = 0;
378
379 createFile () ;
380
381 state = S T A T E _ P R O G R A M _ R E D ;
382 }
383
384 // LED indications
385 flashRedLED () ;
386
387 co lle c t S e n s o r D a t a () ;
388
389 // Calculate change in time
390 unsigned long now = micros () ;
391 float dt = ( now - lastLoopTime ) * 1E -6;
392 lastLoopTime = now ;
393
394 calcLeanAngle ( dt ) ;
395
396 // Automatic Control
397 // steerA ngle_ref = calcTheta_ref ( leanAngle , lsy , leanAngle_ref ) ;
398 // U_AS = calcU_AS ( steerAngle , ssx , steer Angle_re f ) ;
399 // U_AD = calcU_AD ( dt ) ;
400
401 // Turn off motors
402 digitalWrite ( MOTOR_DRIVE_A , LOW ) ;
403 digitalWrite ( MOTOR_DRIVE_B , LOW ) ;
404 analogWrite ( MOTOR_DRIVE_PWM , 0) ;
405 digitalWrite ( MOTOR_STEER_A , LOW ) ;
406 digitalWrite ( MOTOR_STEER_B , LOW ) ;
407 analogWrite ( MOTOR_STEER_PWM , 0) ;
408 }
409
410 void loopProg ramRed () {
411 // If user pressed cancel button , turn off the program
412 bool cancelValue = digitalRead ( BUTTON_CANCEL ) ;
413
414 if ( cancelValue == HIGH )
415 cancelPressed = 1;
416 else if ( cancelValue == LOW && cancelPressed ) {
417 cancelPressed = 0;
418 dataFile . close () ;
419 reg u l a t e S t e e r i ng = false ;
420 state = STATE_STARTUP ;
421
422 return ;
423 }
424
425 // LED indications
426 digitalWrite ( LED_RED , HIGH ) ;
427
428 co lle c t S e n s o r D a t a () ;
65
APPENDIX D. ARDUINO C CODE
429
430 // Detect if unit was lifted up and stop program if that ’s the case
431 if ( l i f t D e t e c t i o n F i l t e r . input ( laz ) > 11.5) {
432 dataFile . close () ;
433 reg u l a t e S t e e r i ng = false ;
434 state = STATE_STARTUP ;
435
436 return ;
437 }
438
439 // Calculate change in time
440 unsigned long now = micros () ;
441 float dt = ( now - lastLoopTime ) * 1E -6;
442 lastLoopTime = now ;
443
444 calcLeanAngle ( dt ) ;
445
446 // Automatic Control
447 steer Angle_re f = calcTheta_ref ( leanAngle , lsy , leanAngle_ref ) ;
448
449 // With support wheel :
450 // Only regulate the steering when the bicycle has attained the desired speed .
451 // Otherwise steer slightly to the left to keep as straight as possible .
452
453 if ( r e g u l a t e S t e e r i n g ) {
454 // if ( now > t i m e A t t a i n e d S p e e d + 1000)
455 // leanAngle_ref = -0.174532; // -10 deg
456 }
457 else {
458 stee rAngle_r ef = 0;
459
460 if ( v > 1.6667) { // 6 km / h
461 r e g u l a t e S t e e r in g = true ;
462 t i m e A t t a i n e d S p e e d = micros () ;
463 }
464 }
465
466 steer Angle_re f = ste erRefFil ter . input ( steerAng le_ref ) ;
467
468 U_AS = calcU_AS ( steerAngle , ssx , st eerAngle _ref ) ;
469 U_AD = calcU_AD ( dt ) ;
470
471 // Send PWM signals to motor drivers
472 digitalWrite ( MOTOR_DRIVE_A , HIGH ) ;
473 digitalWrite ( MOTOR_DRIVE_B , LOW ) ;
474 analogWrite ( MOTOR_DRIVE_PWM , map ( U_AD , 0 , 12 , 0 , 255) ) ;
475
476 if ( U_AS < 0) {
477 U_AS = map ( abs ( U_AS ) , 0 , 12 , 2 , 12) ;
478 digitalWrite ( MOTOR_STEER_A , HIGH ) ;
479 digitalWrite ( MOTOR_STEER_B , LOW ) ;
480 analogWrite ( MOTOR_STEER_PWM , map ( abs ( U_AS ) , 0 , 12 , 24 , 255) ) ;
481 }
482 else {
483 U_AS = - map ( abs ( U_AS ) , 0 , 12 , 2 , 12) ;
484 digitalWrite ( MOTOR_STEER_A , LOW ) ;
485 digitalWrite ( MOTOR_STEER_B , HIGH ) ;
486 analogWrite ( MOTOR_STEER_PWM , map ( abs ( U_AS ) , 0 , 12 , 24 , 255) ) ;
487 }
488
489 // Log data to SD card
490 logData ( dt ) ;
491 }
492
493 // Arduino main loop - selects appropriate loop depending on which state unit is in
494 void loop () {
495 switch ( state ) {
496 case STATE_STARTUP :
497 loopStartup () ;
498 break ;
499 case S T A T E _ P R O G R A M _ R E D :
500 loop ProgramR ed () ;
501 break ;
502 }
66
503 }
67
TRITA-ITM-EX 2018:58
www.kth.se