Autonomous Search and Rescue Surfboard



About: The BCAMRL is a Mechatronics Research Lab, founded in 2014 on the campus of Bergen County Academies, a magnet high school within the Bergen County Technical School District. Students create innovations base...

The Life board is designed with a single simple purpose in mind, to help lifeguards save lives. The process of saving lives is however not so simple. In each case of a rescue there is a different set of circumstances involved. It is for this reason that the Life board comes equipped with many functions to make each unique rescue as simple and easy as possible. The Life board, other than its obvious use as a rescue board, comes with a retractable netting in the front of the board that can scoop the victim up and raise them up to the level of the board. This would be especially useful for rescues involving an unconscious victim. This netting occupies approximately one third of the board’s total length depending on the specific size preferences. A Pixy camera mounted on an Adafruit mini pan-tilt allows for the board to track a lifeguard or another subject. In addition to this, the Life board is self-propelling, utilizing a combination of a bilge pump and a motor.

Teacher Notes

Teachers! Did you use this instructable in your classroom?
Add a Teacher Note to share how you incorporated it into your lesson.

Step 1: Parts List

  • 3' x 2' XPS foam board
  • 3' x 2' plywood board
  • LCD panel
  • watertight plastic casing box
  • PIXY camera
  • bilge pump
  • 2" PVC coupler
  • 3/4" PVC elbow (x 2)
  • 3/4 inch T-connector PVC
  • Arduino Uno Board
  • Netting

Step 2: Creating a Template for the Shape of the Board

Utilizing the 8'4" Clark Foam Board model by Roger Hinds and Rich Harbour, prototype the shape of the board by scaling it to a 3' x 2' board. Trace the dimensions onto a template.

Step 3: Finalizing the Board Shape

Trace the outline of the template onto a 3' x 2' plywood board and two 3' x 2' XPS foam boards. Stack the three board variants on top of one another, placing the plywood board in between the two XPS boards. Secure the three boards together using clamps. File the 3 boards simultaneously in order to achieve uniform shape.

Step 4: Prepping Holes for Other Components

Cut a 3" diameter hole in the XPS foam board centered 1" from the front of the board. Place a 3" diameter, 3 " tall piece of PVC piping on the plywood board, securing it using a combination of 3 L-brackets and screws. On the other XPS foam board, cut a 3.5" x 4.5" centered rectangular hole in the board, the longer side perpendicular to the board. Place the plastic casing box in the hole, and drill a .5" hole in the center for wires to pass through, keeping in mind to go through the plywood board, not the XPS foam board.. On the same XPS foam board that the hole for the PVC piping was made, on the side facing the plywood board, create a narrow shaft that runs the length of the board up until the hole you created in the plastic casing box. This will serve as a crevice in which you can snake the wiring from the plastic casing box to the motor and bilge pump.

Step 5: Completing the Motor/Bilge Pump Area

Solder two wires each of 2' length to the motor, one for positive, the other for negative. Snake the wires through the crevice created in the previous step. Using superglue or any other strong form of adhesives, attach the bilge pump on top of the motor (red side should be in contact with the motor). Snake the wiring from the bilge pump through the crevice.

Step 6: Covering the Bilge Pump W/ PVC Piping

Once the bilge pump is securely attached to the motor, measure the combined height. Using a 3" diameter piece of PVC piping, cover the bilge pump and the motor. Cut a corresponding hole on the side of the PVC piping for the bilge pump to go through. Place a PVC piping end cap on the end of the PVC piping and secure it. If needed, attach a L-bracket to the XPS foam board in order to support the weight of the thruster.

Step 7: Preparing for Electronics

Secure two small rectangular wooden blocks on the bottom of the plastic casing box, perpendicular to the length of the box. Keep in mind to use thin blocks in order to still have space for the electronics. Drill another hole through the bottom of the box to allow a power cable to be connected to the electronics (this is for the stationary version that is unable to go into the water).

Step 8: Electronics

  1. Using double sided tape (or a stronger form of electronic-friendly adhesive), secure the Arduino Uno board to the wooden blocks, the side with the USB port facing the hole drilled in the previous step.
  2. Attach the PIXY camera atop the Adafruit mini pan-tilt with screws. Place it on the center of the plastic casing box, securing it with screws.
  3. Connect the respective wires of the bilge pump, motor, pan-tilt, and the PIXY camera to the Arduino Uno board.
  4. Program the PIXY camera and mini pan-tilt to track a color of your choice. Connect the Arduino Uno board to power and test it out.
  5. Secure the cover to the plastic casing box, leaving space to allow the wiring to fit in between the cover and the plastic casing box.

Step 9: Code for PIXY Camera

Attach you will find the code used along with the Pixy camera, UNO Arduino micro controller board and Adafruit motor shield. The code interprets the finding of the camera, looking for a specific color. In this case we programmed the camera to look for green. Once the camera tracks the color green it will move accordingly 1 thrust-er propulsion unit. The Arduino code is listed below:

// // MRL Autonomous pixy robot (for project 40-15) // // Modified by: Max Hayashi // All source code is provided under the GNU General Public License v2 ( // //========================================================================== //========================================================================== // Portions of the code is derived from // Pixy Pet Robot // // Adafruit invests time and resources providing this open source code, // please support Adafruit and open-source hardware by purchasing // products from Adafruit! // // Written by: Bill Earl for Adafruit Industries // //========================================================================== // begin license header // // All Pixy Pet source code is provided under the terms of the // GNU General Public License v2 ( // // end license header // //========================================================================== // // Portions of this code are derived from the Pixy CMUcam5 pantilt example code. // //==========================================================================

