Ali Redha and I worked on making a bluetooth control boat using Adafruit Feather.
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
We chose this design specifically because it allowed maximum floating with the weights that we needed to load on it.
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 ¶
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(); } }