Skip to content

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(); } }


Last update: April 21, 2022