All posts by Tom Appleyard

AntBot: Tweaking the modules

The app should be in a working state, so now we shall do some very simple edits of the code.

To set this up properly, instantiate all 4 example modules as descrbied in the previous tutorial, call the Haferlach PI “HF” when registering it.

Tweaking the Combiner (Adjusting Weightings)

If you open up the WeightedCombiner you will see it works by taking the mean of all 4 modules, we’re going to edit this to give more preference to the Trig Path Integrator.

The combiner consists of a single function ‘nextCommand’ which works by calling the ‘getOpinion’ method on each module and storing their headings, it then performs some collection of operations on these to create it’s own heading to be returned.

In this case, the combiner simply takes the average of all 4 modules’ headings and returns this. Currently, the average gives an equal weighting to each – we want this to be skewed so jump to lines 28 and 29 and change the weighting of the modules from 0.25 on all to 0.7 on PI and 0.1 on the others.


double wAngle = PI[0] * 0.7 + VH[0] * 0.1 + SS[0] * 0.1 + HF[0] * 0.1;
double wDist = PI[1] * 0.7 + VH[1] * 0.1 + SS[1] * 0.1 + HF[1] * 0.1;
double[] weightedHeading = { wAngle, wDist };

Now we have a weighted combiner that favours the trig PI. This is in essence the basics of how a combiner works – but what if we want to condition the weightings on the status of the modules?

More Tweaking the Combiner (Examining state of modules)

Each module has a method called ‘getStatus()’ which returns a string describing what it is doing. Looking at the source code for a module will tell you what the format of this string is.

In this case, we want to condition the weighting on the distance from the nest – as such we need to look at the status of the trig path integrator whose status is a string of the format <antbotOrientation> <angleFromNest> <distanceFromNest>.

We can retrieve and split this into tokens with


String[] PI_status = navigationModules.get("PI").getStatus().split("\\s+");
double nestDistance = Double.valueOf(PI_status[2]);

Now we know the nest distance, we can simply surround the weighting with an if statement:


double wAngle;
double wDist;

if(nestDistance > 0.5)
{
wAngle = PI[0] * 0.25 + VH[0] * 0.25 + SS[0] * 0.25 + HF[0] * 0.25;
wDist = PI[1] * 0.25 + VH[1] * 0.25 + SS[1] * 0.25 + HF[1] * 0.25;
}
else
{
wAngle = PI[0] * 0.7 + VH[0] * 0.1 + SS[0] * 0.1 + HF[0] * 0.1;
wDist = PI[1] * 0.7 + VH[1] * 0.1 + SS[1] * 0.1 + HF[1] * 0.1;
}

 

Tweaking Visual Homing

To give a basic example of how tweaking a module would work, we shall change the type of pixelwise error calculation that the visual homing module uses.

Visual Homing works by taking in frames from the camera sensor  and calculating the average value of the pixels in the frame – this is done with the “calculateError()” function.

Open up VisualHoming and declare a new function “sumSquare()”:

 

private double sumSquare()
{
// Get difference
Core.subtract(currentFrame, homeFrame, diffFrame);

// Get square
Core.multiply(diffFrame, diffFrame, sqFrame);

// Get sum of the array
Scalar sum = Core.sumElems(sqFrame);
double errorArr[] = sum.val;
double ss = errorArr[0] / 2;

return ss;
}

Now go into calculateError() and replace “currentError = rootMeanSquare();” with “currentError = sumSquare();”.

Just like that we have modified the module.

AntBot: Setting up the App

Now that you have the projects set up and ready to start development, it is time to examine the code itself.

This post will cover ‘wiring up’ an App with the pre-packaged combiners and navigation modules.

What is Pre-Packaged?

With the AntBot codebase comes with 2 combiners and 4 navigation modules. The ‘Simple Combiner’ ignores all modules apart from one and issues that as the path to be followed. The ‘Weighted Combiner’ takes the average angle and distance of all 4 modules and submits it.

The Navigation modules represent Path Integrators that work through basic trigonometry and one based on Haferlach’s model. The other two implement visual homing based on pixel-wise error and the ‘Run-Down’ algorithm and a simplistic Systematic Search generator.

Setup

First, open MainActivity and declare the modules and combiner that you want to use at the top of the class (we will only use the trig path integrator for now):

WeightedCombiner weightedCombiner;
VisualHoming visualHoming;
TrigPathIntegration trigPathIntegration;
SystematicSearch systematicSearch;

The method ‘onCreate’ holds the actual setup code. First the combiner is instantiated and registered with the framework:

weightedCombiner = new WeightedCombiner();
setCombiner(weightedCombiner);