// Include Pixy libraries #include #include

// Motor shield libraries #include #include #include "utility/Adafruit_MS_PWMServoDriver.h" Adafruit_MotorShield AFMS = Adafruit_MotorShield(); Adafruit_DCMotor *steering = AFMS.getMotor(1); Adafruit_DCMotor *propulsion = AFMS.getMotor(3); String dir = "mid";

// Servo to control h-bridge #include

// Declare objects: Pixy pixy; //Adafruit_MotorShield AFMS = Adafruit_MotorShield(); //Adafruit_DCMotor *m1 = AFMS.getMotor(1); //Adafruit_DCMotor *m2 = AFMS.getMotor(2); //Adafruit_DCMotor *m3 = AFMS.getMotor(3); //Adafruit_DCMotor *m4 = AFMS.getMotor(4); void setup() { Serial.begin(9600); Serial.print("Starting...\n");

pixy.init(); AFMS.begin(); }

uint32_t lastBlockTime = 0;

void loop() { uint16_t blocks; blocks = pixy.getBlocks(); // read pixy

// if there are blocks, track and follow them if (blocks) { int trackedBlock = TrackBlock(blocks); FollowBlock(trackedBlock); lastBlockTime = millis(); } // stop if no blocks else if (millis() - lastBlockTime > 100) { propulsion->run(RELEASE); }



int oldSignature; // find biggest block int TrackBlock(int blockCount) { int trackedBlock = 0; long maxSize = 0;

Serial.print("blocks = "); Serial.println(blockCount);

for (int i = 0; i < blockCount; i++) { if ((oldSignature == 0) || (pixy.blocks[i].signature == oldSignature)) { long newSize = pixy.blocks[i].height * pixy.blocks[i].width; if (newSize > maxSize) { trackedBlock = i; maxSize = newSize; } } }

oldSignature = pixy.blocks[trackedBlock].signature; return trackedBlock; }

// follow the object, try to keep object in center and keep some distance int32_t size = 400; int leftSpeed = 90; int rightSpeed = 90; void FollowBlock(int trackedBlock) { // average of last 8 sizes size += pixy.blocks[trackedBlock].width * pixy.blocks[trackedBlock].height; size -= size >> 3;

// set speed based on distance (with a given size) CHANGE NUMBERS UNDER ARROWS AS NECESSARY // \/ \/ \/ \/ 0(stopped) 255(full speed) int forwardSpeed = constrain((136 - (size / 3100)), 90 , 135);

// differential (keeps object centered) 139? // \/ \/ int32_t differential = ((int32_t)160 - (int32_t)pixy.blocks[trackedBlock].x) / (int32_t)10;

// adjust with differential // if (forwardSpeed > 100) { // if (differential > 5) { // leftSpeed = constrain(90 - differential, 70, 135); // rightSpeed = constrain(forwardSpeed + differential, 70, 135); // } else if (differential < -5){ // leftSpeed = constrain(forwardSpeed - differential, 70, 135); // rightSpeed = constrain(90 + differential, 70, 135); // } else { // leftSpeed = constrain(forwardSpeed - differential, 70, 135); // rightSpeed = constrain(forwardSpeed + differential, 70, 135); // }

// } else { leftSpeed = constrain(forwardSpeed - differential, 90, 135); rightSpeed = constrain(forwardSpeed + differential, 90, 135); // }

// set speeds

/* m1->setSpeed(leftSpeed); m4->setSpeed(leftSpeed); m3->setSpeed(rightSpeed); m2->setSpeed(rightSpeed); m1->run(FORWARD); m2->run(FORWARD); m3->run(FORWARD); m4->run(FORWARD); */ propulsion->setSpeed(150); propulsion->run(FORWARD); if (leftSpeed-rightSpeed > 10){ if (dir == "mid"){ steering->setSpeed(150); steering->run(FORWARD); delay(500); steering->run(RELEASE); } if (dir == "left"){ steering->setSpeed(150); steering->run(FORWARD); delay(1000); steering->run(RELEASE); } dir = "right"; } else if (rightSpeed-leftSpeed > 10){ if (dir == "mid"){ steering->setSpeed(150); steering->run(BACKWARD); delay(500); steering->run(RELEASE); } if (dir == "left"){ steering->setSpeed(150); steering->run(BACKWARD); delay(1000); steering->run(RELEASE); } dir = "left"; }

// else { // m1.detach(); // m2.detach(); // m3.detach(); // m4.detach(); // }

// print to serial - USE TO ADJUST SPEED /* Serial.print("differential: "); Serial.print(differential); Serial.println(" (positive is left)"); Serial.print("x: "); Serial.println(pixy.blocks[trackedBlock].x); Serial.print("left speed: "); Serial.println(leftSpeed); Serial.print("right speed: "); Serial.println(rightSpeed); Serial.print("size: "); Serial.println(size); Serial.println(forwardSpeed); //*/


Step 10: Supporting Documentation

Supporting Documentation for prototype.



    • Indoor Lighting Contest

      Indoor Lighting Contest
    • Make It Fly Challenge

      Make It Fly Challenge
    • Growing Beyond Earth Maker Contest

      Growing Beyond Earth Maker Contest