Final Project¶
Ali Redha and I worked on making a bluetooth control boat using Adafruit Feather.
Main Documentation¶
Click here for the project documentation
Research¶
In this project, an adafruit feather board was programmed to control the motion of a simple boat through Bluetooth signals by linking the bluefruit app to the board and using control pad.
Materials¶
Qty | Description | Price | Link | Notes |
---|---|---|---|---|
1 | Adafruit Feather | $37.50 | https://www.adafruit.com/product/4516 | |
1 | 9 Volt battery | $6.19 | http://amazon.com/test | |
2 | Motors | $5.51 | http://amazon.com/test | |
2 | Fans | $4.50 | http://amazon.com/test | |
1 | L298N Motor Driver | $11.49 | http://amazon.com/test | |
1 | Breadboard | $5.99 | http://amazon.com/test | |
20 | Jumpers | $3.40 | http://amazon.com/test | |
1 | WaterProof Tape | $3.00 | http://amazon.com/test |
2D Boat Modeling¶
The boat was designed using the TinkerCad website The minimum boat volume to float= Load Mass/(Water Density-Boat Density) = 2kg/(1030-48)kg =0.002m^3
The 3D design has transformed into 2D parts using Papercraft Maker Website The design was obtained by laser cutting using a cutting machine.
For more about Computer controlled cutting process
Input & Output device¶
Using the BluefruitConnect smartphone application to control the motors. While the boat requires two motors, and the microcontroller was not delivering a specific amount of current and voltage for the motors, an L298N Motor Driver will be helpful to allow controlling the two motors.
Connections¶
In the motor driver, the A&B motors are connected to the four outputs, 9 Volt battery connected to VS and GND, another connection for GND to the GNC pin in the adafruit, the inputs connections are: in1 = 10, in2 = 11, in3 = A4, in4 = A5.
The motors motion principle¶
After uploading the code which is noted down, we link the BluefruitConnect app to the board using control pad.
For more about Input & Output device
Testing¶
Code¶
#include <bluefruit.h>
int in1 = 10;
int in2 = 11;
int in3 = A4;
int in4 = A5;
// OTA DFU service
BLEDfu bledfu;
// Uart over BLE service
BLEUart bleuart;
// Function prototypes for packetparser.cpp
uint8_t readPacket (BLEUart *ble_uart, uint16_t timeout);
float parsefloat (uint8_t *buffer);
void printHex (const uint8_t * data, const uint32_t numBytes);
// Packet buffer
extern uint8_t packetbuffer[];
void setup(void)
{
Serial.begin(115200);
while ( !Serial ) delay(10); // for nrf52840 with native usb
Serial.println(F("Adafruit Bluefruit52 Controller App Example"));
Serial.println(F("-------------------------------------------"));
Bluefruit.begin();
Bluefruit.setTxPower(4); // Check bluefruit.h for supported values
// To be consistent OTA DFU should be added first if it exists
bledfu.begin();
// Configure and start the BLE Uart service
bleuart.begin();
// Set up and start advertising
startAdv();
Serial.println(F("Please use Adafruit Bluefruit LE app to connect in Controller mode"));
Serial.println(F("Then activate/use the sensors, color picker, game controller, etc!"));
Serial.println();
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);
}
void startAdv(void)
{
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
// Include the BLE UART (AKA 'NUS') 128-bit UUID
Bluefruit.Advertising.addService(bleuart);
// Secondary Scan Response packet (optional)
// Since there is no room for 'Name' in Advertising packet
Bluefruit.ScanResponse.addName();
/* Start Advertising
* - Enable auto advertising if disconnected
* - Interval: fast mode = 20 ms, slow mode = 152.5 ms
* - Timeout for fast mode is 30 seconds
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
*
*
*/
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
}
/**************************************************************************/
void loop(void)
{
// Wait for new data to arrive
uint8_t len = readPacket(&bleuart, 500);
if (len == 0) return;
// Got a packet!
// printHex(packetbuffer, len);
// Color
if (packetbuffer[1] == 'C') {
uint8_t red = packetbuffer[2];
uint8_t green = packetbuffer[3];
uint8_t blue = packetbuffer[4];
Serial.print ("RGB #");
if (red < 0x10) Serial.print("0");
Serial.print(red, HEX);
if (green < 0x10) Serial.print("0");
Serial.print(green, HEX);
if (blue < 0x10) Serial.print("0");
Serial.println(blue, HEX);
}
// Buttons
if (packetbuffer[1] == 'B') {
uint8_t buttnum = packetbuffer[2] - '0';
boolean pressed = packetbuffer[3] - '0';
Serial.print ("Button "); Serial.print(buttnum);
if (pressed){
if (pressed & buttnum==5 ) {
Serial.println(" pressed");
digitalWrite(in2, HIGH);
digitalWrite(in3, LOW); //forward ok
digitalWrite(in1, LOW);
digitalWrite(in4, HIGH);
}
if (pressed & buttnum==8 ) {
Serial.println(" pressed");
digitalWrite(in2, HIGH);
digitalWrite(in3, LOW); //right ok
digitalWrite(in1, LOW);
digitalWrite(in4, LOW);
}
if (pressed & buttnum==7 ) {
Serial.println(" pressed");
digitalWrite(in3, LOW);
digitalWrite(in2, LOW); //left ok
digitalWrite(in1, LOW);
digitalWrite(in4, HIGH);
}
if (pressed & buttnum==6 ) {
Serial.println(" pressed");
digitalWrite(in1, HIGH);
digitalWrite(in4, LOW); //reverse ok
digitalWrite(in2, LOW);
digitalWrite(in3, HIGH);
}
}
else {
Serial.println(" released");
digitalWrite(in1, LOW);
digitalWrite(in4, LOW); //reverse ok
digitalWrite(in2, LOW);
digitalWrite(in3, LOW);
}
}
// GPS Location
if (packetbuffer[1] == 'L') {
float lat, lon, alt;
lat = parsefloat(packetbuffer+2);
lon = parsefloat(packetbuffer+6);
alt = parsefloat(packetbuffer+10);
Serial.print("GPS Location\t");
Serial.print("Lat: "); Serial.print(lat, 4); // 4 digits of precision!
Serial.print('\t');
Serial.print("Lon: "); Serial.print(lon, 4); // 4 digits of precision!
Serial.print('\t');
Serial.print(alt, 4); Serial.println(" meters");
}
// Accelerometer
if (packetbuffer[1] == 'A') {
float x, y, z;
x = parsefloat(packetbuffer+2);
y = parsefloat(packetbuffer+6);
z = parsefloat(packetbuffer+10);
Serial.print("Accel\t");
Serial.print(x); Serial.print('\t');
Serial.print(y); Serial.print('\t');
Serial.print(z); Serial.println();
}
// Magnetometer
if (packetbuffer[1] == 'M') {
float x, y, z;
x = parsefloat(packetbuffer+2);
y = parsefloat(packetbuffer+6);
z = parsefloat(packetbuffer+10);
Serial.print("Mag\t");
Serial.print(x); Serial.print('\t');
Serial.print(y); Serial.print('\t');
Serial.print(z); Serial.println();
}
// Gyroscope
if (packetbuffer[1] == 'G') {
float x, y, z;
x = parsefloat(packetbuffer+2);
y = parsefloat(packetbuffer+6);
z = parsefloat(packetbuffer+10);
Serial.print("Gyro\t");
Serial.print(x); Serial.print('\t');
Serial.print(y); Serial.print('\t');
Serial.print(z); Serial.println();
}
// Quaternions
if (packetbuffer[1] == 'Q') {
float x, y, z, w;
x = parsefloat(packetbuffer+2);
y = parsefloat(packetbuffer+6);
z = parsefloat(packetbuffer+10);
w = parsefloat(packetbuffer+14);
Serial.print("Quat\t");
Serial.print(x); Serial.print('\t');
Serial.print(y); Serial.print('\t');
Serial.print(z); Serial.print('\t');
Serial.print(w); Serial.println();
}
}
Assembly¶
For the boat’s assembly we have used vynil and laser cuttign
For more about Computer controlled cutting
We have decorated the boat by stars and “FABLAB” term
Hero Shot¶
Files: VINYL DESIGN Laser Cut