Escolar Documentos
Profissional Documentos
Cultura Documentos
of
autonomous
manoeuvres
in
a
quadcopter
Table
of
Contents
1.
Introduction
........................................................................................................................................
4
1.1.
Background
and
context
............................................................................................................................
4
1.2.
Purpose
.............................................................................................................................................................
4
1.3.
Specifications
and
scope
............................................................................................................................
5
2.
Hardware
.............................................................................................................................................
6
2.1.
The
quadcopter:
Parrot
AR.
Drone
2.0
................................................................................................
6
2.2.
Joypad
..............................................................................................................................................................
10
2.3.
Network
layout
............................................................................................................................................
10
3.
External
software
............................................................................................................................
12
3.1.
Ubuntu
.............................................................................................................................................................
12
3.2.
Robot
Operating
System
(ROS)
............................................................................................................
13
3.2.1.
Basic
tools
and
concepts
.................................................................................................................
13
3.2.2.
ROS
build
tool:
CMake
......................................................................................................................
15
3.2.3.
Types
of
messages
.............................................................................................................................
16
3.3.
Ardrone
driver
.............................................................................................................................................
18
3.3.1.
Introduction
.........................................................................................................................................
18
3.3.2.
Structure
................................................................................................................................................
18
3.3.3.
Custom
messages
...............................................................................................................................
20
4.
Custom
software
structure
..........................................................................................................
22
4.1.
Introduction
..................................................................................................................................................
22
4.2.
Joypad
..............................................................................................................................................................
22
4.3.
Spooler
............................................................................................................................................................
24
4.4.
First
controller
.............................................................................................................................................
26
5.
Position
estimation
.........................................................................................................................
28
5.1.
Position
estimation
based
on
image
...................................................................................................
28
5.1.1.
Position
estimation
based
on
features
......................................................................................
28
5.1.2.
Position
estimation
based
on
phase
correlation
..................................................................
36
5.2.
Position
estimation
based
on
odometry
...........................................................................................
39
1. Introduction
1.1. Background
and
context
Robotics
is
a
branch
of
the
technology
that
in
recent
years
hasnt
stopped
growing.
The
robots
have
become
an
important
tool
for
human
beings
not
only
in
the
military
domain,
but
also
in
civilian
environments.
Some
of
the
tasks
assigned
to
robots
and
remotely
operated
vehicles
are
observation
and
exploration
of
environments,
which
sometimes
can
be
dangerous,
expensive
access
or
simply
inaccessible
to
humans.
One
kind
of
robots
or
remotely
commanded
vehicles
that
have
seen
increased
their
use
and
research
are
flying
vehicles
and
small
flying
vehicles
(Miniature
aerial
vehicles
or
MAVs).
Quadcopters
are
one
type
of
these
flying
vehicles.
A
quadcopter
(also
quadrotor,
quadrotor
helicopter
or
quadcopter)
is
a
multicopter
that
is
propelled
by
four
rotors.
The
quadcopters
have
almost
all
the
advantages
(in
terms
of
flight)
of
the
helicopters,
such
as
stay
still
in
one
position
when
flying,
move
and
turn
fast,
move
to
any
direction
without
turning,
turn
without
moving
or
take
off
and
land
vertically.
Quadcopters
have
become
very
popular
in
unmanned
aerial
vehicle
(UAV)
research
in
robotics
and
in
computer
vision.
Researchers
are
frequently
choosing
quadcopters
because
can
accurately
and
efficiently
perform
tasks
and
it
is
quite
easy
to
implement
tasks
and
do
trials
with
them.
In
addition,
there
is
a
wide
range
of
prices
of
quadcopters
or
sensors,
motors
or
cameras
to
build
them,
and
they
can
be
used
for
many
purposes
and
featured
with
many
different
sensors,
cameras,
etc.
Many
researches
has
been
done
with
quadcopters
such
as
autonomous
navigation,
autonomous
surveillance,
maping,
searching
and
detecting,
following,
collaborative
manoeuvres,
lifting
or
landing
in
a
target
among
others.
An
example
of
one
of
these
researches
is
a
project
sFly
that
lasted
from
2009
until
2011,
which
aims
the
development
of
several
small
and
safe
helicopters
which
can
fly
autonomously
in
city-like
enviroments
and
which
can
be
used
to
assist
humans
in
tasks
like
rescue
and
monitoring.
Another
example
is
the
Flying
Machine
Arena
(ETH
Zurich),
which
is
a
space
that
was
made
to
fly
machines,
especially
quadcopters.
This
project
had
been
developed
in
the
Oceans
Systems
Laboratory
of
the
Heriot-Watt
University
of
Edinburgh
(Scotland),
which
is
a
research
centre
specialized
in
autonomous
systems,
sensor
modelling
and
processing
and
underwater
acoustic
system
theory
and
design.
To
this
date
the
OSL
has
done
projects
with
Autonomous
Underwater
Vehicles
(AUV)
but
never
with
an
Unmanned
Aerial
Vehicle
(UAV).
For
the
interaction
with
the
robots
the
OSL
uses
the
platform
ROS
(Robotics
Open
Source).
This
platform
provides
libraries
and
tools
to
help
software
developers
create
robot
applications.
ROS
drivers
for
the
UAV
object
of
this
project
have
already
been
developed.
1.2. Purpose
The
purpose
of
this
project
is
to
use
ROS
software
to
interact
with
an
existing
UAV
and
develop
applications
in
C++
in
order
to
command
the
UAV.
The
goals
of
this
project
are
to
develop
applications,
like
simple
controller,
to
get
the
UAV
first
to
follow
simple
commands,
then
do
position
estimation
trying
several
methods
and
finally
detect
a
target
to
perform
an
autonomous
landing
on
that
target.
2. Hardware
The
devices
used
in
the
present
project
are
a
quadcopter
and
a
joypad
coupled
with
a
ground-
based
laptop.
The
quadcopter
is
the
main
hardware
used
in
the
project,
and
the
joypad
is
used
to
control
the
quadcopter
remotely
when
its
needed.
All
the
programs
are
run
in
the
laptop,
which
sends
all
the
orders
to
the
quadcopter.
2.1. The
quadcopter:
Parrot
AR.
Drone
2.0
The
quadcopter
used
is
the
Parrot
AR.
Drone
2.0
(Fig.
1),
which
is
a
ready-to-fly
quadcopter,
suitable
for
operation
indoors
or
outdoors.
The
Parrot
AR.
Drone
2.0
is
the
second
version
of
a
quadcopter
sold
as
a
flying
sophisticated
toy
for
14
ages
and
up
created
by
the
company
Parrot.
Besides
the
quadcopter,
the
company
also
sells
multimedia
devices,
such
as
headphones
or
speakers,
and
hands-free
kits
for
cars.
This
quadcopter
can
fly
indoors
or
outdoors
(without
much
wind,
up
to
15
m/h).
It
is
supposed
to
be
controlled
by
Wi-Fi
using
an
application
for
smartphones
or
tablets
(Fig.
2).
This
quadcopter
is
used
in
several
universities
and
research
institutions
to
use
it
in
research
projects
in
fields
such
as
robotics,
artificial
intelligence
and
computer
vision.
This
has
been
the
quadcopter
used
in
this
project
because
it
is
not
expensive
(306.39
with
spare
battery
included)
and
it
is
very
easy
to
use
because
there
are
drivers
done
by
universities
to
connect
to
the
drone
directly
and
send
to
it,
for
example,
velocity
commands.
Although
this
quadcopter
is
used
in
research,
it
is
not
the
most
indicate
because
it
is
a
toy
and
its
motors
are
not
very
powerful
and
it
has
not
been
designed
to
raise
extra
weight.
A
test
of
the
altitude
sensor
of
the
new
drone
has
been
done
to
check
its
proper
operation
(Fig.
4),
and
the
conclusion
is
that
it
is
quite
accurate
when
it
is
still
but
the
measurements
are
a
bit
wrong
when
it
raises
or
descends
rapidly.
Most
of
the
parts
of
the
drone
can
be
replaced
with
spare
parts
that
can
be
bought
from
the
same
company
that
AR
Parrot.
It
has
been
made
a
modification
to
the
drone
with
the
project
highly
advanced
due
to
the
possibility
to
get
better
results
with
the
modification.
It
basically
consists
of
moving
the
front
looking
camera
to
become
a
down
looking
camera
because
as
it
is
a
flying
robot,
it
is
much
more
useful
a
good
down
looking
camera
with
wide
angle
lens
(92
diagonal
fisheye)
than
a
good
front
camera,
and
the
bottom
camera
that
has
by
default
is
of
very
poor
quality.
The
foam
from
the
front
part
of
the
drone
has
been
removed
in
order
to
turn
the
camera.
The
changes
can
be
seen
in
the
Fig.
7.
This
change
has
been
done
at
the
end
of
January
2013,
during
the
project
development.
10
Node 1
AR Drone
driver
Node 2
Velocity
commands
...
All
processing
data
acquired
from
the
drones
sensors
and
cameras
and
all
the
programs
to
control
it
run
on
the
ground-based
laptop
and
only
velocity
commands
are
sent
to
the
drone
via
Wi-Fi.
So
almost
all
the
computation
takes
place
in
the
laptop,
and
there
is
no
on-board
computation
in
the
drone,
except
for
the
stabilization
and
image
acquisition.
The
joypad
is
also
connected
to
the
laptop
via
USB
stick.
There
were
problems
with
the
Wi-Fi
communication
between
the
laptop
and
the
drone
during
some
trials
because
its
default
Wi-Fi
channel
is
the
sixth,
and
many
other
wireless
networks
were
using
this
channel.
It
was
a
problem
because
this
project
is
carried
out
in
a
laboratory
at
the
Heriot-Watt
University
of
Edinburgh
where
there
are
several
active
wireless
networks.
The
solution
has
been
changing
the
channel
used
for
the
drones
Wi-Fi
network
to
the
first
one
because
in
this
channel
there
are
less
Wi-Fi
networks
than
in
the
sixth
channel
and
since
then
the
communications
are
working
properly.
11
3. External
software
3.1. Ubuntu
The
operating
system
used
for
the
developing
of
this
project
is
Ubuntu.
Ubuntu
is
based
on
a
Devian
-
Linux
distribution
and
it's
free
and
open-source
software.
The
reason
for
using
this
operating
system
is
that
it's
able
to
support
the
different
software
used
in
this
project
that
will
be
explained
below.
Ubuntu,
just
as
most
commercial
operating
systems
like
Windows
or
Mac
OS,
has
a
graphical
interface.
Among
other
things
have
a
desktop,
folder
organization
(Fig.
10),
office
applications,
web
browser,
and
a
terminal
(Fig.
12).
There
are
many
applications
available
for
free
download
and
installation
as
image
editors,
games,
drawing
tools,
sound
and
video
players
and
more.
On
this
project,
as
will
be
explained
on
the
next
sections,
the
terminal
has
been
an
essential
tool
(Fig.
12).
12
13
Topic:
Nodes
can
publish
messages
to
a
topic
as
well
as
subscribe
to
a
topic
to
receive
messages.
It
is
the
medium
of
communication
between
nodes.
A
clear
example
of
this
would
be
the
constant
feedback
on
the
position
of
the
robot;
the
node
that
obtains
this
position
would
be
the
publisher
and
the
node
containing
the
PID
the
subscriber.
Parameter:
Parameters
can
be
either
set
or
accessed
from
a
node
or
from
a
terminal
by
a
user.
It's
a
useful
way
to
pass
punctual
information.
One
example
could
be
for
the
gain
of
a
PID
implemented
in
a
node,
if
it
takes
its
value
from
a
parameter,
the
user
can
change
this
value
during
the
functioning
of
the
program
and
it
will
be
actualized.
Service:
When
a
node
calls
a
service
it's
making
a
request
on
another
node,
and
will
then
receive
a
response.
Like
in
the
case
of
the
messages,
there
are
different
types
of
services
depending
on
the
type
of
the
data
Rxgraph
(Fig.
15)
is
a
tool
that
creates
a
graph
showing
all
the
nodes
that
are
currently
running
and
the
topics
that
join
them.
An
arrow,
coming
out
from
the
publisher
and
into
the
subscriber,
represents
the
topic.
Each
node
can
be
at
the
same
time
publisher
and
subscriber
to
different
nodes.
To
summarize,
in
order
to
communicate,
the
nodes
can
recur
to
send
messages
through
topics,
call
services
or
set
and
get
parameters.
14
15
3.2.3. Types
of
messages
There
are
many
types
of
messages
but
here
will
only
be
explained
the
ones
of
interest
to
the
project.
Messages,
like
nodes,
have
to
be
created
in
a
ROS
package.
The
name
of
a
type
of
message
contains
the
name
of
the
package
where
it
comes
from
and
then
the
name
of
the
specific
type.
For
instance,
the
package
std_msgs
contains
different
standard
messages
like:
std_msgs/String,
std_msgs/Bool.
The
type
from
this
package
that's
been
used
in
this
project
is
std_msgs/Empty
which
as
the
name
implies
does
not
contain
any
fields.
To
work
with
image
broadcasting
it
has
been
used
the
sensor_msgs
package.
In
particular,
the
sensor_msg
types
used
are
sensor_msgs/Image
and
sensor_msgs/CameraInfo.
The
sensor_msgs/Image
contains
the
following
fields:
Header
header
uint32
seq
time
stamp
string
frame_id
uint32
height
uint32
width
string
encoding
uint8
is_bigendian
uint32
step
uint8[]
data
16
As
can
be
observed,
it
is
possible
to
have
a
message
type
inside
another
one.
This
makes
it
simpler
to
design
message
types
because
one
can
combine
existing
ones
then
and
add
more
fields
if
necessary.
The
package
geometry_msgs
provides
messages
for
common
geometrical
primitives
such
as
points,
vectors
and
poses.
The
type
geometry_msgs/Point32
is
to
send
a
3D
point
float32
x
float32
y
float32
z
The
type
geometry_msgs/Twist
can
have
different
uses,
such
as
sending
a
velocity
command,
or
a
displacement
both
in
3D
coordinates
and
with
linear
and
angular
fields.
geometry_msgs/Vector3
linear
float64
x
float64
y
float64
z
geometry_msgs/Vector3
angular
float64
x
float64
y
float64
z
17
18
19
state:
The
Drone's
current
state:
0:
Unknown,
1:
Inited,
2:
Landed,
3
and
7:
Flying,
4:
Hovering,
5:
Test,
6:
Taking
off
and
8:
Landing.
magX, magY, magZ: Magnetometer readings (AR. Drone 2.0 Only) (TBA: Convention)
pressure: Pressure sensed by Drone's barometer (AR. Drone 2.0 Only) (TBA: Unit)
temp : Temperature sensed by Drone's sensor (AR. Drone 2.0 Only) (TBA: Unit)
wind_speed: Estimated wind speed (AR. Drone 2.0 Only) (TBA: Unit)
wind_angle: Estimated wind angle (AR. Drone 2.0 Only) (TBA: Unit)
wind_comp_angle: Estimated wind angle compensation (AR. Drone 2.0 Only) (TBA: Unit)
tm:
Timestamp
of
the
data
returned
by
the
Drone
returned
as
number
of
micro-seconds
passed
since
Drone's
boot-up.
20
21
Velocity
commands
Pose
Spooler
Control
Development
of
autonomous
manoeuvres
in
a
quadcopter
Velocity
Report
Velocity
commands
commands
Pose
Control based
on odometry
Velocity
commands
Visual
Servoing
4.1. Introduction
Estimated
position
(NOT
SCALED)
PTAM
The
general
structure
of
the
software
is
shown
in
Fig.
19.
There
is
a
node
called
spooler
that
decides
which
messages
arrive
to
the
AR.
Drone
driver.
Publishing
to
this
Spooler
node
there
is
the
joypad
node,
to
be
able
to
manually
control
the
quadcopter,
and
then
the
controller
node
that
can
be
any
node
designed
to
AR
control
AR Drone cameras
Dronethe
AR.
Drone.
What
has
been
developed
in
this
project
are
the
different
controller
nodes,
all
guided
by
the
AR.
Drone
cameras
and
sensors.
Over
the
next
chapters
these
controllers
will
be
explained
in
detail.
Velocity
commands
Spooler
joypad
node
Velocity
commands
Velocity
commands
Controller
Navigation
data
AR Drone
driver
Navigation
data
Velocity
commands
Cameras
images
4.2. Joypad
The
aim
of
the
Joypad
node
is
to
be
able
to
control
the
AR.
Drone
manually.
This
is
especially
useful
when
doing
trials
of
any
of
the
autonomous
manoeuvres
in
case
it
is
necessary
to
regain
the
control
of
the
robot
because
the
program
is
not
working
as
planned
or
needs
a
little
manual
readjustment
to
keep
working.
This
can
help
prevent
any
danger
of
injury
to
the
users,
the
viewers
or
any
damage
on
the
robot.
An
existing
code
to
control
another
robot
has
been
adapted
to
develop
this
node.
This
code
(ANNEX
A.1
Joystick
node)
was
for
a
land
robot
called
Turtlebot
and
was
developed
by
Josep
Bosch
from
the
Oceans
Systems
Lab.
All
the
topics
published
by
this
node
are
listened
by
the
spooler
node
that
is
explained
below.
All
the
messages
broadcast
from
the
Joypad
node
have
the
Priority
field
set
to
true
so
that
its
commands
are
always
executed
regardless
of
the
commands
coming
from
other
nodes.
22
The commands that can be sent from the joypad are the following:
Velocity
commands:
forwards,
backwards,
to
the
left,
to
the
right,
up
and
down.
The
velocities
range
from
0
to
0.3m/s
that
is
the
AR.
Drone
2.0
maximum
velocity.
Take off
Land
Reset.
Custom
and
cmd-aux
do
not
have
a
specific
use
and
can
be
characterized
different
for
each
node.
In
this
project
have
only
been
used
in
the
pose_estimation_ptam
node
as
will
be
explained
further
on
in
this
report.
The
function
of
the
used
buttons
can
be
shown
in
the
Fig.
21.
Reset
Take off
Move up and
down
R1, R2,
L1 or L2
Flips
Land
Turn
Move forwards and
backwars
Fig.
21.
Functions
of
the
joypad
buttons
23
24
Custom
ardrone_msgs
In
order
to
know
where
the
messages
came
from
it
was
necessary
to
design
new
types
of
message
that
had
assigned
a
priority.
These
custom
messages
are
defined
as
ardrone_msgs.
ardrone_msgs/Vel
Has
the
same
fields
as
a
geometry_msgs/Twist
plus
the
Priority
field
that
is
a
bool.
ardrone_msgs/Vector3
linear
float64
x
float64
y
float64
z
ardrone_msgs/Vector3
angular
float64
x
float64
y
float64
z
bool
priority
This
field
Priority
it's
set
to
true
when
the
message
comes
from
the
Joystick
node,
and
set
to
false
if
it
comes
from
any
other
node.
This
way
the
spooler
node
checks
this
field
of
the
message
to
know
where
the
message
comes
from.
25
Fig.
26.
Controller
node
rxgraph
26
FUNCTION
LANDED
Makes sure the drone is in landed state and sends the take_off message
TAKING_OFF
MOVING
For two seconds moves forwards. Sets a timer and when the timer
finishes it set the next state.
STOPPING
WAITING
Starts a timer and waits for two seconds until it finishes and sets the next
state.
START_LANDING Gives the command to land and sets the next state.
LANDING
This state does nothing,. Just waits until the drone has landed, then it sets
the state to finish.
FINISHED
Last state. Just shows a sentence saying the mission has been
accomplished successfully.
Table
1.
Code
states
27
5. Position
estimation
The
issue
of
identifying
the
location
of
a
mobile
robot
(x,
y,
z,
and
orientation)
at
any
given
time
is
one
of
the
most
fundamental
problems
in
robotics.
Localization
is
a
version
of
on-line
temporal
state
estimation,
where
a
mobile
robot
seeks
to
estimate
its
position
in
a
global
coordinate
frame.
The
pose
estimation
problem
can
be
solved
in
different
ways
depending
on
the
choice
of
the
method.
Most
methods
use
relative
position
techniques,
in
which
the
robot
position
is
initialised
to
zero
at
start-up
and
any
subsequent
motion
is
measured
respect
to
this
location.
In
this
project
three
methods
are
developed
to
do
the
position
estimation
task:
first
two
are
based
on
the
image
obtained
from
the
cameras
of
the
drone,
and
the
other
one
is
based
on
the
robots
odometry.
5.1. Position
estimation
based
on
image
The
following
two
methods
use
the
image
from
the
cameras
of
the
robot
to
estimate
its
position.
The
first
of
the
following
methods
uses
the
front
HD
camera
looking
forwards
and
its
based
on
features.
The
second
one
is
designed
for
a
looking
down
camera
and
its
based
on
phase
correlation
between
consecutive
images.
This
section
of
the
project
has
been
made
before
turning
the
front
HD
camera,
so,
during
the
development
of
this
part
the
quadcopter
had
the
front
HD
camera
and
the
default
bottom
camera.
5.1.1. Position
estimation
based
on
features
Two
methods
had
been
tested
to
do
the
position
estimation
based
on
features:
a)
mono_odometer
node
from
Viso2
package,
and
b)
ptam
node
from
ptam
package
in
the
ethzasl_ptam
stack.
a) Viso2
The
Systems,
Robotics
and
Vision
group
of
the
University
of
the
Balearic
Islands,
Spain,
maintain
this
package.
It
contains
two
nodes
that
use
the
libviso21
library:
mono_odometer
and
stereo_odometer.
Both
estimate
camera
motion
based
on
incoming
rectified
images
from
calibrated
camera.
In
our
project
we
tried
the
mono_odometer
node
from
viso2
package
because
we
had
only
one
camera
looking
down.
To
estimate
the
position,
this
algorithms
needs
to
calculate
the
robot
motion,
and
to
be
able
to
calculate
the
camera
motion
the
transformation
from
the
camera
frame
to
the
robot
frame
has
to
be
known.
To
estimate
the
scale
of
the
motion,
this
node
needs
the
altitude
and
the
pitch
of
the
robot.
But
this
node
has
some
limitation
that
makes
it
not
suitable
to
use
for
this
purpose
in
this
project.
It
is
not
recommended
to
use
it
when
there
are
rotations.
If
the
movement
is
linear
it
calculates
the
position
quite
well,
but
when
there
are
rotations
it
doesn't
work
well.
Since
a
quadcopter
is
very
unusual
to
fly
always
with
linear
velocity
without
turning,
this
package
was
discarded
to
do
the
motion
estimation.
Also,
monocular
scale
is
estimated
by
assuming
a
fixed
camera
height
over
ground,
which
is
very
unusual
for
a
quadcopter
flight.
1
LIBVISO2
(Library
for
Visual
Odometry
2)
is
a
very
fast
cross-platfrom
(Linux,
Windows)
C++
library
with MATLAB wrappers for computing the 6 DOF motion of a moving mono/stereo camera.
28
Oxford
by
George
Klein
and
David
Murray.
PTAM
(short
for
Parallel
Tracking
and
Mapping)
is
a
piece
of
computer
vision
software
that
can
track
the
3D
position
of
a
moving
camera
in
real
time.
It
is
a
SLAM
system
for
augmented
reality.
It
requires
no
markers,
pre-made
maps,
known
templates,
or
inertial
sensors
but
instead
works
out
the
structure
of
the
world
as
it
goes.
PTAM
is
useful
primarily
for
augmented
reality,
although
it
has
been
applied
to
other
tasks
(robot
guidance)
as
well.
29
Fig. 27. Not rectified and rectified images from the HD camera
Initialisation
of
PTAM
For
the
use
of
PTAM
is
necessary
to
start
getting
the
features
to
track
from
two
different
points
of
view
in
order
to
be
able
to
triangulate
and
find
the
relative
distance
between
them
and
the
camera.
It
takes
a
main
plane
using
the
initial
features,
and
all
the
positions
are
based
on
the
distance
of
the
camera
to
the
centre
of
coordinates
of
that
plane.
For
this
reason
is
necessary
an
initialisation
to
use
it.
30
To
get
the
two
points
of
view
of
the
initial
features
a
translation
of
the
camera
has
to
be
done.
It
has
to
be
only
translation,
not
rotation,
and
it
has
to
move
10
cm
approximately
(Fig.
29).
When
it
has
been
done,
PTAM
is
able
to
start
building
a
map
(not
scaled),
track
the
initial
features
and
find
new
features
to
track
in
the
camera
frame.
If
only
the
PTAM
is
used,
the
commands
to
control
the
PTAM
(start
a
map,
restart
a
map,
get
the
two
point
of
views
of
the
initial
features,
etc.)
are
sent
with
the
keyboard.
For
example,
get
the
two
initial
points
of
view
is
made
by
pressing
the
space
bar
of
the
keyboard
or
the
letter
r
key
to
restart
the
map.
The
controller
node:
pose_control_ptam
The
functions
developed
in
this
node
(ANNEX
A.4
Pose
control
based
on
features
(ptam))
can
be
split
in
to
different
functions:
the
ones
to
control
ptam
node,
and
the
ones
to
control
the
drone.
The
functions
to
control
ptam
node
are
creating
a
map,
scaling
the
map
and
restarting
the
map.
The
functions
to
control
the
drone
from
the
estimated
position
are
position
keeping
and
moving
in
any
x-y
direction
sending
distance
commands.
The
position
keeping
function
has
been
done
to
test
the
pose
estimation,
and
the
moving
function,
to
test
the
scaling
function.
Should
be
pointed
that
the
driver
of
the
drone
has
its
own
position
keeping
function
that
works
very
well
when
keeps
the
angle
but
not
so
well
when
keeps
the
linear
(x,
y)
position.
The
functions
to
control
the
ptam
node
has
ben
done
by
sending
the
same
message
that
would
send
a
keyboard
(space
bar,
letter
r,
etc.)
to
the
ptam
node,
for
example
msg_spacebar.data
=
"Space"
for
the
space
bar
press.
The
map
is
restarted
in
the
same
way.
And
to
make
the
initialisation
and
to
get
the
two
initial
points
of
view
an
action
had
been
implemented.
This
action
permits
to
move
the
camera
translating
but
not
rotating
it.
The
way
to
do
this
is
descending
or
rising
the
quadcopter
and
get
the
frames
before
and
after
that
movement.
The
other
function
it
has
to
do
with
PTAM
is
the
scaling
function
because
monocular
vision
cannot
measure
metric
scale;
the
maps
are
built
with
an
undetermined
scale.
To
do
the
scaling
one
real
measurement
in
any
of
the
three
axes
must
be
known,
for
example,
a
known
width
or
height
of
an
object,
or,
as
done
in
this
project,
moving
the
camera
again
only
translating
and
not
rotating
and
knowing
how
much
has
it
moved.
To
use
this
method
is
necessary
the
altitude
sensor.
Rising
the
quadcopter
again
about
10
cm,
the
scale
can
be
done.
The
altitude
the
drone
has
raised
(altitude
sensor)
can
be
compared
with
the
displacement
in
the
z-axis
of
31
START_INIT
MOVING_TO_INIT
END_INIT
RE_INIT
POSITION_KEEPING
LOST
STATE
TAKEOFF
START_INIT
MOVING_TO_INIT
END_INIT
RE_INIT
POSITION_KEEPING
LOST
Function
The drone takes off
Starts the initialisation: takes the initial
features in the first frame and rise the
drone
The drone is rising
Ends the initialisation: stops the drone
and takes the position of the initial
features in the frame
Prepare the restart of the initialisation:
descend
Do the scaling (every time there is a
new map), memorizes the initial
position and keeps this position
Stops the drone and turn to find the
lost map
NEXT STATE
START_INIT
MOVING_TO_INIT
END_INIT
POSITION_KEEPING: if
the map works
RE_INIT: If the map
doesnt work
START_INIT
LOST: if the map is lost
POSITION_KEEPING: if
the map if found
START_INIT: If the map
isnt found after a timer
32
33
To
do
the
function
of
moving
the
drone
using
distance
commands,
a
new
usage
of
some
buttons
of
the
joy
has
been
implemented.
This
buttons
set
a
modification
in
the
initial
position
memorised
in
the
POSITION_KEEPING
state.
The
position
can
be
modified
each
time
the
buttons
are
pressed
by
one
meter
in
any
direction
x-y
with
the
arrows
buttons
of
the
joypad.
This
can
only
be
preceded
by
a
scaling,
because
without
the
scaling
procedure,
the
map
has
no
measurements.
The
distance
commands
allows
to
test
the
scaling
procedure
implemented
in
this
node,
and
the
result
obtained
with
this
method
is
that
it
is
not
very
accurate.
In
addition,
the
scale
is
not
always
the
same
because
of
the
not
accuracy
of
the
altitude
sensor
and
the
small
random
movements
of
the
quadcopter
when
it
flies.
However,
it
is
an
initial
approach
of
the
scaling
with
a
quadcopter
with
one
camera,
and
its
error
can
be
disregarded
in
some
applications.
There
was
implemented
another
button
(Select
button
of
the
joypad)
in
this
node
to
start
a
new
map.
This
has
been
done
because
with
this
button
the
map
can
be
build
wherever
we
drive
the
drone.
To
operate
the
entire
package
a
launchfile
has
been
created
to
start
the
nodes:
ardrone_driver,
ardrone_spooler,
ardrone_joy
and
image_proc.
Once
all
these
nodes
are
started
the
ptam
node
is
started.
Finally
the
node
to
control
all
the
system
is
started:
the
pose_control_ptam
node.
In
conclusion,
the
position-based
visual
servoing
node
works
quite
well
if
there
are
enough
features
in
the
image
frame.
So,
to
use
it
is
necessary
to
have
an
environment
with
many
things
to
get
features
from
it
around
the
flying
zone.
If
there
are
too
few
features
and
is
not
able
to
build
a
map
with
them
or
the
drone
loses
the
map,
this
node
is
able
to
restart
a
new
map
with
new
features.
As
said
before,
the
scaling
method
is
not
very
accurate,
but
is
an
initial
approach.
An
improvement
to
the
code
would
be
to
orientate
PTAM
axis
to
match
with
the
drones
axis,
in
this
way,
the
precision
in
the
scaling
and
the
movements
would
increase
significantly
because
the
grid
will
always
be
in
the
same
place
respect
the
drone.
This
orientation
could
not
be
achieved
in
this
project.
34
35
This
however
only
works
for
images
that
have
been
translated
but
not
scaled
or
rotated.
Then
to
use
this
method
the
second
image
has
to
be
de-rotated
and
de-scaled
before
applying
the
algorithm.
In
order
to
do
that
another
property
of
the
Fourier
transform
can
be
used:
the
differences
in
rotation
and
scale
between
the
two
images
in
the
log-polar
coordinates
are
represented
by
linear
shifts.
In
view
of
this
properties
the
process
of
phase
correlation
between
two
images
f
and
g
would
be
the
following:
First
apply
the
FFT
to
both
images,
then
to
each
result
apply
a
polar
transform.
Taking
only
the
magnitudes
of
the
polar
transforms
calculate
the
normalized
cross
power
spectrum
and
then
its
inverse
FFT.
With
this
the
rotation
and
scale
will
be
known
and
the
second
image
can
be
de-scaled
and
de-rotated.
Finally,
the
phase
correlation
algorithm
can
be
applied
and
the
translation
obtained.
In
the
diagram
in
Fig.
35
this
process
can
be
seen
more
clearly.
36
FFT
FFT
Polar transform
Polar transform
|G|
|F|
FFT
FFT
|G|
|F|
FFT
FFT
IFFT
Translation
Since
this
was
implemented
from
the
mathematical
explanation
it
was
decided
to
go
step
by
step.
The
first
code
(ANNEX
A.5.1
phase_correlation_two_images.cpp)
developed
was
only
for
doing
phase
correlation
between
to
non-rotated
and
non-scaled
images
and
gave
the
translation
in
pixels.
After
this
code
worked
the
next
step
was
implement
the
same
for
a
camera
feed
and
get
the
translation
in
milimeters.
This
second
code
(ANNEX
A.5.2
phase_correlation_camera.cpp)
works
but
is
really
unstable
because
a
minimum
rotation
of
the
camera
or
approximation
to
the
image
will
make
the
output
meaningless.
The
period
of
time
for
the
developing
of
the
project
has
come
to
the
end
before
this
node
was
finished
so
only
the
version
without
the
rotation
has
been
achieved.
For
the
implementation
of
this
algortihm
OpenCV
and
cv_bridge
package
has
been
used.
37
The
OpenCV
version
used
in
this
project
is
2.4,
released
on
March
the
19th
of
2012.
Also,
to
be
able
to
use
the
OpenCV
library,
the
images
from
the
camera
feed
which
come
through
a
ROS
topic
have
to
be
converted
from
the
Image
message
to
the
OpenCV
image
format.
For
this
codes
is
necessary
the
use
the
cv_bridge
package.
As
the
name
explains
this
package
acts
as
a
bridge
between
OpenCV
and
other
formats.
It
was
created
by
Patrick
Mihelich
and
James
Bowman
and
has
a
BSD
licence.
As
will
be
seen
on
the
next
chapters,
this
library
and
the
cv_bridge
package
have
been
used
in
different
of
the
nodes
developed
in
the
project.
38
X = Xo + Vot
A
PID
controller
has
been
used
to
calculate
the
velocity
to
send
to
the
robot
depending
on
the
displacement
from
the
starting
point
in
all
axis
and
yaw.
The
PID
controller
is
part
of
a
ROS-
package
called
control_toolbox,
which
contains
several
C++
classes
useful
in
writing
robot
controllers.
The
results
obtained
using
this
node
(ANNEX
A.6
Pose
control
based
on
odometry)
are
not
the
desired
because
the
robot
is
no
able
to
keep
its
position
and
its
not
able
to
come
back
to
the
initial
position
when
it
is
displaced
from
it.
When
the
drone
is
keeping
the
pose
with
this
node,
it
constantly
moves
forwards
or
backwards
and
sideways.
This
method
is
not
appropriate
to
do
position
estimation.
This
is,
possibly,
because
the
/navdata
message
is
received
with
a
certain
frequency,
and
the
acceleration
is
continuously
changing.
This
method
can
only
be
used
if
the
navigation
data
from
a
robot
is
received
very
often,
almost
analogue.
When
we
did
this
node,
the
ardrone
driver
published
the
/navdata
message
every
15Hz,
but
a
few
weeks
after
finishing
the
node,
the
driver
was
updated
with
the
possibility
to
increase
the
frequency
of
only
the
/navdata
message
up
to
200Hz.
We
have
tried
the
node
with
this
new
frequency
and
the
results
are
a
little
better,
but
no
enough
to
get
the
pose
of
the
drone
with
this
node.
39
6. Visual
servoing
Visual
servoing,
or
Vision-Based
Robot
Control,
is
a
technique
that
uses
the
visual
feedback
information
extracted
from
a
camera
(or
more
than
one)
to
control
the
motion
of
a
robot.
Visual
servoing
techniques
can
be
classified
into
three
main
types:
IBVS
(Image-Based
Visual
Servoing),
PBVS
(Position-Based
Visual
Servoing)
and
a
hybrid
approach:
IBVS
is
based
on
the
error
between
the
desired
and
the
current
features
on
the
frame
of
the
camera.
2D
image
measurements
are
used
directly
to
estimate
the
desired
movement
of
the
robot.
PBVS
is
based
on
the
estimation
of
the
position
with
respect
to
the
camera,
and
then
the
command
is
issued
to
the
robot
controller.
These
systems
retrieve
the
3D
information
about
the
scene
where
known
camera
model
(usually
in
conjunction
with
a
geometric
model
of
the
target)
is
used
to
estimate
the
pose
(position
and
orientation)
of
the
target.
In
this
project
has
been
developed
two
types
of
visual
servoing:
the
IBVS
and
the
2-1/2-D
visual
servoing.
The
2-1/2-D
visual
servoing
has
been
explained
in
the
section
5.1.
Position
estimation
based
on
image,
inside
the
position
estimation
part
(chapter
5.
Position
estimation).
It
had
been
explained
within
that
section
because
it
is
one
of
the
two
methods
for
estimating
the
position
that
has
been
tested
(one
based
on
image
and
the
other
based
on
odometry).
Since
it
was
first
developed
the
entire
part
of
position
estimation
(chapter
5),
the
2-1/2-D
visual
servoing
part
of
visual
servoing
is
not
explained
in
this
section
(chapter
6.
Visual
servoing).
The
IBVS
is
explained
further
ahead
in
this
chapter.
The
applications
of
visually
guided
systems
are
many,
from
intelligent
homes
to
automobile
industry,
and
increasing,
and,
of
course,
robotics.
Vision
guided
robots
has
been
on
of
the
major
research
area
in
robotics
during
last
decades.
Along
with
this
growth,
some
software
and
applications
to
work
with
images
in
order
to
do
visual
servoing
have
appeared
in
the
recent
years.
An
example
of
this
software
is
the
OpenCV
library,
which
has
been
explained
before.
Another
distinction
has
to
be
made
inside
the
visual
servoing
methods,
depending
on
the
distance
between
the
camera
and
the
part
of
the
robot
that
has
to
move
to
the
desired
position
there
are
eye-to-hand
and
eye-in-hand
methods.
If
the
camera
is
located
on
the
centre
of
the
part
that
has
to
move,
its
called
eye-in-hand,
because
in
the
case
of
a
robotic
arm
the
camera
would
be
located
in
the
hand
that
has
to
move
to
the
desired
point.
If
the
camera
is
located
elsewhere,
and
therefore
a
transformation
has
to
be
made
to
the
velocities
commanded
to
the
robot,
its
called
eye-to-hand.
The
visual
servoing
developed
in
this
project
is
eye-in-hand
because
the
camera
is
in
the
quadcopter.
40
Goal:
The
goal
is
the
objective
of
the
task.
It
is
sent
to
the
server
(ActionServer)
from
the
client
(ActionClient).
This
can
be,
for
example,
a
PoseStamped
message
that
contains
information
about
where
the
robot
should
move
to
in
the
world,
in
case
of
a
mobile
robot.
Feedback:
The
feedback
provides
the
client
information
about
how
the
task
is
been
carried
out.
For
the
example
of
the
moving
robot,
the
feedback
could
be
the
position
of
the
robot
in
the
world
at
every
moment.
Result:
The
result
is
the
outcome
of
the
performed
task.
It
is
sent
from
the
server
to
the
client
only
once,
when
the
task
is
completed.
For
the
example
of
the
moving
robot,
the
result
could
be
the
final
pose
of
the
robot,
although
in
that
case
the
result
is
not
very
important.
41
Velocity
commands
Spooler
joypad
node
Landing
Control
Velocity
commands
Client
Feedback
/ Result
Start /
Preempt
Target
Detection
Velocity
commands
Feedback
/ Result
Start /
Preempt
Target
Tracking
Server
Server
AR Drone
driver
Navigation
data
Velocity
commands
Cameras
images
In
the
Fig.
38,
the
nodes
in
the
right
are
the
ones
that
perform
the
autonomous
landing
procedure.
There
is
the
master
node,
called
Landing
Control,
which
is
the
client
that
asks
the
Target
Detection
and
the
Target
Tracking
nodes
to
perform
its
respective
tasks.
The
Target
Detection
and
the
Target
Tracking
nodes
are
server
nodes,
which
send
the
feedback
to
the
master
node.
The
orange
arrows
represent
the
messages
created
by
the
Actionlib
library
in
order
to
establish
the
communication
between
clients
and
servers.
In
the
target
detection
feedback
message
there
is
the
target
position,
and
in
the
tracking
feedback
message
there
is
the
velocity
to
send
to
the
drone,
the
position
of
the
target
with
respect
to
the
centre
of
the
image
in
centimetres
and
a
variable
to
know
if
the
tracking
is
working.
The
result
message
of
the
Target
Detection
server
and
the
Tracking
server
are
empty
messages
because
there
is
no
information
to
send
to
the
master,
but
the
achievement
of
the
tasks.
Two
launchs
files
have
been
created
in
order
to
run
the
system.
The
first
launch
file
starts
the
AR.
Drone
driver,
the
Spooler
node,
the
Joypad
node
and
the
image_proc
node
(explained
before:
to
have
the
camera
images
rectified).
The
second
launch
file
starts
the
three
visual
servoing
nodes:
the
landing
control,
the
target
detection
and
the
tracking
nodes.
There
are
two
different
launch
files
instead
of
only
one
because
the
driver
takes
a
while
to
establish
communication
with
the
quadcopter,
and
the
visual
servoing
nodes
need
the
driver
to
be
running
to
start.
Another
thing
needed
to
run
the
system
is
the
template
image
file
to
perform
the
detection
part.
The
path
of
the
image
must
be
specified
in
the
code
of
that
node
(ANNEX
A.7.3
tag_detection_server.cpp)
to
perform
the
detection
of
the
template
and
that
image
must
have
the
appropriate
proportions.
42
Function
The drone takes off
Starts the Target Detection
node
Starts the Tracking node
Tries to find the lost target. If it
can not find it, start searching it
again
Lands the drone
NEXT STATE
SEARCHING
TRACKING: if the target is found
LANDING: if the approach to the target
had been ok
LOST: if the target had been lost
TRACKING: if the target has been found
SEARCHING: if the target has not been
found before 3 seconds
-
In
the
SEARCHING
state,
the
Target
Detection
node
is
started,
and
in
every
loop
a
feedback
from
this
node
is
received,
first
the
drone
is
situated
at
an
optimum
altitude
to
find
the
target
(between
800mm
and
1300mm)
and
then
it
is
moved
forwards
to
find
the
target.
In
the
TRACKING
state,
the
Tracking
node
is
started,
and
every
time
a
feedback
is
received,
a
velocity
command
is
sent
to
the
drone.
During
the
tracking,
the
velocity
commands
are
received
from
the
tracking
node,
which
computes
the
velocities
for
doing
the
visual
servoing
task
as
explained
later.
If
the
target
is
centred
in
the
frame,
a
down
velocity
is
sent.
When
the
target
is
lost,
the
LOST
state
is
set
to
try
to
find
the
target
again,
and
if
this
is
not
found,
the
system
will
change
to
the
SEARCHING
state
again.
When
the
LANDING
state
is
set,
a
forward
velocity
and
the
landing
command
are
sent
to
the
drone
to
make
it
land
centred
over
the
target.
This
node
has
a
function
that
sets
the
system
to
the
LANDING
state
to
land
the
drone
when
the
battery
is
almost
empty.
Another
function
in
this
node
is
to
print
in
the
screen
information
that
could
be
useful
during
the
operation
of
the
system
such
as
the
actual
state
of
the
system,
the
drones
battery,
the
altitude,
or
the
velocities
commands
among
others.
The
Target
Detection
node
and
the
Tracking
node
are
the
main
reason
of
the
modification
of
the
drone,
the
change
of
the
front
camera
angle
mentioned
before
in
this
project.
Since
the
camera
used
is
has
wide
angle
(92
diagonal
fisheye),
its
image
is
rounded,
so
a
processing
effect
that
corrects
the
round
effect
of
the
lens
is
needed.
This
processing
has
been
done
with
the
image_proc
ROS
package,
explained
before,
in
the
5.1.1.
Position
estimation
based
on
features.
43
Pros
No matters the size of the target
Colour
detection
Cons
It is not robust when the light
conditions are changing
Can be detected more things of the
same colour besides the target
To
use
the
colour
strategy,
more
things
should
be
done,
such
as
shape
comparison,
to
increase
the
robustness
of
the
detection.
In
addition,
the
lack
of
robustness
given
by
the
changing
light
conditions
is
very
difficult
to
solve
easily.
Template
matching
can
be
a
fast
and
effective
way
of
monitoring
the
position
of
an
object
within
the
image.
But
it
needs
some
other
processing
to
make
it
work
when
the
target
has
different
sizes
(seen
from
different
highs)
and
with
different
orientations.
Finally,
the
strategy
chosen
to
perform
the
detection
is
the
Template
matching
function
of
OpenCV
because
it
is
easier
to
do
the
processing
to
change
the
orientation
and
the
size
than
to
make
the
colour
detection
robust
in
changing
light
conditions.
44
!
Fig.
40.
First
target
tried
But
since
the
change
of
the
tracking
function,
for
reasons
explained
further,
the
target
with
the
circle
and
the
H
inside
wouldnt
work
any
more.
With
the
new
tracker
the
element
tracked
is
an
area
in
the
centre
of
the
target,
so
the
circle
around
the
H
was
no
necessary
any
more.
And
there
was
a
problem
with
the
transition
of
the
position
of
the
tracking
area
between
the
detector
and
the
tracker.
The
problem
is
that
the
detector
has
to
send
the
position
of
a
point
inside
the
area
to
track,
and
since
the
H
has
narrow
white
areas,
when
the
tracking
node
takes
the
central
position,
the
drone
could
has
moved
a
bit,
enough
to
get
a
point
outside
of
the
H.
For
that
reason
it
was
decided
to
make
a
target
with
a
bigger
H.
Several
targets
where
tried,
but
the
final
target
(Fig.
39)
was
one
with
a
bigger
area
in
the
centre
in
order
to
reduce
the
possibility
to
make
a
mistake
when
passing
the
point
from
the
tracker
to
the
detector
when
flying.
This
new
H
is
black,
because,
since
the
tracking
only
needs
a
white
area
surrounded
with
black
or
vice-versa,
it
works
as
well
as
the
white
H.
The
template
has
to
measure
the
half
of
an
A4
paper
because
it
is
the
size
that
the
detector
will
search
the
template.
So,
the
final
target
is
a
sheet
of
paper
with
the
template
inside
(Fig.
41).
45
Fig.
41.
Target
in
a
sheet
of
paper
To
detect
the
target
the
node
has
to
detect
the
sheet,
compare
to
the
template
and
decide
if
it
is
the
target
or
not.
Also,
to
detect
the
target
is
needed
to
make
the
function
works
if
the
template
is
rotated
and
has
a
different
size
of
the
template.
Thats
why
the
detection
node
is
structured
in
different
functions:
The
first
function,
called
findCountours
in
the
code
(ANNEX
A.7.3
tag_detection_server.cpp),
is
to
find
squared
shapes
and
only
polygons
with
four
edges.
To
do
this,
some
OpenCV
functions
are
used.
First,
the
Canny
function
is
performed
in
the
frame
to
get
the
edges,
to
find
polygons
with
these
edges
the
findCountors
function
is
called.
Then,
the
function
approxPolyDP
is
used
to
approximate
the
polygons
with
quadrangles.
Finally
the
polygons
with
four
edges
with
similar
angles
as
a
rectangle
are
selected.
There
is
implemented
the
drawSquares
function,
which
allows
us
to
see
the
detected
squares
(Fig.
42).
In
the
code,
this
function
is
not
performed
because
it
is
not
necessary
to
the
main
objective.
For
this
detection
function,
the
sheet
must
be
surrounded
by
a
dark
area
to
detect
the
white
square
easily.
46
This
is
the
template
searched
in
the
rectified
square,
which
is
obtained
from
the
four
corners
of
the
squares
detected.
The
four
corners
are
oriented
and
resized
to
the
correct
size
to
compare
with
the
template
(Fig.
44).
When
the
squares
are
resized,
the
MatchingMethod
function
is
carried
out.
This
is
the
main
function
of
the
code,
where
is
compared
the
squares
detected
with
the
template.
In
this
function
can
be
chosen
several
methods,
and
after
having
tested
all
of
them,
the
called
CV_TM_SQDIFF
has
been
proved
as
the
most
effective
for
this
purpose.
The
most
important
thing
inside
this
function
is
the
OpenCV
function
MatchTemplate,
which
slides
the
template
image
through
the
camera
frame
and
stores
the
comparison
results
in
the
result
matrix
Fig.
45.
This
matrix
is
a
grayscale
image
where
the
value
of
each
pixel
corresponds
to
how
close
of
a
match
it
is.
There
is
a
function
in
OpenCV
that
finds
the
pixel
with
the
value
that
has
more
likelihood
to
be
the
target
and
the
likely
target
position
within
the
image.
47
Fig.
45.
Result
matrix
When
the
result
matrix
looks
like
the
Fig.
45,
means
the
template
is
found
in
the
detected
square,
and
if
it
is
detected
during
5
consecutive
frames,
a
green
square
is
drawn
around
the
target
(Fig.
46).
Initially
there
was
another
function
implemented
in
this
node.
That
function
was
used
to
find
a
circle
within
the
target
when
it
is
found
and
then
take
five
points
of
the
perimeter
of
that
circle
to
pass
them
to
the
tracking
node
(Fig.
47),
but
since
the
tracking
strategy
had
been
changed,
this
function
was
no
useful
anymore,
so
we
decide
to
remove
it.
48
Fig. 47. Circle and points found in the first target tried
The
Target
Detection
node
sends
the
result
to
the
master
node
when
the
target
is
found
and
verified,
it
has
been
detected
during
5
consecutive
frames.
The
result
message
is
an
empty
message,
because
there
is
no
important
information
to
communicate
but
the
achievement
of
the
task.
In
the
feedback
message
there
is
the
position
of
the
target
and
two
variables
to
know
if
the
target
has
been
found.
As
explained
before,
to
start
the
tracking
procedure
is
necessary
to
pass
a
point
(x,y)
to
the
tracking
node.
This
point
will
be
the
centre
of
the
target,
the
black
area
of
the
H,
which
is
a
big
area
in
order
to
not
be
mistaken.
It
will
be
sent
to
the
tracking
node
by
two
parameters
(x
and
y
positions
in
the
frame).
This
node
was
begun
when
the
front
camera
(HD
and
wide
angle
camera)
was
not
turned
yet.
In
the
images
Fig.
49
and
Fig.
48
can
be
seen
the
difference
of
definition
among
both
images,
but
the
most
important
thing
is
that
with
the
HD
camera,
there
is
more
surface
covered,
so
the
target
will
be
detected
faster.
This
is
very
important
in
the
tracking
node
as
well.
49
50
Functioning
To
initialize
the
tracking
the
algorithm
needs
to
know
five
points
that
are
on
the
contour
of
the
ellipse
to
be
tracked.
On
the
first
iteration
the
program
initializes
the
tracking
and
the
pose
estimation
and
starts
to
track.
From
the
second
iteration
on
it
only
keeps
tracking
and
the
updates
the
estimated
position.
The
input
image
has
to
be
processed
so
that
the
tracker
is
able
to
work.
The
processing
includes
a
Gaussian
Blur
to
reduce
the
noise
and
a
Canny
Edges
detector
to
obtain
an
image
with
only
edges.
Tracking
parameters
The
tracking
parameters
are
very
sensitive
to
the
resolution
of
the
camera,
the
frames
per
second
to
be
processed
and
the
illumination
conditions.
They
are
declared
within
the
code
and
have
to
be
tuned
for
every
application.
Threshold:
The
higher
it
is,
the
sharper
the
transition
must
be
to
accept
a
point.
Using
a
low
value
facilitates
the
detection
of
an
edge
in
a
low
contrast
environment,
however
it
may
introduce
outliers
in
the
minimisation.
mu1
and
mu2:
These
values
are
used
to
reject
a
new
candidate
position
for
the
sample
point
if
the
new
convolution
is
too
small
(for
mu1)
or
too
high
(for
mu2)
compared
to
the
previous
one.
For
example,
if
mu1
=
mu2
=
0:5,
the
sample
point
is
accepted
only
if
the
value
of
the
new
convolution
is
between
50%
and
150%
of
the
previous
convolution.
This
procedure
allows
to
reject
points
with
a
different
transition
(black-to-white
instead
of
the
previous
white-to-black
for
example).
Range:
Corresponds
to
the
distance
in
pixel
along
the
normal
to
the
curve
where
the
new
edge
is
searched.
This
value
is
dependant
on
the
expected
displacement
of
the
edge
between
two
consecutive
images.
The
higher
the
value
is,
the
slower
will
be
the
algorithm
and
the
more
there
will
be
outliers.
Sample
step:
Corresponds
to
the
distance
between
two
consecutive
sample
points
on
a
curve.
If
the
object
is
very
simple,
and
if
the
environment
is
not
too
noisy,
a
high
value
can
be
sufcient.
51
Fig.
51.
Structure
of
the
circle
tracker
52
The
Target
tracking
node
sends
the
position
of
the
target,
the
velocity
calculated
and
a
variable
to
know
if
the
node
is
tracking
correctly
or
has
lost
the
target.
The
result
message
of
this
node
is
an
empty
message,
as
said
before,
because
there
is
no
information
to
transmit
but
the
accomplishment
of
the
task.
The
master
can
preempt
this
task
if
the
tracking
has
been
lost
for
more
than
3
seconds.
Then,
the
result
empty
message
is
sent
as
well
with
no
consequences.
53
!""#" = ! ! ! , ! !
Where
s
is
a
vector
of
visual
features,
m(t)
a
set
of
image
measurements,
usually
the
image
coordinates
of
interest
points
or
the
centroid
of
an
object
and
a
a
set
of
parameters
that
represent
potential
additional
knowledge
about
the
system.
s*
contains
the
desired
values
of
the
features.
In
the
case
of
image-based
control
m(t)
are
the
image-plane
coordinates,
in
pixels,
of
the
interest
points
and
a
the
camera
intrinsic
parameters.
The
control
law
is
the
one
shown
in
the
function
(3).
(3)
!! = ! !!!
Where
the
vc
is
the
velocity
for
the
robot,
L+
is
the
interaction
matrix
and
is
a
constant
that
has
to
be
negative
to
reduce
the
error.
The
interaction
matrix
must
be
approximated.
There
are
several
choices
for
constructing
the
approximate
Le+,
but
the
more
commonly
used
are
the
following.
54
Current:
For
this
method
the
current
depth
of
each
point
must
be
available.
(4)
Desired:
This
way
only
the
desired
depth
of
each
point
has
to
be
set.
(5)
!!! = !!!
!!! = !!!
Mean:
Le+^=
1/2*(Le
+
Le+*)
for
this
method
is
also
necessary
to
have
the
current
depth
of
each
point.
(6)
According
to
the
results
obtained
by
Franois
Chaumette
and
Seth
Hutchinson
[4]
the
better
method
was
the
mean
of
the
two
approximations,
so
initially
it
was
the
chosen
method
for
this
project.
Since
the
target
is
located
on
the
floor,
the
current
depths
of
the
points
correspond
to
the
altitude
of
the
quadcopter
that
can
be
obtained
from
the
altitude
sensor.
However
during
the
trials
the
method
that
proved
to
work
better
was
the
approximation
using
the
desired
position
and
then
this
is
the
method
implemented
in
the
last
version
of
the
code.
Problem
solving
This
library
is
aimed
mostly
to
robotic
arms,
which
makes
the
visual
servo
control
difficult
to
implement
in
a
robot
such
as
a
quadcopter.
In
the
case
of
a
robotic
arm
the
velocities
sent
are
more
accurately
executed,
and
especially
when
dealing
a
decrease
in
the
velocity
is
really
difficult
for
the
drone
to
reduce
in
time
and
not
to
overshoot
the
target.
To
solve
that
problem
it
has
been
imposed
a
maximum
velocity,
if
the
velocity
resulting
from
the
control
law
is
bigger
than
that,
the
velocity
sent
to
the
drone
will
be
the
maximum
value.
Flying
slower
it
is
easier
for
the
quadcopter
to
stop
or
change
direction
without
overshooting
the
target.
6.3.4. Calibration
of
the
bottom
camera
Visp
has
a
package
for
calibrating
the
camera.
The
user
has
to
edit
the
launch
file
to
add
the
camera
path.
The
package
launches
a
console
and
a
visual
interface.
The
user
has
to
point
the
camera
to
the
calibration
pattern
from
different
positions
and
angles.
Each
time
once
the
new
position
is
hold
the
user
has
to
click
on
the
display,
then
click
in
the
four
points
indicated
in
the
pattern
on
the
proper
order.
After
that
has
to
choose
the
next
image
and
repeat
the
process.
When
enough
images
had
been
taken
the
user
has
to
write
a
command
on
a
new
terminal
calling
the
calibrator
to
calculate
the
calibration
parameters
and
write
them
on
a
.calib
file.
55
56
7. Conclusions
The
Parrot
AR.
Drone
2.0
is
a
very
versatile
quadcopter,
as
can
be
seen
in
this
project
it's
possible
to
develop
many
robotic
applications
out
of
it.
It's
quite
resistant
to
small
crashes
and
blows
that
make
it
a
good
choice
for
programming
learning.
One
pro
is
it
has
Wi-Fi
which
makes
it
possible
to
run
the
programs
on
a
computer
while
receiving
all
the
data
from
the
sensors
and
sending
all
the
commands.
On
the
downside
it's
not
very
accurate
on
following
the
velocities.
Many
factors
like
a
clustered
environment,
or
air
currents
can
make
the
drone
a
bit
unstable,
even
enough
as
to
make
it
move
when
the
command
is
to
stay
still
and
hovering.
Also
when
some
of
these
conditions
met
the
quadcopter
may
find
more
difficult
to
progress
in
some
directions
than
others,
depending
on
the
direction
the
environment
is
pushing
it
on.
Also,
from
the
trials
it's
been
observed
that
the
amount
of
battery
can
also
affect
the
flight.
Under
the
same
velocity
commands,
the
drone
will
move
slower
when
the
battery
level
is
under
30%
approximately,
making
it
less
powerful
against
the
external
forces
mentioned
above.
Moreover,
the
movement
of
the
quadcopter
is
not
smooth
but
fluctuating
which
makes
the
video
feed
from
the
cameras
highly
changeable
and
full
and
so
makes
the
image
processing
more
difficult
to
implement.
With
the
position
estimation
based
on
features
has
been
demonstrated
that
with
the
system
proposed
in
this
project
(position
estimation
with
PTAM
with
a
front
looking
camera)
is
possible
to
estimate
the
position
of
the
drone
very
accurately
and
to
navigate
with
a
navigation
using
a
front
camera
without
previous
knowledge
of
the
environment.
A
thing
that
we
couldnt
achieve
in
this
project
is
to
get
the
PTAM
axes
orientated
according
to
the
initial
position
of
the
drone,
with
the
grid
always
on
the
floor
or
on
a
parallel
plane
to
the
ground.
The
position
estimation
based
on
phase
correlation
was
not
achieved
in
this
project
due
to
a
lack
of
time
and
knowledge.
Further
work
on
the
subject
would
be
necessary
to
successfully
implement
this
node.
As
can
be
expected,
is
in
this
case
impossible
to
assess
the
performance
of
this
node.
It
has
been
tested
the
odometry
accuracy
of
the
A.R
Drone
2.0
doing
position
keeping
and
it
has
been
proved
that
the
navigation
data
acquired
from
the
drone
is
not
accurate
enough
to
perform
the
navigation.
With
this
first
approach
of
the
autonomous
landing
procedure
(visual
servoing
part)
developed
in
this
project
has
been
demonstrated
that
a
landing
procedure
is
a
manoeuvre
that
can
be
achieved
with
very
few
sensors
and
a
camera.
One
thing
that
has
not
been
done
is
a
target
searching
strategy
because
we
had
no
navigation
when
developing
the
visual
servoing
part
since
the
front
camera
(used
to
estimate
the
position
with
PTAM)
was
turned
down.
57
Rosify
the
quadcopter.
Make
a
ROS
driver
for
the
quadcopter
that
can
control
the
robot
more
deeply,
for
example
that
controls
each
motor
separately.
Improve
the
communication
between
the
nodes
and
the
spooler,
especially
the
joystick
node,
to
reduce
the
number
of
topics.
Instead
of
one
topic
per
command
with
empty
messages,
use
only
a
few
topics
with
the
messages
containing
different
commands.
On
this
project
this
was
done
emulating
the
system
used
in
the
ardrone_autonomy
package,
but
in
the
end
there
are
too
many
topics.
Get
the
PTAM
axes
orientated
according
to
the
initial
position
of
the
drone,
with
the
grid
always
on
the
floor
or
on
a
parallel
plane
to
the
ground.
Try
to
make
the
PTAM
work
in
a
quadcopter
with
a
down
looking
camera
flying
at
a
higher
altitude.
Finish
the
phase
correlation
node
to
be
able
to
obtain
the
rotation
and
the
scale
from
the
camera
feed.
Complement
the
autonomous
landing
with
a
searching
strategy
that
permits
to
start
the
procedure
from
more
distance.
To
achieve
that,
navigation
is
needed
because
only
sending
velocity
messages
without
navigation
is
impossible
to
follow
a
path.
Since
in
this
project
the
front
HD
camera
was
turned,
there
was
no
navigation.
58
8. References
[1] Quigley,
M.;
Gerkey,
B.;
Conley,
K.;
Faust,
J.;
Foote,
T.;
Leibs,
J.;
Berger,
E.;
Wheeler,
R.;
Ng,
A.;
,
"ROS:
an
open-source
Robot
Operating
System,"
in
Proc.
Open-Source
Software
workshop
of
the
International
Conference
on
Robotics
and
Automation
(ICRA),
2009
[2] Hurtos,
N.;
Cuf',
X.;
Petillot,
Y.;
Salvi,
J.;
,
Fourier-based
registrations
for
two-dimensional
forward-looking
sonar
image
mosaicing,
Intelligent
Robots
and
Systems
(IROS),
2012
IEEE/RSJ
International
Conference
on
,
vol.,
no.,
pp.5298-5305,
7-12
Oct.
2012
[3] Klein,
G.;
Murray,
D.;
,
Parallel
Tracking
and
Mapping
for
Small
AR
Workspaces,
Mixed
and
Augmented
Reality,
2007.
ISMAR
2007.
6th
IEEE
and
ACM
International
Symposium
on
,
vol.,
no.,
pp.225-234,
13-16
Nov.
2007
[4] Chaumette,
F.;
Hutchinson,
S.;
,
Visual
servo
control.
I.
Basic
approaches,
Robotics
&
Automation
Magazine,
IEEE
,
vol.13,
no.4,
pp.82-90,
Dec.
2006
[5] Reddy,
B.S.;
Chatterji,
B.N.;
,
"An
FFT-based
technique
for
translation,
rotation,
and
scale-
invariant
image
registration,"
Image
Processing,
IEEE
Transactions
on
,
vol.5,
no.8,
pp.1266-1271,
Aug
1996
[6] Engel,
J.;
Sturm,
J.;
Cremers,
D.;
,
Camera-based
navigation
of
a
low-cost
quadcopter,
Intelligent
Robots
and
Systems
(IROS),
2012
IEEE/RSJ
International
Conference
on
,
vol.,
no.,
pp.2815-2821,
7-12
Oct.
2012
[7] Engel,
J.;
Sturm
J.;
Cremers
D.;
,
Accurate
Figure
Flying
with
a
Quadcopter
Using
Onboard
Visual
and
Inertial
Sensing,
In
Proc.
of
the
Workshop
on
Visual
Control
of
Mobile
Robots
(ViCoMoR)
at
the
IEEE/RJS
International
Conference
on
Intelligent
Robot
Systems
(IROS),
2012
[8] Chaumette,
F.;
Marchand,
E.;
Novotny,
F.;
Saunier,
A.;
Spindler,
F.;
Tallonneau,
R.;
,
Building
a
visual
servoing
task
visp
tutorial,
Lagadic
project,
http://www.irisa.fr/lagadic,
October
2011
[9] Chaumette,
F.;
Marchand,
E.;
Spindler,
F.;
Tallonneau,
R.;
Yol,
A.;
,
Computer
vision
algorithms
visp
tutorial,
Lagadic
project,
http://www.irisa.fr/lagadic,
July
2012
[10] Bradski,
G.;
Kaeller,
A.;
,
Learning
OpenCV:
Computer
Vision
with
the
OpenCV
Library,
O'Reilly
Media,
September
2008
[11] Souli,
J;
,
C++
Language
Tutorial,
cplusplus.com,
2008
[12] http://www.ros.org/wiki/
[13] https://github.com/AutonomyLab/ardrone_autonomy
59
60
ANNEX
A:
CODES
A.1
Joystick
node
A.1.1
joystick.cpp
//
Define
DEBUG_OUTPUT
to
enable
PRINTLN_DEBUG
output
when
not
using
ROS.
//
ROS
debug
level
output
is
toggled
at
runtime
using
rxconsole.
//#define
DEBUG_OUTPUT
//
=======================================
includes
#include
<iostream>
using
namespace
std;
#include
<errno.h>
#include
<fcntl.h>
#include
<unistd.h>
#include
<stdint.h>
#include
<stdio.h>
#include
<sys/stat.h>
#include
<sys/types.h>
#include
<linux/joystick.h>
#include
"Joystick.h"
using
namespace
std;
//
=========================================
defines
#define
MAX_ANALOG_VALUE
32767
#define
LINEAR_LIMIT
0.3
#define
ANGULAR_LIMIT
1
#define
VELOCITY_SCALE_X
1
#define
VELOCITY_SCALE_Y
1
#define
VELOCITY_SCALE_Z
1
#define
VELOCITY_SCALE_YAW
1
//
======================================
methods
//
---------------------------------------------------------------------------
Joystick::Joystick(int
argc,
char
**
argv)
{
if(argc==3){
if
(strcmp(argv[1],
"-p")
==
0)
{
ROS_INFO_STREAM("Using
joystick
device:
"
<<
argv[2]);
deviceName
=
"/dev/input/"
+
string(argv[2]);
}
}
if(deviceName.length()
==
0)
{
deviceName
=
DEFAULT_DEVICE_PATH;
ROS_INFO_STREAM("Using
DEFAULT
Device:
"
<<
deviceName);
}
}
Joystick::~Joystick()
{
}
//
---------------------------------------------------------------------------
int
Joystick::main(){
ROS_INFO_STREAM("init
entered");
//
And
create
a
timer
for
periodic
calls
to
read
Joy.
doWorkTimer_
=
nh_.createTimer(ros::Duration(0.1),
boost::bind(&Joystick::doWork
,this));
memset(&pad,
0,
sizeof(pad));
pad.fd
=
open(deviceName.c_str(),
O_RDONLY);
if
(pad.fd
<=
0)
{
close(pad.fd);
cerr
<<
"Failed
to
open
joystick
-
check
it
is
attached."
<<
endl;
61
62
back_flip,
back_flip,
back_flip,
back_flip,
63
64
A.1.2
joystick.h
#ifndef
_JOYSTICK_H_
#define
_JOYSTICK_H_
//
==========================================================
includes
#include
<ros/ros.h>
#include
<ardrone_msgs/Vel.h>
#include
<ardrone_msgs/Priority.h>
//
======================================================
external
defines
/*
*
BUTTON
MAPPING
INFORMATION
*
~~~~~~~~~~~~~~~~~~~~~~~~~~
*
Buttons
appear
to
be
indexed
from
0,
but
otherwise
keep
to
the
same
order
*
as
written
on
the
joypad
itself.
So
button
1
is
pad.bPos[0],
etc.
*/
#define
MAX_AXIS
16
#define
MAX_BUTTON
16
#define
DEFAULT_DEVICE_PATH
"/dev/input/js0"
typedef
struct
{
unsigned
char
axisCount;
unsigned
char
buttonCount;
int
fd;
int
version;
char
devName[80];
int
aPos[MAX_AXIS];
int
bPos[MAX_BUTTON];
bool
changed;
js_event
ev;
}
pad_data_t;
//
===========================================================
class
class
Joystick
{
65
66
67
68
A.2.2
spooler.h
#include
<ros/ros.h>
#include
<ardrone_msgs/Vel.h>
#include
<ardrone_msgs/Priority.h>
#include
<geometry_msgs/Twist.h>
#include
<std_msgs/Empty.h>
#include
"ardrone_autonomy/FlightAnim.h"
class
spooler
{
public:
spooler();
private:
void
SendVelocityMsg(const
ardrone_msgs::Vel::ConstPtr&
msg);
void
SendTakeoffMsg(const
ardrone_msgs::Priority::ConstPtr&
msg);
void
SendLandMsg(const
ardrone_msgs::Priority::ConstPtr&
msg);
void
SendResetMsg(const
ardrone_msgs::Priority::ConstPtr&
msg);
void
EndOfTakeover(const
ardrone_msgs::Priority::ConstPtr&
msg);
void
LeftFlip(const
ardrone_msgs::Priority::ConstPtr&
msg);
void
RightFlip(const
ardrone_msgs::Priority::ConstPtr&
msg);
void
BackFlip(const
ardrone_msgs::Priority::ConstPtr&
msg);
void
ForwardFlip(const
ardrone_msgs::Priority::ConstPtr&
msg);
void
TimerCallback(const
ros::TimerEvent&
event);
ros::NodeHandle
n;
69
70
71
A.3.2
first_controller.h
#include
"ros/ros.h"
#include
"ardrone_autonomy/Navdata.h"
#include
<ardrone_msgs/Vel.h>
#include
<ardrone_msgs/Priority.h>
class
controller
{
public:
controller();
void
controlCallback(const
ardrone_autonomy::Navdata::ConstPtr&
msg);
void
WaitingCallback(const
ros::TimerEvent&
event);
void
MovingCallback(const
ros::TimerEvent&
event);
private:
ros::Publisher
pub_takeoff;
ros::Publisher
pub_land;
ros::Publisher
pub_move;
ros::Subscriber
sub_data;
ros::NodeHandle
n;
ardrone_msgs::Vel
msg_move;
ros::Timer
timer_wait;
ros::Timer
timer_move;
bool
waiting,
moving;
int
seq;
enum
{LANDED
=
0,
TAKING_OFF
=
1,
MOVING
=
2,
STOPPING
=
3,
WAITING
=
4,
START_LANDING
=
5,
LANDING
=
6,
FINISHED
=
7}
state;
};
72
73
74
75
76
77
78
A.4.2
pose_control_ptam
#include
<ros/ros.h>
#include
<std_msgs/String.h>
#include
<std_msgs/Empty.h>
#include
<tf/transform_datatypes.h>
#include
<geometry_msgs/PoseWithCovarianceStamped.h>
#include
<ardrone_msgs/Vel.h>
#include
<ardrone_msgs/Priority.h>
#include
<ardrone_autonomy/Navdata.h>
class
pose_controller{
public:
pose_controller();
//Functions
void
poseCallback(const
geometry_msgs::PoseWithCovarianceStamped::ConstPtr&
msg);
void
controlCallback(const
ardrone_autonomy::Navdata::ConstPtr&
msg);
void
initCallback(const
ardrone_msgs::Priority::ConstPtr&
msg);
void
waypointCallback(const
ardrone_msgs::Vel::ConstPtr&
msg);
void
MovingCallback(const
ros::TimerEvent&
event);
void
LostCallback(const
ros::TimerEvent&
event);
void
ScaleCallback(const
ros::TimerEvent&
event);
void
WaitCallback(const
ros::TimerEvent&
event);
void
xCallback(const
ros::TimerEvent&
event);
void
yCallback(const
ros::TimerEvent&
event);
void
print();
private:
79
80
81
A.5.2
phase_correlation_camera.cpp
#include
"phase_correlation_camera.h"
//--------CALLBACK
CONTAINING
THE
IMAGE----------------------
void
PhaseCorrelation::controller(const
sensor_msgs::ImageConstPtr&
msg)
{
//Transform
the
image
to
opencv
format
cv_bridge::CvImagePtr
cv_ptr;
try
{
cv_ptr
=
cv_bridge::toCvCopy(msg,
enc::BGR8);
}
catch
(cv_bridge::Exception&
e)
{
ROS_ERROR("cv_bridge
exception:
%s",
e.what());
return;
}
82
Mat
image
=
cv_ptr->image;
imshow("image",
image);
waitKey(1);
//Transform
image
to
grayscale
cvtColor(image,
image2_in,
CV_RGB2GRAY);
//Image2
is
the
newest
image,
the
one
we
get
from
this
callback
//image1
is
the
image2
from
the
last
callback
(we
use
the
one
that
already
has
the
dft
applied.
Mat
image1_dft
=
last_image_dft;
//Image2,
preparation
and
dft
Mat
padded2;
//expand
input
image
to
optimal
size
int
m2
=
getOptimalDFTSize(
image2_in.rows
);
int
n2
=
getOptimalDFTSize(
image2_in.cols
);
//
on
the
border
add
zero
values
copyMakeBorder(image2_in,
padded2,
0,
m2
-
image2_in.rows,
0,
n2
-
image2_in.cols,
BORDER_CONSTANT,
Scalar::all(0));
Mat
planes2[]
=
{Mat_<float>(padded2),
Mat::zeros(padded2.size(),
CV_32F)};
Mat
image2,image2_dft;
merge(planes2,
2,
image2);
//
Add
to
the
expanded
another
plane
with
zeros
dft(image2,
image2_dft);
//Normalize
the
trans_mat
so
that
all
the
values
are
between
0
and
1
normalize(trans_mat,
trans_mat,
NORM_INF);
imshow("trans_mat_real",
trans_mat_real);
waitKey(1);
//Look
for
maximum
value
and
it's
location
on
the
trans_mat_real
matrix
double*
max_value;
Point*
max_location;
double
max_val;
Point
max_loc;
max_value
=
&max_val;
max_location
=
&max_loc;
ROS_INFO_STREAM("max_value: " << max_val << " - " << "max_location: " << max_loc);
83
84
A.5.3
phase_correlation_camera.h
#include
<ros/ros.h>
#include
<opencv2/core/core.hpp>
#include
<image_transport/image_transport.h>
#include
<cv_bridge/cv_bridge.h>
#include
<sensor_msgs/image_encodings.h>
#include
<opencv2/imgproc/imgproc.hpp>
#include
<opencv2/highgui/highgui.hpp>
#include
<opencv2/calib3d/calib3d.hpp>
#include
"sensor_msgs/Image.h"
#include
<iostream>
#include
<stdio.h>
#include
<stdlib.h>
#include
<ardrone_autonomy/Navdata.h>
using
namespace
std;
using
namespace
cv;
namespace
enc
=
sensor_msgs::image_encodings;
class
PhaseCorrelation
{
public:
ros::NodeHandle
nh_;
image_transport::ImageTransport
it_;
image_transport::Subscriber
image_sub_;
ros::Subscriber
navdata_sub_;
PhaseCorrelation();
void
controller(const
sensor_msgs::ImageConstPtr&
msg);
void
navdata(const
ardrone_autonomy::Navdata::ConstPtr&
msg);
bool
first;
int
pixels_x,
pixels_y;
float
mov_x,
mov_y;
float
mov_x_acc,
mov_y_acc;
int
h;
double
fl;
Mat
image2_in;
Mat
last_image_dft,image1_dft;
};
85
86
87
A.6.2.
pose_control_odom.h
#include
<ros/ros.h>
#include
<ardrone_msgs/Vel.h>
#include
<ardrone_msgs/Priority.h>
#include
<ardrone_autonomy/Navdata.h>
#include
<std_msgs/String.h>
#include
<tf/transform_datatypes.h>
#include
<control_toolbox/pid.h>
class
pose_controller{
public:
pose_controller();
//Functions
void
controlCallback(const
ardrone_autonomy::Navdata::ConstPtr&
msg);
void
print();
private:
ros::NodeHandle
n;
//Subscribers
and
publishers
ros::Publisher
pub_move;
ros::Publisher
pub_takeoff;
ros::Publisher
pub_land;
ros::Subscriber
sub_ardrone;
ardrone_msgs::Vel
msg_move;
ardrone_msgs::Priority
msg_takeoff;
ardrone_msgs::Priority
msg_land;
//Node
variables
enum
{TAKEOFF
=
0,
POSITION_KEEPING
=
1,
LANDING
=
2}
state;
double
x,
y,
z,
z_init,
yaw_init,
yaw,
yaw_rad;
float
delta_t;
double
margin,
margin_yaw;
double
x_vel,
y_vel,
z_vel,
yaw_vel;
control_toolbox::Pid
pid_x,
pid_y,
pid_z,
pid_yaw;
ros::Time
last_time,
time;
88
float
battery;
int
drone_state,
altd;
std::string
status,
drone,
info;
89
this,
_1),
90
91
92
93
init_takeoff
=
false;
init_tracker
=
false;
init_detector
=
false;
battery_low
=
false;
ai
=
true;
altd
=
0;
tag_x
=
0;
tag_y
=
0;
drone_state
=
0;
info
=
"Landing
control
node
started";
print();
A.7.2
landing_control.h
#include
<ros/ros.h>
#include
<iostream>
#include
<string>
#include
<boost/thread.hpp>
#include
<actionlib/client/simple_action_client.h>
#include
<actionlib/client/terminal_state.h>
#include
<visual_servoing/Tag_poseAction.h>
#include
<visual_servoing/trackingAction.h>
#include
<ardrone_msgs/Vel.h>
#include
<ardrone_msgs/Priority.h>
#include
<ardrone_autonomy/Navdata.h>
#include
<ardrone_autonomy/CamSelect.h>
typedef
actionlib::SimpleActionClient<visual_servoing::Tag_poseAction>
detect_client;
typedef
actionlib::SimpleActionClient<visual_servoing::trackingAction>
track_client;
class
land{
public:
land();
~land(void){}
//Functions
void
NavdataCallback(const
ardrone_autonomy::Navdata::ConstPtr&
msg);
void
detection_feedbackCb(const
visual_servoing::Tag_poseFeedbackConstPtr&
feedback);
void
detection_doneCb(const
actionlib::SimpleClientGoalState&
state);
void
tracking_feedbackCb(const
visual_servoing::trackingFeedbackConstPtr&
feedback);
void
tracking_doneCb(const
actionlib::SimpleClientGoalState&
state);
void
pid(float
gain,
float
error_x,
float
error_y);
void
LostCallback(const
ros::TimerEvent&
event);
void
print();
private:
ros::NodeHandle
nh_;
//Create
the
action
clients
detect_client
detection;
track_client
tracking;
//Subscribers
and
publishers
ros::Subscriber
sub_ardrone;
ros::Subscriber
sub_tag_feedback;
ros::Publisher
pub_takeoff;
ros::Publisher
pub_move;
ros::Publisher
pub_land;
ardrone_msgs::Priority
msg_takeoff;
ardrone_msgs::Vel
msg_move;
ardrone_msgs::Priority
msg_land;
//To
set
the
bottom
camera
ros::ServiceClient
client;
ardrone_autonomy::CamSelect
srv;
//Node
variables
94
A.7.3
tag_detection_server.cpp
#include
"tag_detection_server.h"
namespace
enc
=
sensor_msgs::image_encodings;
//
----------
Goal
callback
----------------------------------------------------------------------
//to
start
the
target
searching
when
required
for
the
master
void
TagDetection::goalCB(){
start
=
true;
Server_.acceptNewGoal();
//Make
sure
the
goal
hasn't
been
cancelled
between
it
was
found
and
we
accept
it,
as
between
his
time
period
preemt
callback
is
not
triggered
if(Server_.isPreemptRequested()){
preemptCB();
}
}
//
-------------
Preempt
callback
----------------------------------------
//to
cancel
the
goal
when
required
by
the
master
void
TagDetection::preemptCB(){
Server_.setPreempted();
restart
=
false;
}
//
---------
Camera
image
callback
---------------------------------------------------------------
//contains
the
images
void
TagDetection::image_cam(const
sensor_msgs::ImageConstPtr&
msg){
if
(start){
//If
the
restart
of
the
searching
is
required,
set
all
the
variables
to
its
initial
value
if
(restart){
start
=
false;
try_next
=
1;
trying
=
5;
found
=
false;
found_sure
=
0;
foundSure
=
false;
start
=
false;
templ_loaded
=
false;
restart
=
false;
}
else{
//Get
a
frame
cv_bridge::CvImagePtr
cv_ptr;
try{
cv_ptr
=
cv_bridge::toCvCopy(msg,
enc::BGR8);
}
catch
(cv_bridge::Exception&
e){
ROS_ERROR("tag_detection_server:
cv_bridge
exception:
%s",
e.what());
return;
}
frame
=
cv_ptr->image;
//Call
the
function
to
find
the
squares
findSquares(frame,
squares);
//Show
the
detected
squares
95
96
}
}
}
//
-----
Angle
function
--------------------------------------------------------------------
//to
check
if
the
countours
found
in
the
findSquares
function
double
TagDetection::angle(Point
pt1,
Point
pt2,
Point
pt0){
double
dx1
=
pt1.x
-
pt0.x;
double
dy1
=
pt1.y
-
pt0.y;
double
dx2
=
pt2.x
-
pt0.x;
double
dy2
=
pt2.y
-
pt0.y;
return
(dx1*dx2
+
dy1*dy2)/sqrt((dx1*dx1
+
dy1*dy1)*(dx2*dx2
+
dy2*dy2)
+
1e-10);
}
//-------
draWSquares
function
---------------------------------------------------------------------
//Drows
all
the
squares
in
the
image
void
TagDetection::drawSquares(
Mat&
image,
const
vector<vector<Point>
>&
squares
){
for(size_t
i
=
0;
i
<
squares.size();
i++){
const
Point*
p
=
&squares[i][0];
int
n
=
(int)squares[i].size();
polylines(image,
&p,
&n,
1,
true,
Scalar(0,255,0),
1,
CV_AA);
}
}
//-------
findTarget
function
---------------------------------------------------------------------
//Compare
the
squares
with
the
template
void
TagDetection::findTarget(Mat&
image,
const
vector<vector<Point>
>&
square,
Mat&
rotated,
Mat&
templ){
//Load
the
template
if
(templ_loaded
==
false){
templ
=
imread("/home/marc/electric_workspace/visual_servoing/templ_H.jpg",
1);
if
(templ.empty()){
cout
<<
"tag_detection_server:
Cannot
open
the
target
image"
<<
endl;
}
resize(templ,
templ,
Size(),
1,
1,
INTER_NEAREST);
templ_loaded
=
true;
}
if
(square.empty()){
found
=
false;
}
else{
//Normalize
the
squares
detected
for(size_t
i
=
0;
i
<
square.size();
i++){
//Get
the
four
points
of
the
square
vector<Point>
orig_square
=
square[i];
vector<Point>
not_a_rect_shape;
not_a_rect_shape.push_back(Point(orig_square[0]));
not_a_rect_shape.push_back(Point(orig_square[1]));
not_a_rect_shape.push_back(Point(orig_square[2]));
not_a_rect_shape.push_back(Point(orig_square[3]));
RotatedRect
box
=
minAreaRect(Mat(not_a_rect_shape));
box.points(pts);
if
(try_next
==
1){
src_vertices[0]
=
pts[2];
src_vertices[1]
=
pts[3];
src_vertices[2]
=
pts[1];
src_vertices[3]
=
pts[0];
}
else
if
(try_next
==
2){
src_vertices[0]
=
pts[1];
src_vertices[1]
=
pts[2];
src_vertices[2]
=
pts[0];
src_vertices[3]
=
pts[3];
}
else
if
(try_next
==
3){
src_vertices[0]
=
pts[0];
97
98
//If
it
is
found,
wait
a
bit
and
draw
a
green
rectangle
in
the
target,
if
not,
try
to
rotated
it
if
there
is
a
possible
target
if
(found
==
true){
//Find
it
during
5
consecutives
frames
to
set
founSure
to
true
found_sure++;
if
(found_sure
>=
5
||
(trying
<
5
&&
trying
>
0)){
foundSure
=
true;
}
else{
foundSure
=
false;
}
//Draw
a
rectangle
in
the
target
if
(foundSure
==
false){
//Show
me
what
you
got
rectangle(rotated,
matchLoc,
Point(x
+
templ.cols,
y
+
templ.rows),
Scalar(0,150,255),
2,
8,
0);
//Draw
an
orange
rectangle
in
the
target
line(frame,
src_vertices[0],
src_vertices[1],
Scalar(0,150,255),
5,
8,
0);
line(frame,
src_vertices[1],
src_vertices[3],
Scalar(0,150,255),
5,
8,
0);
line(frame,
src_vertices[3],
src_vertices[2],
Scalar(0,150,255),
5,
8,
0);
line(frame,
src_vertices[2],
src_vertices[0],
Scalar(0,150,255),
5,
8,
0);
}
else{
//Show
me
what
you
got
rectangle(rotated,
matchLoc,
Point(x
+
templ.cols,
y
+
templ.rows),
Scalar(0,255,0),
2,
8,
0);
//Draw
a
green
rectangle
in
the
target
line(frame,
src_vertices[0],
src_vertices[1],
Scalar(0,255,0),
5,
8,
0);
line(frame,
src_vertices[1],
src_vertices[3],
Scalar(0,255,0),
5,
8,
0);
line(frame,
src_vertices[3],
src_vertices[2],
Scalar(0,255,0),
5,
8,
0);
line(frame,
src_vertices[2],
src_vertices[0],
Scalar(0,255,0),
5,
8,
0);
//Find
the
centre
of
the
target
if
(src_vertices[0].x
<
src_vertices[3].x){
d_x
=
src_vertices[3].x
-
src_vertices[0].x;
tag_x
=
src_vertices[0].x
+
d_x/2;
}
else{
d_x
=
src_vertices[0].x-src_vertices[3].x;
tag_x
=
src_vertices[3].x
+
d_x/2;
}
if
(src_vertices[0].y
<
src_vertices[3].y){
d_y
=
src_vertices[3].y-src_vertices[0].y;
tag_y
=
src_vertices[0].y
+
d_y/2;
}
else{
d_y
=
src_vertices[0].y-src_vertices[3].y;
tag_y
=
src_vertices[3].y
+
d_y/2;
}
//Set
the
params
to
send
the
centre
of
the
target
to
the
tracking
node
nh_.setParam("/target/x",
tag_x);
nh_.setParam("/target/y",
tag_y);
//Set
the
action
state
to
succeeded
Server_.setSucceeded(result_);
restart
=
true;
}
//If
found
is
false
but
possible
is
true
}
else
if(possible
==
true){
//If
there
is
no
matching
target,
try
to
rotate
the
image
if
(try_next
==
4)
{try_next
=
1;}
else
{try_next
=
try_next
+
1;}
trying++;
}
return;
}
}
//
---------------
Main
-------------------------------------------------
int
main(int
argc,
char**
argv){
ros::init(argc,
argv,
"visual_servoing");
99
A.7.4
target_detection_server.h
#include
<ros/ros.h>
#include
<stdio.h>
#include
<image_transport/image_transport.h>
#include
<cv_bridge/cv_bridge.h>
#include
<sensor_msgs/image_encodings.h>
#include
"sensor_msgs/Image.h"
#include
<actionlib/server/simple_action_server.h>
#include
<visual_servoing/Tag_poseAction.h>
#include
<opencv2/core/core.hpp>
#include
<opencv2/imgproc/imgproc.hpp>
#include
<opencv2/highgui/highgui.hpp>
#include
"opencv2/objdetect/objdetect.hpp"
#include
"opencv2/video/tracking.hpp"
#include
"opencv2/calib3d/calib3d.hpp"
using
namespace
std;
using
namespace
cv;
namespace
enc
=
sensor_msgs::image_encodings;
typedef
actionlib::SimpleActionServer<visual_servoing::Tag_poseAction>
TagServer;
class
TagDetection{
public:
TagDetection();
~TagDetection(void){}
//Functions
void
goalCB();
void
preemptCB();
void
image_cam(const
sensor_msgs::ImageConstPtr&
msg);
double
angle(
Point
pt1,
Point
pt2,
Point
pt0
);
void
findSquares(
const
Mat&
image,
vector<vector<Point>
>&
squares
);
void
drawSquares(
Mat&
image,
const
vector<vector<Point>
>&
squares
);
void
findTarget(
Mat&
image,
const
vector<vector<Point>
>&
square,
Mat&
rotated,
Mat&
templ
);
void
MatchingMethod(
int,
void*
);
protected:
ros::NodeHandle
nh_;
100
A.7.5
tracker_server.cpp
#include
"tracker_server.h"
//
-----
Goal
callback
------------------------------------------------------------
//to
start
the
tracking
when
is
required
by
the
master
void
Tracking::goalCB(){
start
=
true;
Server_.acceptNewGoal();
//Make
sure
the
goal
hasn't
been
cancelled
between
it
was
found
and
we
accept
it,
as
between
his
time
period
preemt
callback
is
not
triggered
if(Server_.isPreemptRequested()){
preemptCB();
}
}
//
------
Preempt
callback
-------------------------------------
//to
cancel
the
goal
when
required
by
the
master
void
Tracking::preemptCB(){
Server_.setPreempted();
start
=
false;
first
=
true;
working
=
false;
taskPtr->kill();
delete
taskPtr;
}
//
------
Navdata
callback
------------------------------------------------------
//to
get
the
altitude
and
the
battery
percent)
void
Tracking::NavdataCallback(const
ardrone_autonomy::Navdata::ConstPtr&
msg){
altd
=
msg
->
altd;
battery
=
msg
->
batteryPercent;
}
//
------
Camera
info
callback
--------------------------------------------------
//to
get
the
camera
parameters
void
Tracking::camerainfo(const
sensor_msgs::CameraInfo&
msg){
sensor_msgs::CameraInfo
cam_info=msg;
cam
=
visp_bridge::toVispCameraParameters(cam_info);
}
//
------
Controller
callback
----------------------------------------------------
//contains
the
images
void
Tracking::controller(const
sensor_msgs::ImageConstPtr&
msg){
if
(start){
cv_bridge::CvImagePtr
cv_ptr;
try{
cv_ptr
=
cv_bridge::toCvCopy(msg,
enc::BGR8);
}
catch
(cv_bridge::Exception&
e){
ROS_ERROR("cv_bridge
exception:
%s",
e.what());
101
return;
}
frame
=
cv_ptr->image;
vpDisplay::display(I);
vpDisplay::flush(I);
dot.initTracking(I,
ip);
vpDisplay::flush(I);
first = false;
vpDisplay::display(I);
//Try
to
do
the
tracking
of
the
dot,
if
it
fails,
set
working
to
false
try{
//Track
the
dot
dot.track(I);
dot.display(I,
vpColor::cyan,
3);
vpFeatureBuilder::create(s,
cam,
dot);
v
=
taskPtr->computeControlLaw();
working
=
true;
}
catch
(...){
working
=
false;
SendPose();
}
102
103
A.7.6
tracker_server.h
#include
<ros/ros.h>
#include
<iostream>
#include
<stdio.h>
#include
<stdlib.h>
#include
<image_transport/image_transport.h>
#include
<cv_bridge/cv_bridge.h>
#include
<sensor_msgs/image_encodings.h>
#include
<opencv2/core/core.hpp>
#include
<opencv2/imgproc/imgproc.hpp>
#include
<opencv2/highgui/highgui.hpp>
#include
"sensor_msgs/Image.h"
#include
<ardrone_autonomy/Navdata.h>
#include
<conversions/camera.h>
#include
<actionlib/server/simple_action_server.h>
#include
<visual_servoing/trackingAction.h>
#include
<visp/vpConfig.h>
#include
<visp/vpImage.h>
#include
<visp/vpDot2.h>
#include
<visp/vpOpenCVGrabber.h>
#include
<visp/vpDisplayOpenCV.h>
#include
<visp/vpDisplayGDI.h>
#include
<visp/vpDisplayX.h>
#include
<visp/vpPoint.h>
#include
<visp/vpServo.h>
#include
<visp/vpFeatureBuilder.h>
#include
<visp/vpServoDisplay.h>
#include
<visp/vpConfig.h>
#include
<visp/vpVideoWriter.h>
using
namespace
std;
using
namespace
cv;
namespace
enc
=
sensor_msgs::image_encodings;
typedef
actionlib::SimpleActionServer<visual_servoing::trackingAction>
TrackServer;
class
Tracking{
public:
Tracking();
~Tracking();
//Functions
104
105
A.8.2
Priority.msg
bool
priority
A.8.3
Vector3.msg
#
This
represents
a
vector
in
free
space.
float64
x
float64
y
float64
z
A.8.4
Vel.msg
Vector3
linear
Vector3
angular
bool
priority
106