Now, the modules are set up – for each module it must be instantiated, subscribed to it’s feeds and registered with the combiner (where it is given a name so it can be identified), for example:

visualHoming = new VisualHoming();
cameraFragment.addSubscriber(visualHoming);
simpleCombiner.addModule("VH", visualHoming);

The trig path integrator has to be subscribed to the controller fragment and should be called “PI”. The systematic search generator should be subscribed to the trig path integrator and the controller fragment. It should be called “SS”.

If data is to be sent to the server the Network Fragment must be subscribed to the modules which will supply it with said information:

trigPathIntegration.addSubscriber(networkFragment);
visualHoming.addSubscriber(networkFragment);

Finally, a further step is needed for any modules that make use of OpenCV (such as the Visual Homing module), below onCreate is another method named onOpenCVLoaded – it is recommended that all vision based modules be placed into a dormant state until the library is loaded, after which they can be ‘woken up’ (this stops function calls being made to non-existant libraries):

visualHoming.enableVisualHoming();

This is all that setup consists of – pressing the Run app button should load the app onto the phone ready for use.

Swapping Modules

To swap modules in and out you simply need to comment out/delete their code. If you wanted to replace the trig path integrator with the haferlach path intergator you would simply have to do the following:

//trigPathIntegration = new TrigPathIntegration();
//controllerFragment.addSubscriber(trigPathIntegration);
//simpleCombiner.addModule("PI", trigPathIntegration);

haferlachPathIntegration = new HaferlachPathIntegration();
controllerFragment.addSubscriber(haferlachPathIntegration);
simpleCombiner.addModule(“PI”, haferlachPathIntegration);

Having said that, the system is of course module agnostic so it is more than possible to have the two modules coexist happily (but with one of them would have to be called something that isn’t PI).

The weighted combiner could be swapped for the simple combiner in the same way, but only one combiner can be used at a time.

 

Now we have the app working, let’s tweak the modules!

AntBot: Setting up the Development Environment

This guide expects you to have basic familiarity with Eclipse.

Download the project from GitHub

https://github.com/InsectRobotics/antbot

Download Android Studio, Eclipse & Arduino IDE

To begin with, download Android Studio and follow the instructions on the site – on Linux you may need to install extra packages so this is particularly important.

To compile the AntBotServer code you will also need Eclipse – specifically the ‘Eclipse IDE for Java Developers’.

After Downloading both, run them for the first time – Android Studio particularly may need to set up Android SDKs (for reference, AntBot is built for Android 4.4 and higher).

It should be noted that whenever I use the term ‘workspace’ within this guide it can refer to a space both programs use or separate ones.

The Ardunio IDE can be found here. Like the above, it will use a ‘workspace’ folder which it calls ‘sketches’. Arduino IDE requires no further setup outside of installation.

Dependencies

There are two libraries the AntBot app and AntBotServer depend on: USBSerialForAndroid (this is actually included in the source code) and OpenCV – both the desktop and android versions.

The Arduino code requires a library to monitor the wheel encoders called Encoder.

Set up OpenCV

Compiling OpenCV (hopefully optional)

Unless you are using Windows, this is required for the desktop version – I have included a compiled version of the library for linux which can be found under AntBotServer/opencv3.0.0/ubuntu-14.04. Hopefully this will work, if not or if you want to compile it yourself this guide will demonstrate how to compile it. If it does, skip to setting OpenCV up as a user library.

You will need the OpenCV source (from the above link) and cmake. Once you finish the ‘Build’ section of the guide, the desired files will be opencv-3.0.0/bin/opencv-300.jar and opencv-3.0.0/lib/libopencv_java300.so.

Now that there is a compiled version of OpenCV you can set it up as a user library in eclipse with this guide.  It should be noted that in the section of the guide that tells you to set the native path to ‘OpenCV-2.4.6/build/java/x64’ should actually say ‘OpenCV-2.4.6/lib’.

Installing OpenCV on the Android Device (hopefully optional)

Assuming you are testing with an Android device, you will need to load the OpenCV library onto it. Within the OpenCV Android zip there will be a folder called ‘apk’ – take the contents and follow this guide.

Importing OpenCV as an Android Module

Before you use the OpenCV Android library you will need to have it set up as a project in your workspace. Doing this is relatively simple – just place the OpenCV Android library in your workspace folder and perform either File -> Import Project or from the splash screen do Import Project and select the OpenCV-android-sdk folder from your workspace.

Import Projects

Now that the requirements are in place, simply import AntBot into Android Studio and AntBotServer into Eclipse using the same method as above. Android Studio may need to download a different version of the Android SDK to run – allow it to do so. Eclipse will require you to add the OpenCV user library to AntBotServer.

Allow USB Debugging

