Final Project Report

 Deep Sea Exploration- Renna – Andy

video:

https://drive.google.com/file/d/1DjrPeysvoFKc_ZGfAdGncWY3uBDK5aZ4/view?usp=drive_link

1 CONCEPTION AND DESIGN:

Most people in their lifetime will never have the opportunity to explore the deep sea, limited by factors such as physical fitness, unknown risks, professional knowledge, financial support and so on. This project aims to immerse users in the captivating world of the deep sea. By collecting real-time data from Arduino sensors, my project seeks to provide an interactive experience which let the user manipulate a submarine to inspire people’s curiosity on exploring unknown realms and promote their environmental awareness for protecting the deep-sea ecosystem.

the footage I used:

submarine png files / background music generated by Suno/ undersea creatures& scene png files/ rubbish png/ submarine creatures video

my reference:

2 FABRICATION AND PRODUCTION:

In terms of sensors, I wanted to simulate the mode of controlling the ascent and descent of the submarine by inflating. So, I thought of using an airflow sensor and manually inflatable airbags. Additionally, I set up a remote sensing system to control the movement of the submarine, and I used a button as a switch for the illumination lights. In terms of project design, I used an air pump to increase the depth and then mapped the depth values to the HSB color model. As the depth increases, the brightness of the color decreases. This way, when the player keeps inflating, the background gradually transitions from light blue to black. Furthermore, I wrote four depth values as variables to control the triggering conditions for the four stages.

stage1:

pump air ,then depth1 will increase to 250, triggering the collecting rubbish part.

https://drive.google.com/file/d/1MPPGYV8KUPoo0r9mZTTlJgrVPwEfpfe1/view?usp=drive_link

stage2:

after collecting all the rubbish, you can interact with the fish. Every fish will follow your submarine.

https://drive.google.com/file/d/1EKNLGe_6ebCs9eVQDr65TSF4PW6_rTxz/view?usp=drive_link

stage3: 

after you drop in the waterflow, you will be in danger. The player need to control the submarine to escape from the stones!!!

https://drive.google.com/file/d/1PNvF-6oDdolIQmpgXbx8RYkHqc3B1awF/view?usp=drive_link

stage 4:

 you have reached the bottom of the sea. Everything is dark. When you find a creature, press the button to open the light and see what the creature is.

https://drive.google.com/file/d/1PNvF-6oDdolIQmpgXbx8RYkHqc3B1awF/view?usp=drive_link

I also received many helpful and creative ideas in the user testing day.

Shengli’s suggestion is to create an image on a canvas that is four times larger than the display area. In the center of the image, a transparent circle should be carved out. The transparent portion of the image should be aligned with the submarine, and as the submarine’s position changes, the image should be translated accordingly. This approach would create a realistic effect of illuminating a small circle within the deep-sea range.

Calista’s suggestion is to add a whirlpool as an entrance to the next level in a location where the player can interact with small fish. If the player is curious or accidentally touches the whirlpool, they will be transported to the next stage.

The fabrication part is easy. I just laser cut 5 wooden boards, and hot glue them together into a box. I hide the electric lines, bread board and Arduino board under the box. Then, I cut 3 circles with 7cm diameters and use 502 glues to stick them on the board. Finally, I find some pictures which match my theme and cut& stick them to the box, making my project looks more beautiful.

 

3 CONCLUSIONS:

I believe my project has successfully implemented the design outlined in my proposal, and due to my previous experience in coding labs, I have a solid foundation in programming. I am proficient in using functions such as Boolean, class, dist, map, and translate to achieve the desired effects. On the day of the presentation, my project was evaluated as being very comprehensive and engaging. It was described as a project that promotes exploration and provides a relaxing and therapeutic experience.

If I had more time to refine this project, I would focus on the following aspects:

1. Adding Audio Cues: Since the players may not always know what their next step should be, I would incorporate more audio cues. These cues would provide guidance to the players by alerting them about the actions they should take when certain conditions are triggered. This would enhance the overall user experience and make it more engaging.

2. Unique Creatures in the Final Stage: In the final stage, instead of using common sea creatures like sharks and turtles, I would replace them with rare and exotic creatures. This modification would align better with the theme of exploring the depths of the ocean. It would add a sense of excitement and discovery for the players as they encounter these extraordinary creatures.

By implementing these enhancements, the project would become more immersive, informative, and captivating for the players.

4 DISASSEMBLY:

5 APPENDIX:

diagram:

Arduino to processing Code:

import processing.serial.*;
import processing.video.*;
import java.util.ArrayList;
import processing.sound.*;

