Introduction: DIY ROV: the Unsinkable #2

About: I'm a wanna be engineer with a soldering iron and a 3D printer

An underwater ROV or remotely operated vehicle is a tethered underwater mobile device that can be controlled by an operator on the surface. They are mostly used for marine salvage and recovery operations where sending a diver would be to hazardous or difficult to do. They can also perform underwater surveying and other similar commercial operations. Now this ROV design isn't a million dollar commercial grade version like most, but for locating lost objects in lakes in rivers, it'll do the job just fine. Although this design isn't 100% complete, its proof of concept that it'd perform as advertised is complete. I designed the ROV in Fusion 360 from its remote all the way down to its propeller shafts. I wanted this submersible to not just be an eye below the surface, but an object retriever and dredger. So i incorporated a 6 axis robotic arm for retrieving objects and performing other underwater nonsense tasks. Along with the arm i added a dredge pump to remove small layers of silt on an object or possibly suction up small objects into a sediment trap. I also attempted to make the design as low cost and efficient as possible using off the shelf arduino mega shields and components. Unlike most underwater motors, the ones used in this design will not cost you an arm and a leg (just as long as you have access too a metal lathe). A lot of my ideas also came from The ROV Manual, Second Edition: A User Guide for Remotely Operated Vehicles, which is a wealth of knowledge on the topic of ROVs and can help you out alot.

https://www.amazon.com/gp/product/0080982883/ref=o...

Step 1: Remote Design

I started off by purchasing a 11.4" x 8.3" x 3.1" Plastic Enclosure Project Case off amazon (ill include the links for purchase on amazon at the end), i then began to lay it out in autodesk fusion 360 till i had the general layout of how i wanted the remote to look like. I then printed out the DFX file to scale and taped it to the top of the project box. Once it was laid out as my template i began to cut out the holes with a dremel and drill.

I then mounted the components in their spots and began to plan out their wiring.

Wiring was a bit more complicated, i used cat5 cable to help with wire management and keep everything together but its still kind of a work in progress, 2hrs of soldering and redesigning l finally had a successful layout.

For the compass LCD i used someone elses instructable for a reference and combined it with my own code to incorporate it in the remote. https://www.instructables.com/id/Arduino-Digital-M...

Code:

*/

const int potpin1 = 1; const int potpin = 0; // analog pin used to connect the potentiometer int pan = 0; // variable to read the value from the analog pin int tilt = 1; //Include libraries #include #include #include #include #include #include #include

//Init Display (SCLK, DIN, D/C, CS, RST) Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3); //Init HMC5883L sensor Adafruit_HMC5883_Unified compass = Adafruit_HMC5883_Unified(12345);

//Constants const int lcdLight = 13; //BL pin of LCD to arduino pin 13 (BL = Back Light) Button buttonA = Button(2,PULLUP); //Button to turn on/off display light Button buttonB = Button(8,PULLUP); //Button for changing display mode // For 1st display mode: static unsigned char Leters[] = { 'N' , 'E' , 'S' , 'W' };

const static unsigned char PROGMEM arrow_bmp[] = { B00100000, B00100000, B01110000, B01110000, B11111000}; // For 2nd display mode: int r = 24; // radius of compass rose int x0= 60; // x-origin int y0= 24; // y-origin

//Variables int flag=0;//Store buttonA condition 0:1st display mode / 1: 2nd display mode int i=1; //Store buttonB condition 1: light on / 0: light off

