- prepared a radio controlled boat to operate on an Arduino Uno board,
- set up the general software architecture that follows a modular, multi-tasking approach
- Made the boat change state between Manual and Autonomous by 'switching gears' on the RC control.
Note: the full software is available on GitHub.
Controlling the Movement
As was mentioned earlier, the motor controller is a SparkFun Motor Driver Shield. The product page gives detailed schematics of the motor shield, and also provides example code. Based on this, the propulsion becomes a matter of copying and pasting, with a few modifications://Radio controls for Propulsion
#define MOTOR 3
#define MOTOR_RICHTING 12
static int fade = 0;
void Motor_Init(){
pinMode( MOTOR, OUTPUT); //Set control pins to be outputs
pinMode( MOTOR_RICHTING, OUTPUT);
}
/**
* Manual control motor controller
*/
static byte mdir = 0;
void Motor_ManualControl(){
if( !State_IsManual() )
return;
byte dir = RCP_Direction();
if( RCP_Forward() ){
if( dir != mdir ){
forw(); //Set Motors to go
forward Note : No pwm is defined with the for function, so that fade in and out works
fadein(); //fade in from 0-255
}
forward(); //continue full speed forward
}else if ( RCP_Backward() ){
if( dir != mdir ){
back(); //Set motors to
revers. Note : No pwm is defined with the back function, so that fade in and out works
fadein(); //fade in from 0-255
}
backward(); //full speed backward
}else if ( RCP_Stop() ){
stopped(); // stop for 2 seconds
}
mdir = dir;
//Serial.print( dir );
}
void forw() // no pwm defined
{
digitalWrite(MOTOR_RICHTING, HIGH); //Reverse motor direction, 1 high, 2 low
}
void back() // no pwm defined
{
digitalWrite(MOTOR_RICHTING, LOW); //Set motor direction, 1 low, 2 high
}
void forward() //full speed forward
{
digitalWrite(MOTOR_RICHTING, HIGH); //Reverse motor direction, 1 high, 2 low
analogWrite(MOTOR, 255); //set both motors to run at (100/255 = 39)% duty cycle
}
void backward() //full speed backward
{
digitalWrite(MOTOR_RICHTING, LOW); //Set motor direction, 1 low, 2 high
analogWrite(MOTOR, 255); //set both motors to run at 100% duty cycle (fast)
}
void stopped() //stop
{
digitalWrite(MOTOR_RICHTING, LOW); //Set motor direction, 1 low, 2 high
analogWrite(MOTOR, 0); //set both motors to run at 100% duty cycle (fast)
}
void fadein()
{
// fade in from min to max in increments of 5 points:
for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5)
{
// sets the value (range from 0 to 255):
analogWrite(MOTOR, fadeValue);
// wait for 30 milliseconds to see the dimming effect
delay(30);
}
}
void fadeout()
{
// fade out from max to min in increments of 5 points:
for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5)
{
// sets the value (range from 0 to 255):
analogWrite(MOTOR, fadeValue);
// wait for 30 milliseconds to see the dimming effect
delay(30);
}
}
void astop() //stop motor A
{
analogWrite(MOTOR, 0); //set both motors to run at 100% duty cycle (fast)
}
The majority of the functions are provided on the SparkFun website. The only new function is
Motor_ManualControl()
,
which uses these functions to respond to the radio controls. Obviously, the Rudder control can be controlled in a similar fashion, when a motor is used.
This control depends on the mechanics of the boat that is used, as so the example code will not be included here.In our particular case, we decided to change the boat a bit, so that the servo motor that is shipped with the Arduino Starter Kit could be used instead. The resulting code is as follows:
#include <Servo.h>
#define RUDDER 2 //input 2
#define MAX_ANGLE 17 //maximum turn of the angle
Servo rudder;
int angle;
void Rudder_Init(){
//Activeer roer
rudder.attach( RUDDER );
angle = 0;
}
/**
* Manual control motor controller
*/
void Rudder_ManualControl(){
if( !State_IsManual() )
return;
byte dir = RCD_Steering();
if( RCD_Left() ){
Rudder_Right();
}else if ( RCD_Right() ){
Rudder_Left();
}else if ( RCD_Straight() ){
Rudder_Straight(); //reset
}
rudder.write( MAX_ANGLE + angle );
}
void Rudder_Right(){
if( angle < MAX_ANGLE )
angle++;
rudder.write( MAX_ANGLE + angle );
}
void Rudder_Left(){
if( angle > 0 )
angle--;
rudder.write( MAX_ANGLE + angle );
}
void Rudder_Straight(){
rudder.write( MAX_ANGLE );
}
This code uses the default
Servo.h
library that is provided
with the Arduino IDE. The code was based on Project
Five, "Mood Cue", from the Arduino Projects Book that is shipped with
the starter kit. A definite advantage of the servo is that the rudder does not have to move between its maximum angle, but instead can move
gradually by removing the 'Straight' option, to which the rudder defaults if no pulse is detected from the radio controller. With this, only one more tab is needed to make the software compile without problems, and give the boat some autonomy. Add an
'Autonomy'
tab and add code according to the following template:enum Steps{
ST_REST = 0,
ST_FORWARD = 5,
ST_TURN = 10,
ST_BACK = 15
};
static int step = ST_REST;
void Autonomous_Init(){
step = ST_REST;
}
void Autonomous_Update(){
step++;
}
void Autonomous_Motion(){
if( !State_IsAutonomous() )
return;
switch( step ){
case ST_REST:
break;
case ST_FORWARD:
fadein();
forw();
break;
case ST_TURN:
Rudder_Right();
forw();
break;
case ST_BACK:
forw();
fadeout();
break;
default:
break;
}
}
This piece of codeis called when the 'switch gears' action has been carried out, and consists of a number of steps (in seconds), in which the boat will automatically carry out some of the motor and rudder tasks. In this case, the boat moves away, turns and comes back, but of course you are free to implement your own schedules. you could even record a movement with the radio control, for instance when you tip the left gear in autonomous mode, which is carried out the next time 'autonomy' is selected! Have fun with your ro-boat!