Movie sharkmovie;
Movie wuguimovie;
Movie shuimumovie;
float[] xs = new float[10];
float[] ys = new float[10];
float[] xspeeds = new float[10];
float[] yspeeds = new float[10];

Serial serialPort;
ArrayList<laji> lajis = new ArrayList<laji>();
ArrayList<lj> ljs = new ArrayList<lj>();
ArrayList<Fish> fishList;

int NUM_OF_VALUES_FROM_ARDUINO = 5;
/* This array stores values from Arduino */
int arduino_values[] = new int[NUM_OF_VALUES_FROM_ARDUINO];
PImage sub1;
PImage rubbish1;
PImage rubbish2;
PImage sea;
PImage fish;
PImage sea2;
PImage flow;
PImage black;
PImage stone;
PImage light;
PImage sharks;
PImage shuimu;
PImage wugui;
int depth1=0;
int depth2=0;
int depth3=0;
int depth4=0;
int depth=0;
int a=0;
float x;
float y;
float xspd;
float yspd;
int score=0;
int touming=255;
boolean fishover=false;
boolean shark=false;
boolean die=false;
boolean sharkfind=false;
boolean wuguifind=false;
boolean shuimufind=false;
float seax;
float seay;
float seab;
float fx=300;
float fy=300;
float fxs=8;
float fys=8;
float fishx=5000;
float sharkx=random(100,2500);
float sharky=random(100,1500);
float wuguix=random(100,2500);
float wuguiy=random(100,1500);
float shuimux=random(100,2500);
float shuimuy=random(100,1500);
boolean find1=false;
boolean find2=false;

boolean find3=false;

SoundFile bgm;
SoundFile welcome;
SoundFile danger;

 

void setup() {
size(2600, 1600);
colorMode(HSB, 360, 100, 100);
sub1=loadImage(“sub.png”);
rubbish1=loadImage(“rubbish1.png”);
rubbish2=loadImage(“rubbish2.png”);
sea=loadImage(“sea.png”);
sea2=loadImage(“sea2.png”);
flow=loadImage(“flow.png”);
light=loadImage(“light.png”);
black=loadImage(“black.png”);
stone=loadImage(“stone.png”);
fish=loadImage(“fish.png”);
sharks=loadImage(“sharks.png”);
wugui=loadImage(“wugui.png”);
shuimu=loadImage(“shuimu.png”);
sharkmovie = new Movie(this, “shark.mp4”);
wuguimovie = new Movie(this, “wugui.mp4”);
shuimumovie = new Movie(this, “shuimu.mp4”);
bgm = new SoundFile(this, “bgm.mp3”);
welcome = new SoundFile(this, “welcome.mp3”);
danger = new SoundFile(this, “danger.mp3”);

bgm.loop();
delay(5000);
welcome.play();

printArray(Serial.list());
serialPort = new Serial(this, “COM5”, 9600);
fishList = new ArrayList<Fish>();
for (int i = 0; i < 10; i++) {
float x = random(100, 2500);
float y = random(100, 1500);
fishList.add(new Fish(x, y));
}
for (int i = 0; i < 5; i++) {
float a = random(100, 2500);
float b = random(100, 1500);
lajis.add(new laji(a, b));
}
for (int i = 0; i < 5; i++) {
float a = random(100, 2500); // 随机生成x位置
float b = random(400, 500); // 随机生成y位置
ljs.add(new lj(a, b));
}

for (int i=0; i < 10; i=i+1) {
xs[i] = random(40,width-40);
ys[i] = random(40,height-40);
xspeeds[i] = random(-3, 3)*3;
yspeeds[i] = random(-3, 3)*3;
}

}

