3D Printed RC boat

 

3D printed Remote Controlled model boat

This summer vacation we printed a RC boat model which we found on Thinginverse, it is designed bywersy, see http://www.thingiverse.com/thing:274054

boat_finished

Some pictures of the finishing boat, we printed in three parts on our Prusa I3 steel printer. After gluing the parts together, doing some sanding, applying primer and spraypainting, we added the motors and electronics.

Martijn is showing the final result.

martijn_happy

 

To control the boat we used a cheap ESP8266, which is an embedded micro processor, it has a built-in Wifi capabilities. So we wrote some software to run on the ESP chip, which is basically a web server that hosts an embedded html page with some javascript.

The DC motor (for the impeller) is salvaged from an old toy car, we create a small  MOSFET circuit to control the speed of the DC motor. The S9 servo can be controlled directly from the ESP8266.

schematic_mosfet

As a battery pack we used a cheap USB power bank, however, we soldered some additional wires directly on the 18650 batteries to power the DC motor and the servo.

After final assembly we took to boat to sail on the pond in front of our house. It did suprisingly well. The second try we had to inflate the rubber boat to rescue the RC boat, the issue was that the propeller became loose, well Martijn did not mind.

rescue_boat

We 3D printed another propeller and used a slightly different design, which turned out to work a lot better than the original propeller.

 

 

Software (ESP8266 arduino)

#include

#include
#include
#include

Servo myservo; // create servo object to control a servo
// twelve servo objects can be created on most boards

const int SERVO_PIN = 13;
const int MOTOR_PIN = 14;

static int inByte = 0;
static int servoAngle = 90;
static int curServoAngle = 90;
static int motorPwm = 0;
static bool debug = false;
static int loopCnt = 0;

//#ifdef USE_SERIAL

static void UpdateServoMotor()
{
myservo.write(curServoAngle);
analogWrite(MOTOR_PIN, motorPwm);

if ( curServoAngle < servoAngle) ++curServoAngle; if ( curServoAngle > servoAngle) --curServoAngle;
}

static void SetServoAngle( int pos_in_degrees)
{

if ( pos_in_degrees < 60 ) pos_in_degrees = 60; if ( pos_in_degrees > 120 ) pos_in_degrees = 120;

if ( debug )
{
Serial.print("servoAngle to : ");
Serial.print(pos_in_degrees);
Serial.println();
Serial.flush();
}

servoAngle = pos_in_degrees;
}

static void ChangeMotorPwm( int deltaPwm)
{
motorPwm += deltaPwm;

if ( motorPwm < 0 ) motorPwm = 0; if ( motorPwm > PWMRANGE ) motorPwm = PWMRANGE;

if ( debug )
{
Serial.print("ChangeMotorPwm to : ");
Serial.print(motorPwm);
Serial.println();
Serial.flush();
}
}

const char *ssid = "EspBoat";
const char *password = "thereisnospoon";

ESP8266WebServer server(80);

static char page_txt[] = {
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\t\n"
"\n"
"

\n"
"\n"
" \n"
"\n"
"\n"
"

Boot Besturing version 1.0

\n"
"

Throttle=?

\n"
"

Rudder=?

\n"
"\n"
"\n"
"

\n"
"\t

\n"
"\t\t

\n"
"\t\t

\n"
"\t\t

\n"
"\t

\n"
"\t

\n"
"\t\t

\n"
"\t\t

\n"
"\t\t

\n"
"\t

\n"
"\t

\n"
"\t\t

\n"
"\t\t\t

\n"
"\t\t

\n"
"\t

\n"
"

\n"
"\t\n"
"
\n"
"

dbg

\n"
"\n"
"\n"
"\n"
"\n"
""
""};

// return main page with java script at http://192.168.4.1 in a web browser
void handleRoot() {
Serial.print("Sending page...");
Serial.println(page_txt);
Serial.println("done...");
server.send(200, "text/html", page_txt);
}

void handleBoat() {
String getAction=server.arg("action");

if ( debug )
{

if ( getAction.length() > 0)
{
Serial.print("Handle boat...");
Serial.print(" action is :");
Serial.print(getAction);
Serial.println(":");

}
}

if (getAction == "stop")
{
servoAngle = 90;
motorPwm = 0;
}
else if (getAction.startsWith("throttle_fwd") )
{
ChangeMotorPwm(+90);
}
else if (getAction.startsWith("throttle_rev") )
{
ChangeMotorPwm(-90);
}
else if (getAction.startsWith("rudder_port"))
{
SetServoAngle( servoAngle - 4 ) ;
}
else if (getAction.startsWith("rudder_starboard"))
{
SetServoAngle( servoAngle + 4 ) ;
}

String responseTxt = "{ \"rudder\" : ";

responseTxt += curServoAngle;
responseTxt += ", \"throttle\" : ";
responseTxt += (motorPwm * 100) / PWMRANGE;
responseTxt += "}";

if ( debug ) {
Serial.print(" sending response:");
Serial.println(responseTxt);
}

server.send(200, "api/json", responseTxt);
}

void setup() {

UpdateServoMotor();

delay(1000);
Serial.begin(115200);
Serial.println();
Serial.println("(c) Albert & Martijn Faber, RC boat version 1.0");
pinMode(SERVO_PIN, OUTPUT);
myservo.attach(SERVO_PIN);

Serial.print("Configuring access point...");
WiFi.softAP(ssid, password);

IPAddress myIP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(myIP);
server.on("/", handleRoot);
server.on("/api/boat", handleBoat);
server.begin();
Serial.println("HTTP server started");

// get max power
WiFi.setOutputPower(20.5);
}

void loop() {
server.handleClient();

#ifdef USE_SERIAL
if (Serial.available() > 0)
{
inByte = Serial.read();

switch ( inByte )
{
case '1': SetServoAngle(130); break;
case '2': SetServoAngle(120); break;
case '3': SetServoAngle(110); break;
case '4': SetServoAngle(100); break;
case '5': SetServoAngle( 90); break;
case '6': SetServoAngle( 80); break;
case '7': SetServoAngle( 70); break;
case '8': SetServoAngle( 60); break;
case '9': SetServoAngle( 50); break;

case 'a': ChangeMotorPwm( -10 ); break;
case 's': ChangeMotorPwm( -100 ); break;
case 'd': ChangeMotorPwm( 10 ); break;
case 'f': ChangeMotorPwm( 100 ); break;
case '0':
ChangeMotorPwm( 90 );
SetServoAngle( 40);
break;

case '?':
Serial.print("HELP .... ");
break;
case 'D':
{
debug = !debug;
}
break;
}
}
#endif

if (debug)
{
if ( (loopCnt % 100)==0 )
{
Serial.print("Debug => ");
Serial.print("servoAngle : ");
Serial.print(servoAngle);
Serial.print(" curservoAngle : ");
Serial.print(curServoAngle);
Serial.print(" motorPwm : ");
Serial.print(motorPwm);
Serial.println();
}
}

UpdateServoMotor();
delay(10);
loopCnt++;

}

This entry was posted in Electronics, software, Uncategorized. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *