Skip to content

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


Last update: June 18, 2022