void draw() {
// receive the values from Arduino

getSerialData();

x=constrain(x,100,width);
y=constrain(y,100,height);
a=constrain(a, 0, 100);
depth1=constrain(depth1, 0, 250);
depth2=constrain(depth2, 0, 250);
depth3=constrain(depth3, 0, 250);
depth4=constrain(depth4, 0, 250);
background(213, 73, a);

seax=map(depth1,0,250,0,-height);
if(depth2==0){
image(sea, 0, seax);
image(sea, 0, seax+height);
}
push();
fill(1,100,0);
text(“pump air to dive deeper”,width/2,height/2);
pop();

image(sub1,x,y);
textSize(20);
fill(255);
push();
strokeWeight(3);
fill(359,100,100);
textSize(80);
text(“depth:”+depth, width/2, 80);
pop();
text(“a:”+a, 50, 80);
text(“depth1:”+depth1, 50, 110);
text(“depth2:”+depth2, 50, 140);
text(“depth3:”+depth3, 50, 170);
text(“depth4:”+depth4, 50, 200);
text(“score:”+score, 50, 230);
text(“shark:”+shark, 50, 260);
depth=depth1+depth2+depth3+depth4;
if (arduino_values[0]<450) {
x-=10;
}
if (arduino_values[0]>550) {
x+=10;
}
if (arduino_values[1]<450) {
y-=10;
}
if (arduino_values[1]>550) {
y+=10;
}
if (a>=0) {
a=floor(map(depth, 0, 1000, 100, 0));
}

//String mousePosition = “Pos(” + mouseX + “, ” + mouseY + “)”;
//text(mousePosition, mouseX, mouseY);

//下潜,触发吃垃圾
if (arduino_values[3]==1) {
depth1+=1;
fill(1, 0, 100);
noStroke();

}

//吃完所有垃圾之后下潜,触发鱼群
if (score==10&&depth1>=250) {
seay=map(depth2,0,250,0,-height);
if(depth3<=0&&fishover==false){
image(sea2, 0, seay+height);
image(sea2, 0, seay);
}
if (arduino_values[3]==1) {
depth2+=1;
}
}

//和鱼群互动结束,继续下潜
if (fishover==true) {

depth3+=1;
}

if (arduino_values[3]==1&&shark==true) {
depth4+=1;

}

if (depth1>=250&&score<10) {
seab=map(depth2,0,250,0,-height);
image(sea,0,seab);
for (int i = 0; i < lajis.size(); i++) {
laji currentLaji = lajis.get(i);
currentLaji.update(); // 更新垃圾的位置
currentLaji.display(); // 绘制垃圾
if (dist(x, y, currentLaji.a + currentLaji.xspd, currentLaji.b + currentLaji.yspd) < 50) {
score += 1;
lajis.remove(i); // 从ArrayList中删除laji对象
i–; // 调整索引以保持正确的迭代
//local 和全局变量不能写在class里 要写在外面
}
}
for (int i = 0; i < ljs.size(); i++) {
lj currentLj = ljs.get(i);
currentLj.update(); // 更新垃圾的位置
currentLj.display(); // 绘制垃圾
if (dist(x, y, currentLj.a + currentLj.xspd, currentLj.b + currentLj.yspd) < 50) {
score += 1;
ljs.remove(i); // 从ArrayList中删除laji对象
i–; // 调整索引以保持正确的迭代
//local 和全局变量不能写在class里 要写在外面
}
}
}

if (depth2>=250&&score==10&&shark==false) {
if(fishover==false){
for (Fish fish : fishList) {
fish.update(x, y);
fish.display();
}
image(flow,fx,fy);
fx+= fxs;
fy+= fys;
// check right edge
if (fx> width-200||fx < 200){
fxs *=-1;
}
// check bottom edge
if (fy > height-200||fy< 200) {
fys*=-1;
}
}
if(dist(x+150,y+150,fx+150,fy+150)<50){
fishover=true;
}
}

if(depth3>=250&&shark==false){
if(die==true){
danger.stop();

background(213, 73, a);
push();
strokeWeight(3);
fill(359,100,100);
textSize(80);
text(“YOU DIE!”,width/2,height/2);
text(“click to restart”,width/2,height/2+200);
pop();
}
fishx-=5;
image(fish,fishx,height/2);
if(fishx==0){
background(213, 73, a);
shark=true;
}
if(shark==false);
for (int i=0; i < 10; i=i+1) {
image(stone,xs[i], ys[i]);
xs[i] = xs[i] + xspeeds[i];
ys[i] = ys[i] + yspeeds[i];
if (xs[i] > width-150||xs[i] < 150){
xspeeds[i] *=-1;
}
if (ys[i] > height-150||ys[i] < 150) {
yspeeds[i] *=-1;
}
if(dist(xs[i],ys[i],x,y)<60){
die=true;}
}

if(depth1>=250&depth2>=250&&score>=10&&fishover==true&&die==true){
if(arduino_values[2]==1){
depth3=0;
depth4=0;
die=false;
fishx=5000;
}
}

}

if(depth4>=250){
background(213, 73, 30);
image(sub1,x,y);
image(sharks,sharkx,sharky);
image(wugui,wuguix,wuguiy);
image(shuimu,shuimux,shuimuy);
push();
imageMode(CENTER);
image(black,x+20,y+110);
pop();
if(arduino_values[4]==1){
image(light,x+225,y+110);
if(dist(sharkx,sharky,x,y)<100){
sharkfind=true;
}
if(dist(shuimux,shuimuy,x,y)<100){
shuimufind=true;
}
if(dist(wuguix,wuguiy,x,y)<100){
wuguifind=true;
}
}
if(wuguifind==true){
wuguimovie.play();
if (wuguimovie.available()) {
wuguimovie.read();
}else{
wuguifind=false;
}
image(wuguimovie,0,0);
find1=true;
}
if(sharkfind==true){
sharkmovie.play();
if (sharkmovie.available()) {
sharkmovie.read();
}else{
sharkfind=false;
}
image(sharkmovie,0,0);
find2=true;
}
if(shuimufind==true){
shuimumovie.play();
if (shuimumovie.available()) {
shuimumovie.read();
}else{
shuimufind=false;
}
image(shuimumovie,0,0);

find3=true;
}

}
//if(find1==true&&find2==true&&find3==true){
// background(213, 73, 0);
// push();
// textSize(100);
// text(“You’ve reached the bottom of the sea”,1100,600);
// pop();

//}
}