If you are just getting started or are doing this on a new computer, you will need to authorise USB debugging on your computer – when plugging in the Android Device this should automatically come as a pop up. If not, follow this guide.

Now it’s time to set up the app!

AntBot: Calibrating the Chassis

Once the chassis has been wired up the wheels may need to be calibrated.

Each wheel is equipped with a ‘wheel encoder’ that measures the wheel’s rotations. The next section will provide some background as to what a wheel encoder is and how they work. If you are already familiar with wheel encoders then simply note that out of the box, the encoders should provide 333 ticks per rotation and skip to the ‘Calibration’ section.

Wheel Encoders Overview

The wheels on the Rover 5 chassis are equipped with a device that allows them to self-monitor their progress called a ’wheel encoder’. Rover 5s use a type of wheel encoder called an ’optical encoder’ in which, in addition to the wheel the motor drives a disc (black/white disc on the left hand side of the image below) that is monitored by two infrared sensors embedded on the chip opposite it.

rover5

encoder_waves_sensors

 

Both sensors emit a sequence of electronic pulses, responding to what they detect at any given moment, crests denote white whereas troughs denote black. Individually either wave will give speed when the frequency of it’s crests are measured. If the order of the crests in the two is compared this will give direction (blue-red is forwards, red-blue is backwards).

The term ’tick’ is used in this section to denote a crest in either individual wave. In real terms a tick means that the disc has rotated enough that the sensor from which speed is derived is reading a new segment. As the angle of each segment is the same we can convert each ’tick’ into a fixed forward or backward movement (i.e. 1 tick = x metres) and use this to record how far the AntBot has moved.

encoder_tick

A single tick denotes that the disc has rotated enough for a single segment to elapse. According to the Rover 5 Specification, the optical disc is set up so that 333 ticks will denote a full wheel rotation.

encoder_rotation

The Rover 5 specification states that 333 encoder ticks equate to a full wheel rotation and that the circumference of each wheel is 20cm. as such, we can calculate a ratio between encoder ticks and forward movement.

 

Calibration – Ticks

An unfortunate reality of development with Hardware is that while the spec may claim a certain accuracy – it is often the case that this will not stand in practice.

With the Rover 5, testing of AntBot found that the left wheels and right wheels have different sensitivities, as such to be able to make readings from them you need to apply a scaling factor so that they all appear to be ticking at the same rate.

The scaling should mean that all encoders are scaled up to the same range as the most sensitive encoder (as this means you will be able to monitor the wheel more closely).

The process of doing this simply involves recording how many ticks the wheels produce over a certain period (over 1 metre or over 10 seconds) and calculating the ratio accordingly. Below we can see how many ticks are produced on AntBot’s chassis with no scaling:

encoder_rates_1_pin

Measured over 10 seconds, wheels 1 & 2 produce the same number, 4 slightly less and 3 much less. We therefore need to scale up 3 and 4.

Wheel 3 ticks ~3500 times when it should tick ~6000 times, it’s scaling factor is therefore 1.71 (as 3500 * 1.71 = 6000). 4 is adjusted using the same process.

 

Calibration – PWMs

The Pulse Width Modulation is effectively the speed of rotation of the wheel. In theory, if the same PWM is given to all wheels they should start rotating at the same rate. However this often not the case – when given the same PWM the wheels may rotate at different rates and as such the robot may drift like so:

drift

 

A second scaling system may need to be implemented to combat this. The scaling system would work by translating the PWM settings from one set of wheels into equivalent settings in the other that ensures the wheels spin at the same rate.

Below we can see a diagram that shows this equivalence. The blue line denotes what the PWM should be in theory (i.e. all wheels rotate a the same rate given the same PWM) and the red denotes what happens in practice (different PWMs are needed to have the same wheel spin rate).

pwm_ratio

 

Now it’s time to set up the development environment!

AntBot: Make Your Own AntBot

antbot_side_view

 

Above we can see AntBot ‘in the flesh. Ignoring the lego framework that supports the camera, to assemble your own AntBot you need the following*:

component

 

*You will also need some standard issue male-female copper wires to connect the boards as well as a Serial-USB cable to connect the Arduino to the smartphone.

The prices quoted are taken from Proto-Pic at the time of writing and as such it may be prudent to shop around in case these have changed. While a Nexus 5 is listed, the framework can theoretically be deployed on any Android smartphone with a sufficient level of processing power.

 

To connect the chassis to the motor driver board, simply connect as directed in the following. Each ‘channel’ corresponds to a wheel, i.e. Channel 1 -> Wheel 1 etc.

components_chassis

To connect the Ardunio to the motor driver board, connect like so:

components_arduino

 

The colours correspond to the channels in the picture above.

 

First step done, now it’s time to calibrate the chassis!