void setup() { delay(10000); //The 10 second delay to upload new programs. Serial.begin(9600); //Begin Serial to talk to the Serial Monitor Serial1.begin(9600); //Begin Serial to talk to the Slave Arduino Serial.println("Serial Monitor Connected"); Serial.parseInt(); //clear any garbage in the buffer.

pinMode(lcdLight, OUTPUT); // lcd led compass.begin(); Wire.begin(); display.begin(); display.setContrast(30); //Print a welcome message in startup for 6sec.////////// digitalWrite(lcdLight,HIGH); display.clearDisplay(); // clears the screen and buffer display.setTextColor(BLACK); display.setCursor(0,2); display.print(" ROV "); display.setCursor(0,13); display.print(" Compass "); display.setCursor(0,23); display.print(" "); display.setCursor(0,33); display.print(" Derrico Industries"); display.display(); // show splashscreen digitalWrite(lcdLight,HIGH); delay(10000); ///////////////////////////////////////////////////////// display.clearDisplay(); // clears the screen and buffer}

void loop() { //Read the flex sensor. We'll keep this value raw. pan = analogRead(potpin);// reads the value of the potentiometer(value between 0 and 1023) tilt = analogRead(potpin1); Serial1.println(pan); //Send the potentiometer value to the Slave Arduino Serial1.println(tilt); // keep an ear out for messages back from the Slave. You know // complaints and the like. delay(10); //This delay is added to give the Slave a chance to //return data

if(Serial1.available()) //while there is data available { delay(10); //This delay is added to give the Slave a chance to //return data } //if buttonB is pressed, 'flag' will change between 0 and 1 if(buttonB.isPressed()){ delay(100);//small delay if(flag==0){ flag=1; } else{ flag=0; } } //if buttonA is pressed, 'i' will change between 0 and 1 if(buttonA.isPressed()){ if(i==0){ i=1; } else{ i=0; } } //if i is equal with 0, set display light on, else set display light off if (i==0){ digitalWrite(lcdLight,HIGH);} else{ digitalWrite(lcdLight,LOW); } //Reading and calculate degrees: ///////////////////////////////////// //Get new sensor value every time that loop starting again sensors_event_t event; compass.getEvent(&event); //Variable heading stores value in radians float heading = atan2(event.magnetic.y, event.magnetic.x); // Once you have your heading, you must then add your 'Declination Angle', which is the 'Error' of the compassnetic field in your location. // Find yours here: http://www.compassnetic-declination.com/ // Mine is: -13* 2' W, which is ~13 Degrees, or (which we need) 0.22 radians float declinationAngle = 0.22; //<--Change 0.22 with yours. If you can't find your declination juct delete those lines ;) heading += declinationAngle; // Correct for when signs are reversed. if(heading < 0) heading += 2*PI; // Check for wrap due to addition of declination. if(heading > 2*PI)heading -= 2*PI; // Convert radians to degrees for readability. float headingDegrees = heading * 180/M_PI; //Convert float to int int angle=(int)headingDegrees; //////////////////////////////////////////////////////////////////////////

display.clearDisplay(); // Just in case... //if flag is equal with 0 - 1st Display Mode if (flag==0){ DrawRow(angle); //call DrawRow function display.drawBitmap(40, 24, arrow_bmp, 5, 5, 1); display.drawLine(42, 0, 42, 24, BLACK); display.setCursor(32,34); display.print(angle); display.setTextSize(1); display.print("o"); display.display(); delay(500); //print new value every 0.5sec } //if flag is equal with 1 - 2nd Display Mode if (flag==1){ // Calculation of compass needle on lcd pointing to the direction DrawCircle(angle); //call DrawCircle function // Display actual heading display.setTextSize(2); display.setTextColor(BLACK); display.setCursor(0,0); display.println(angle); display.setTextSize(1); display.setTextColor(BLACK); display.setCursor(x0-2,0); display.println("N"); display.setTextSize(1); display.setTextColor(BLACK); display.setCursor((x0+r)-5,y0-3); display.println("E"); display.setTextSize(1); display.setTextColor(BLACK); display.setCursor(x0-2,y0+r-8); display.println("S"); display.setTextSize(1); display.setTextColor(BLACK); display.setCursor((x0-r)+5,y0-3); display.println("W"); // Triangle for direction display.drawTriangle(0, 46, 20, 46, 10, 18, BLACK); display.fillTriangle (0, 46, 20, 46, 10, 18, BLACK); display.display(); delay(150); //print new value every 0.5sec }

} //////////// Functions ///////////

/Draw rows and print letters to display - 1st Display Mode void DrawRow(int angle) {

display.drawLine(0, 0, 84, 0, BLACK); display.drawLine(0, 1, 84, 1, BLACK);

display.drawLine(0, 22, 91, 22, BLACK); display.drawLine(0, 23, 95, 23, BLACK); display.setTextSize(2); display.setTextColor(BLACK); int start = 42 - angle / 3 ; if (start > 120) start += -120 ;

int x = 0 ; int y = 18 ; for (int i=0; i<4; i++) { x = start + (i*30) -1; if (x>119) x += -120; display.drawPixel(x+1, y-2, 1); display.drawPixel(x, y, 1); display.drawPixel(x+1, y, 1); display.drawPixel(x+2, y, 1); display.drawPixel(x, y-1, 1); display.drawPixel(x+1, y-1, 1); display.drawPixel(x+2, y-1, 1); display.setCursor((x-4),(y-16)); display.write(Leters[i]); } for (int i=0; i<24; i++) { x = start + (i*5) -1; if (x>119) x += -120; display.drawPixel(x+1, y+1, 1); display.drawPixel(x, y+2, 1); display.drawPixel(x+1, y+2, 1); display.drawPixel(x+2, y+2, 1); display.drawPixel(x, y+3, 1); display.drawPixel(x+1, y+3, 1); display.drawPixel(x+2, y+3, 1); }; for (int i=0; i<8; i++) { x = start + (i*15)-1; if (x>119) x += -120; display.drawPixel(x+1, y-1, 1);

display.drawPixel(x, y, 1); display.drawPixel(x+1, y, 1); display.drawPixel(x+2, y, 1); display.drawPixel(x, y+1, 1); display.drawPixel(x+1, y+1, 1); display.drawPixel(x+2, y+1, 1);

}; }

////Draw circle and print letters to display - 1st Display Mode void DrawCircle(int angle) { if (angle >= 0 && angle <=45) { // 0-45 degrees int angle = angle/2; display.drawLine(x0, y0, x0+angle, y0-r, BLACK); } else if (angle >45 && angle <=90) {// 46-90 degrees int angle = (angle-44)/2 ; display.drawLine(x0, y0, x0+r, (y0-r)+angle, BLACK); } else if (angle >90 && angle <=135) {// 91-135 degrees int angle = (angle-90)/2; display.drawLine(x0, y0, x0+r, y0+angle, BLACK); } else if (angle >135 && angle <=180){// 136-180 degrees int angle = (angle-134)/2; display.drawLine(x0, y0, (x0+r)-angle, y0+r, BLACK); } else if (angle >180 && angle <=225){// 181-225 degrees int angle = (angle-178)/2; display.drawLine(x0, y0, x0-angle, y0+r, BLACK); } else if (angle >225 && angle <=270){// 226-270 degrees int angle = (angle-222)/2; display.drawLine(x0, y0, x0-r, (y0+r)-angle, BLACK); } else if (angle >270 && angle <=315){// 271-315 degrees int angle = (angle-270)/2; display.drawLine(x0, y0, x0-r, y0-angle, BLACK); } else if (angle >315 && angle <=360){// 316-360 degrees int angle = (angle-312)/2; display.drawLine(x0, y0, (x0-r)+angle, y0-r, BLACK); } }

STL Files

https://www.thingiverse.com/thing:2709264

Material purchased:

https://www.amazon.com/gp/product/B01EE4VQYG/ref=o...

https://www.amazon.com/gp/product/B01DZ8BRHI/ref=o...

https://www.amazon.com/gp/product/B010U8FO0C/ref=o...

https://www.amazon.com/gp/product/B00LGKG1BA/ref=o...

https://www.amazon.com/gp/product/B00UT13YXA/ref=o...

https://www.amazon.com/gp/product/B00M6KO3LO/ref=o...

Step 2: Motor

Unlike most underwater motors, the ones used in this design will not cost you an arm and a leg (just as long as you have access too a metal lathe). I chose to use cheap simple bilge pumps that one can find on amazon fairly cheap. I then found simple rc boat propellers to mount on them. The propeller shafts are made out of 1/2" aluminum round stock and ill include the blue prints for them.

Step 3: Pan and Tilt for Camera

I chose to use a simple usb camera and a usb to ethernet for the tether to the surface, its pretty simple and works well. The pan tilt is just a simple 2 servo pan and tilt you can pick up on amazon for around $17. I designed the camera bracket for it in fusion 360 and ill include the stl file for it.

Camera: https://www.amazon.com/gp/product/B01E8OC3EO/ref=o...

Pan tilt: https://www.amazon.com/Adafruit-Mini-Pan-Tilt-Kit-...

STL: https://www.thingiverse.com/thing:2709264

The camera just bolts to the bracket using m3 screws that can be found at any local hardware store.

From there the bracket just clips into the pan an tilt and your ready to program!

Now the program with the pan and tilt communicating between two arduinos is listed in the remote design step, but to test your pan and tilt you can use this program and it will work just fine

Pin out:

A0= Pot 1

A1= Pot 2

Digital pin 8 = Servo 1

Digital pin 9 = Servo 2

Code:

#include

Servo myservo1; Servo myservo2; // create servo object to control a servo ;

int potpin1 = 0; // analog pin used to connect the potentiometer int potpin2 = 1;

int val; // variable to read the value from the analog pin int val2;

void setup() { myservo1.attach(8); // attaches the servo on pin 9 to the servo object myservo2.attach(9); }

void loop() { val = analogRead(potpin1); // reads the value of the potentiometer (value between 0 and 1023) val = map(val, 0, 1023, 0, 180); // scale it to use it with the servo (value between 0 and 180) myservo1.write(val); // sets the servo position according to the scaled value val2 = analogRead(potpin2); val2 = map(val2, 0, 1023, 0, 180); myservo2.write(val2); }