void mouseClicked() {

shark=true;
depth1=250;
depth2=250;
depth3=250;
score=10;
fishover=true;
}

class Fish {
float x;
float y;
float angle;
float speed;
float scale;
float yanse;

Fish(float x, float y) {
this.x = x;
this.y = y;
angle = 0;
speed = random(4,8);
scale=random(0.5, 2);
yanse=random(0, 360);
}

void update(float targetX, float targetY) {
// 计算鱼与主角的角度
angle = atan2(targetY – y, targetX – x);

// 计算鱼与主角的距离
float distance = dist(x, y, targetX, targetY);

// 让鱼朝向主角并向主角靠近
if (distance > 10) {
x += cos(angle) * speed;
y += sin(angle) * speed;
}
}
void display() {
push();
scale(scale);
translate(x, y);
rotate(angle);
tint(yanse, 100, 100);
image(fish, 0, 0);
pop();
}
}

class laji {
float a;
float b;
float xspd;
float yspd;
float freq;

laji(float a, float b) {
this.a = random(100, 2500);
this.b = random(100, 1500);
this.xspd = 0;
this.yspd = 0;
this.freq = random(0.01, 0.03);
}

void update() {
this.xspd = map(noise(sin(frameCount * this.freq)), 0, 1, -30, 30);
this.yspd = map(noise(sin(frameCount * this.freq)), 0, 1, -30, 30);
}
void display() {
rubbish1=loadImage(“rubbish1.png”);
push();
translate(a, b);
image(rubbish1, xspd, yspd);
pop();
}
}
class lj {
float a;
float b;
float xspd;
float yspd;
float freq;

lj(float a, float b) {
this.a = random(100, 2500);
this.b = random(100, 1500);
this.xspd = 0;
this.yspd = 0;
this.freq = random(0.01, 0.03);
}

void update() {
this.xspd = map(noise(sin(frameCount * this.freq)), 0, 1, -30, 30);
this.yspd = map(noise(sin(frameCount * this.freq)), 0, 1, -30, 30);
}
void display() {
rubbish2=loadImage(“rubbish2.png”);
push();
translate(a, b);
image(rubbish2, xspd, yspd);
pop();
}
}

void getSerialData() {
while (serialPort.available() > 0) {
String in = serialPort.readStringUntil( 10 ); // 10 = ‘\n’ Linefeed in ASCII
if (in != null) {
print(“From Arduino: ” + in);
String[] serialInArray = split(trim(in), “,”);
if (serialInArray.length == NUM_OF_VALUES_FROM_ARDUINO) {
for (int i=0; i<serialInArray.length; i++) {
arduino_values[i] = int(serialInArray[i]);
}
}
}
}
}

 

Arduino Code:

void setup() {
  Serial.begin(9600);
}
void loop() {
  // to send values to Processing assign the values you want to send
  // this is an example:
  int sensor0 = analogRead(A0);
  int sensor1 = analogRead(A1);
  int sensor2 = digitalRead(8);//kaideng
  int sensor3 = digitalRead(2);//吹
  int sensor4 = digitalRead(9);//重开
  // send the values keeping this format
  Serial.print(sensor0);
  Serial.print(“,”);  
  Serial.print(sensor1);
  Serial.print(“,”);
  Serial.print(sensor2);
  Serial.print(“,”);  
  Serial.print(sensor3);
  Serial.print(“,”);  
  Serial.print(sensor4);
  Serial.println();  
  delay(20);
  // end of example sending values
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *