Main File.

Programming design:

Title: Interact to Expose.                                           Title: Programming the wild.

     

Title: Pilgrimage and brainstorming.                          Title: Warm smell of tea.

          

 

Film and Animation

《竹石——立根原在破岩中》(bamboo of the stone)

 

《编码与自然互动》

Design with hardware: 

Title: 3D model water wheel liquid trash can prototype

     

Title: under the night light

 

 

Recitation 10: Making a Media Controller-Rahmon Chapoteau (Leon)

For this recitation, I wanted to make a controller that would control the size of the circles in the processing sketch, which would make the live video look either more or less pixelated. The first thing I tired to do was make and control the color and placement of rectangles since I still did not really understand serial communication between Arduino and Processing:

 

After I had a better understanding of this, I got a lot of help from the fellows on how to fill the screen with the circles/pixels, and multiply them as I moved my potentiometer. Although I had trouble understanding how to fill the screen with circles based on how much the potentiometer moved, I did start to have a better understanding of the serial communication between Arduino and Processing. Here is the final result of my project:

Processing 

import processing.video.*;
Capture cam;

int sizeX = 10;

int sizeY = 10;

import processing.serial.*;


Serial myPort;
int valueFromArduino;

void setup() {
  size(640, 480);
  cam = new Capture(this, 640, 480);
  cam.start();
  myPort = new Serial(this, Serial.list()[ 3 ], 9600);
}

void draw() {
   while ( myPort.available() > 0) {
    valueFromArduino = myPort.read();
    println(valueFromArduino);
  }
  
  if (cam.available()) {
    cam.read();
    //can load pixels of camera input
    //just like how we load pixels of an image
    cam.loadPixels();

    int sizeArduino = int(map(valueFromArduino, 0, 255, 5, 20));
    int w = cam.width;
    int h = cam.height;
    for (int y = 0; y < h; y +=sizeArduino) {
      for (int x = 0; x < w; x+=sizeArduino) {


        int i =  x + y*w; // *** IMPORTANT ***

        float r =  red(cam.pixels[i]); 
        float g =  green(cam.pixels[i]);
        float b = blue(cam.pixels[i]);
        float brightness = map(mouseX, 0, width, 0, 255);
        //cam.pixels[i] = color(r+brightness, g+brightness, b+brightness); 

        fill(r, g, b);
        ellipse(x, y, sizeArduino, sizeArduino);


        //include size variable. 
        //if mouseX > ..., decrease size 


        //if ((mouseX <160)) {
        //  sizeX = 5;
        //  sizeY = 5;
        //} else if ((mouseX > 160) && (mouseX <320)) {

        //  sizeX = 10;
        //  sizeY = 10;
        //  //ellipse(x, y, sizeX, sizeY);
        //} else if ((mouseX > 160) && (mouseX <320)) {

        //  sizeX = 10;
        //  sizeY = 10;
        //  //ellipse(x, y, sizeX, sizeY);
        //} else if ((mouseX >320) && (mouseX <480)) {

        //  sizeX = 15;
        //  sizeY = 15;
        //} else if ((mouseX >480) && (mouseX <640)) {
        //  sizeX = 20;
        //  sizeY = 20;
        //}



        //1023 highest for potentiometer, can use map
      }
    }
    cam.updatePixels();
  }
}

//void captureEvent(Capture cam) {
//  cam.read();
//}

Week 15: Internet Art project – Iyad Abdi (Chen)

Title: BRAND NEW WORLD

Linkhttp://imanas.shanghai.nyu.edu/~kap633/final-website/

Partner: Katie Pellegrino

Conception & Design:

In designing our internet art project, Katie and I wanted to mock/comment on our 21st century brand-obsessed consumer culture. We began by posing the question: “Why do people care about brands and logos?” Our inquiry lead us to hypothesize that it isn’t necessarily the products that people are pursuing. But rather the feelings that they derive from wearing visible branding. So we sought to tap into these base pursuits by creating an ironic webshop where we would sell consumers the feelings they’re after without needing to buy the product. (“Skip the product cop the feeling!”) We came up with the name ‘BRAND NEW WORLD‘, which we thought was a clever play on words on the dystopic social satire novel by Aldous Huxley, ‘BRAVE NEW WORLD’.

Process:

When building our project, Katie and I sat and discussed how we wanted this webshop to look. We were really fascinated by the aesthetics and sketchy look of early 2000s websites, and the nostalgia that they evoked. So we aimed to design our webshop to be simple and tacky in its visual design. We went with Times New Roman for the title and all the headers because that was the go-to font for many websites back then; and also a bright blue for the text color against a pale yellow background because we felt that looked pretty 2002-ish. We used an image of a web browser from back then to build our webshop within, but used Photoshop to adjust it and add functions that would work with and fit our site. Katie took the lead on the technical web construction. I took took the lead on the visual assets. I used Adobe Illustrator to distort brand logos into the underlying feelings that they might give to their consumers. (Champion > Cool, Rolls Royce > Really Rich). To give our site a more retro feel, we implemented GIFs that were blatantly consumer-centric (dollar signs, ‘I LOVE SHOPPING’, ETC.) . We initially were stuck about how we would convey our idea of buying the feelings while reflecting the actual brands. During user testing, we received feedback that our project wasn’t entirely clear that it was supposed to be a webshop, and were suggested to add pricing and a checkout process to better convey it. One night while working on our project, we had an epiphany that it would be cool to juxtapose the original logos against the twisted logos of the feelings by perfectly fading into the feeling when hovered over, and adding prices that were were significantly cheaper that the actual relative price ranges of the brands’ products. The prices of the feelings that we’re selling go significantly down to reflect the “cheap feelings” that buying things give us. When checking out, users click the cart button which redirects them to an article on the psychological effect of purchasing luxury goods.

Future:

Upon receiving feedback, we probably should have been a bit less obvious with the irony and allowed users to think it was a real webshop and, after exploring the site a bit, discover that “Oh! this is actually not a real webshop, but an art piece.” I also would have loved to expand our “product inventory”. We did want to add more than just 3 items for each category. But unfortunately, time did not allow for the creation of more visual assets. In the future, I imagine there to be at least 9 per category, enough for the user to scroll while browsing.

 

Overall, I am very satisfied with how our project turned out, and how well Katie and I were able to execute it. Our final product looked almost exactly how I imagined it to look in my head since day 1 and our initial rough sketch on graph paper,

 

 

Working with Electrons Actuator and Sensor lab Coneys

For the actuator and sensor lab I built a circuit where a laser fires into a light detector that then turns on a buzzer. Everything was powered by a simple battery pack, the laser and sensor were connected to the power and then the output of the photoelectric sensor was sent to a basic buzzer that buzzes whenever powered. However the output of the photoelectric sensor wasn’t enough to drive the buzzer so even though the laser was being detected it was unable to buzz. I considered different method for stepping up the voltage until Professor Rudi swapped the source from the output of the electric sensor to its ground. The sink current of the sensor was strong enough to power the buzzer and was only activated when the sensor detected light. This blew my mind because I had previously not known about sink currents and didn’t understand how a ground could be used like an output.

Working with Electrons 555 Lab (Coneys)

Creating the an astable 555 circuit was pretty interesting. I know how to do lots of timing stuff based off a micro-controller but it was cool to learn how to hard code it. The main functions like vcc, ground, threshold, and trigger were pretty easy to understand but some of the other pins I still don’t quite understand. Our circuit was designed in a similar fashion to this in astable mode so that it could oscillate and blink the light  without an input.

Then in class together we built an EAGLE schematic for a 555 lighting circuit PCB. The initial simulation section was pretty straightforward but then arranging it on the actual board once you had simulated it was a little more complex. It wasn’t quite clear to me what placements would or wouldn’t work in actual practice and when different layers should be used. The auto placement function seemed sufficient for our needs but I suspect that it falls off pretty hard as circuit complexity increases.

The manufacturing process was pretty interesting, I was surprised at how different it was in our lab vs at an industrial scale. We had some trouble with the milling when we tried to construct it , maybe at some point the wrong tip was used but other than that it seemed fairly straightforward. A lot of the difficulty seems to come with positioning stuff on the board but also the board in the machine and on the software. Any misalignment on any of these levels could break it so it seemed really important to check all your measurements well.

FInals Documentation

During the finals process, I’ve learn a lot about the circuit building process and construction procedure. The first step that I took was designing the schematic drawing. I then used falstad.com to witness how the circuit logistically worked and how the individual parts worked. After testing that this circuit was viable, i wired it on the breadboard to test whether it actually worked in the real work application. (diagram below) There were some issues initially because the capacitors had the wrong values but I was able to clear that up and continue the process.

The main part of my building process consisted of drawing and print the PCB myself. After creating it on Eagle, I had the option to take it to a factory to construct but I opted for the more education approach and did it myself. Although I was able to learn a lot,  I ultimately ran into some logistical issues as the copper wiring was too thin and too close due to the machine’s faulty calibration. To conclude, I finished assembling all the parts onto the PCB and then used an acrylic casing to enclose the project.

I did extensive research into the IC circuit: 555 timer. I fully understand the inner-workings of this piece and how it operates. In my circuit, it works as an astable circuit. Which means that between the states: stable and unstable, it will consistent be unable until triggered to be stable. Additionally, the time remained in these states depends on R&C. Consequently, when I use resistors or capacitors of higher value, there is a small range of tones.

After constructing my project, I started experimenting. I soon realized that there are many different paths to discover. Initially I had wanted to have one large body of water, but I recognized that this doesn’t work because the resistance becomes uniform From the equation V=IR, I realized that as the voltage is constant, when the distant or resistance is higher the pitch will be lower.

Based on where I place the two ends of the wires, I can play different sounds which resonates to different notes on the musical spectrum due to different frequencies being played. I also experimented with different concentrations of salt in water which corresponded to different frequencies once again . All in all, I found this project very interesting and transpirational for me to pursue more IMA classes in the future.

Final Project: Submarine Explorer — Jake Scavone (Rudi)

                This documentation will illustrate my thought process throughout the development of my Interaction Lab final project. Before I begin, I believe it’s important to first explain my original idea and why I ultimately discarded it, considering it was the basis of my project proposal essay (which seems to be a component of our final project grade).

                For our Interaction Lab final project, our project was required to utilize both the Arduino hardware and Processing software. This opened a lot of ideas that I wanted to explore. Since some focus was on the significance and importance of our project, I first explored concepts that would be environmentally proactive. I thought about how I’m always finding myself recycling a bunch of empty bottles at the end of each week. Even though I’m recycling them, I still think it’s a waste when they could be reused. In addition, a lot of these bottles weren’t originally water, some were sodas and other types of beverages. I thought it would be cool if there was a way to refill them with whatever type of beverage you want. This led to my idea of creating a model machine that you could insert empty plastic bottles into. Then, it would move the bottle into a visible compartment, and an interface via processing would prompt you to select a drink. After choosing what you want, the machine would then mock the process of filling up your bottle with a liquid. Since the availability of fluid compatible parts is rather limited and the combination of liquids, cardboard, my laptop, and Arduino hardware would probably not end well, it was clear that it would be best to not have it dispense anything that was actually wet. Instead, this process could be represented by filling the bottle with colored little plastic balls or paper scraps that would have to be released from a compartment hidden above with a servo motor or something. While there are machines where empty bottles are recycled in exchange for money, my project would instead refill the bottle to your preference. This idea would hopefully cause people to be more conservative about their plastic bottle waste, which according to studies is a massively high number.

                After proposing this concept with my professor, he explained that this idea alone wouldn’t be a very strong example of interaction, and because of this I would need to add certain elements to make it more interactive. He also pointed out many significant flaws that I would encounter. I started to think that I should pursue a different idea. For one, I realized that this choice of a project isn’t really something I feel I would excel at and be passionate about. I also didn’t like the fact that I would most likely have to fill the bottles with some sort of material as opposed to a liquid. In addition, the actual fabrication of the model machine would most likely be challenging, and I expected there would be unpredicted obstacles and flaws that I would have to overcome during the process. Because of these reasons, the final product would only be a model, and not completely achieve its purpose. Furthermore, I wasn’t certain that I would be able to fully accomplish the design that I had in mind. As a result of my uncertainty, I decided to completely scrap the idea and pursue a project that I believed would open doors for much more creativity and flexibility, all while remaining something I’m passionate about and interested in: video games.

                A major theme of the Interaction Lab course involves exploring the concept of interaction. Similar to our midterm, our final project needs to involve interaction. More specifically, our final project prompt states that “any interactive project is going to involve listening, thinking and communicating.” Not only are video games naturally a form of interaction, but they can also be made to entirely meet these requirements.  In making a game for my final project, the direction of communication between the two programs would be Arduino to Processing. This was because Arduino hardware would only be used as the controller for the game, and these inputs would control the functions within the Processing interface. In the time we had during recitation to achieve tasks utilizing both Arduino hardware and Processing software, I noticed certain parts I had trouble understanding. Most of these difficulties were related to Arduino. I found it very challenging to establish efficient communication between the two programs when there were multiple inputs from Arduino hardware to account for. As a result, I decided that my game should require as little inputs as possible. Using minimal controls brought consequences though, one being how most of the user’s focus would then be on the display. This emphasized the importance of creating a game that was visually sophisticated, consistent, and most of all, entertaining. Another consequence of using minimal controls ties back to the assignment itself. Our project must include a relatively unique way of interaction, meaning my plan for a very simple controller would need to be improved somehow.

                While the topic of video games was on my mind, I noticed my friend using a slide potentiometer that he planned to implement into his final project. I found the movement of it to be very smooth and accurate, making it a preferable candidate for the controller for my game.

               I realized that it similarly resembled a throttle control found in many modern-day vehicles, and my mind started to explore possible themes for my game that would be relevant. Not long after, I checked out a slide potentiometer from the IMA equipment room. When playing around with it, I found the use of a slide potentiometer as a throttle to feel very arcade-like, which was also the style for what I wanted my game to be (an arcade game). Nonetheless, there were many more things I needed to figure out before I began developing.

                Before planning out what game I would create, I realized it was important to first understand the possibilities and limitations within the Processing software. I began to research the games that other people created in Processing. I started with browsing through many of the 2D games uploaded by the community on Open Processing’s website. Since I was trying to figure out what elements were possible to include in my game, I was specifically looking for the most developed and complicated games. In my search, I analyzed and played around with a wide variety of both unimpressive and noteworthy games. One of these was a game titled “Timberman” by Santiago Fiorino, which provides a strong example of how this research helped. While I found the game to be poorly made and very undeveloped, it utilized different animations for the character. In return, I learned that this element is possible to include, and my game could utilize different character animations as well.

                It’s important to note that at this point during my research, the theme I had in mind for my game steered in the direction of something similar to the well-known mobile game called “Flappy Bird”.

               While this game is notorious for being super simplistic, there are elements that make the game entertaining and challenging that I wanted to include in my own game. For example, the notion of dodging obstacles by controlling the y-axis of a character is perfectly suitable for the sliding potentiometer I hoped to use. Also, this challenge of dodging obstacles can be very entertaining, especially if there is enough variety in their occurrence and a progression of difficulty. Anyways, back to researching…

                After testing and viewing the source code for the many games that I found online, it was obvious that I needed to massively develop my understanding and ability to code in the Processing software. By typing something along the lines of “how to make a game in processing” into google, I discovered two websites that would prove to be massively helpful resources. The first one was a post titled “Let’s make a Mario game” which provided an in-depth tutorial on how to make a simple Mario-styled game in Processing. Unfortunately, the game was made using Java Script in Processing.js, making the code explained somewhat useless since I would be coding in a different language. Regardless, this tutorial provided an excellent reference for figuring out the elements I want to include in my game beforehand. For example, the beginning of this tutorial discussed the type of background for the game. Since the author was creating a Mario-styled game, he noted how the background should move according to the movement of the player. It made me think that if I do decide to create a Flappy Bird style game, I would want to use a background consisting of different layers that are on a loop to create an illusion of distance and movement.

               The second website this search brought was an article titled “Ultimate Guide to the Processing Language Part II: Building a Simple Game” by Oguz Gelal. This tutorial massively contributed to the production of my game and can be credited for many of the elements I was able to include. After all, the game that is developed throughout the tutorial is literally called “Flappy Pong”- which was basically a different take on the game Flappy Bird. After skimming through this post, my plan to create a Flappy Bird styled game was only encouraged and eventually became definite. There are only a few tutorials online for developing video games in Processing, and this one is perfectly suitable for what I planned on making.

Oguz Gelal’s Flappy Pong game

                    After reading through the tutorial, I carefully analyzed the finalized Flappy Pong game. I thought it would be important to figure out what elements my current game concept shared with it. After figuring these similarities out, I would then be able to take out the corresponding sections of code from the tutorial. As a result, I could have the core elements for my game already established, allowing me to prioritize other elements I wanted to include and return to altering the copied code later- especially once I figured out the theme for my game.  

                 First, Flappy Pong utilized different game screens: an initial screen, the game screen, and a game over screen. The initial screen would serve as the introduction, displaying the title and other relevant information. After clicking to continue, the initial screen would shift to the game screen, where the game is played. When the user loses, the game screen shifts to the game over screen, where the score is shown as well as the option to retry. Since my game would be an arcade game, these different screens were perfect to include. The code made in the tutorial for this structure provided me with an organized and efficient way to implement the contents for each screen throughout the development process.

                Another element I wanted to reference this tutorial for was the randomly generated walls that would serve as the obstacles. The code made by the author included interchangeable variables for the attributes of the walls, making it easy to alter according to my desires. The code also included a method for determining collisions between the “ball” and the walls. This would be very useful since my game would involve consequences when the user failed to avoid the obstacles as well. Though ultimately needed to be edited anyways, the code for recognizing when something collides with the walls was extremely intricate and by including it early on, I saved a lot of time and confusion.

                After the different game screens and randomly generated walls were in place, it was time to start creating the character. I hooked up the slide potentiometer to an Arduino circuit and established the communication to Processing. Since Processing would be able to read the values given by the potentiometer, I could have the movement of the character controlled by it. Since I didn’t know what my character was going to be yet, I used an ellipse in its place. The ellipse was fixed to a certain value on the x-axis, while its location on the y-axis was determined by the slide potentiometer.

                At this point, it became obvious that I needed to figure out what type of theme my game should have in order to make more progress. Lacking creativity in this department, I decided to browse EnvatoMarket and view the game sprites that could be used as my main character. This proved to be a great idea, as I was immediately overwhelmed by the number of options related to what I was searching for. After considering a variety of spaceships, planes, rockets and everything related, I decided to use a submarine as the main avatar. I chose this for a few reasons. First, the complicated generated walls that my game contained had to match with the theme. If I decided to go with the submarine, then the walls could be changed to rocks throughout a cave. Second, I had a lot of ideas for cosmetics that would work well if I was to go with an underwater-styled theme. Finally, I really enjoyed the animations that were included for the submarine. There were different images for levels of damage on the vessel, which I wanted to use for when the user collides with one of the obstacles. Once I made my decision, I purchased the rights to download and use this content, as well as a portfolio of similar-styled background layers from the same creator.  

 

 

 

 

              With the structure, core elements, controller input, and theme of the game established, I could finally start developing and altering further aspects of my game. Since this documentation is already ridiculously long, I’m going to skip most of the things I added during this period. I would like to include a few things which were very challenging and did not go the way I expected to though.

               A significant problem I encountered was related to the use of gifs in Processing. Since I had such cool little animations from purchasing the submarine game graphics, I really wanted to include them in some way. Using these animations was not as simple as it seemed, and after extensive research on forums and references, I realized that Processing no longer supports the use of .gif files. Furthermore, the downloadable library that solved this problem was no longer available, neither in the software itself or anywhere I came across online. I ultimately tried to overcome this problem by separating the images within the gif files and having them animate directly within Processing. I achieved this by having the images shift between one another based off intervals of milliseconds that passed. While the result was working, it had two major consequences. The first one I realized was that using this method caused the game to have lag, but I was able to slightly reduce this by increasing the intervals between shifts in the images. The second problem was much more severe- this method of animating the submarine massively complicated my desire to include the different levels of damage on the vessel. Since this is something that I thought was more important to include, I decided to exclude the animations with hopes to get back to it in the future.

 

             Another major setback I encountered was during the later-stages of my game development. The code I used from the tutorial that generated the walls had them appear as black rectangles with rounded edges. When I chose to use an underwater-styled theme for my game, I intended to replace these rectangles with rocks, which would also be totally different shapes than rectangles. This problem I encountered was massively due to over estimating my ability to understand and alter the code for these walls when I would need to. Since I was finally at the point where it was appropriate to make this adjustment, I confidently scrolled down to the copied code from the tutorial. After hours of re-reading this section in the tutorial, countless forum posts, references on Processing’s website, and YouTube videos, I still couldn’t understand what was going on within the code. During this period, I made many attempts at making the changes I intended, but each one failed. Ultimately, I realized that changing the code from making randomly generated walls to randomly generated rocks was not possible with my current understanding of the language as well as the time restraints to complete this project. Regardless, my game massively depended on this element and it was too late to turn back. Since my previous intentions weren’t realistic, I decided my best option was to change the texture of the walls themselves. Even though they would still appear as out-of-place rectangles, I thought at least they could have the appearance of rocks. I somehow still had confidence in my ability to do this, since I thought it would be as simple as using the texture function on the already made walls. I was once again totally wrong, and I spent more hours trying to determine the vertex points of randomly generated moving rectangles. Eventually, I decided to just change the code from spawning randomly sized rectangles to randomly sized images of a cartoon-styled rock that I found would most closely fit into the theme.

            Although it worked, I wasn’t pleased with the result as it looked anything but natural within the game. Regardless, I was running out of time to complete my project, and I would have to leave this element how it was as there were countless more things I needed to accomplish.

                A few days later and after much trial and tribulation, I finally had a complete version of my game that resembled what I originally had in mind. I chose to name the game “Submarine Explorer” as a placeholder for when I thought of a more creative name. It was now time to focus on the controller for my game, which at this point was just a slide potentiometer. I was still determined to utilize only this single piece, as I had confidence in my ability to transform this minimal input into a unique, entertaining, and relative method of interacting with the game. I was also still fixed on the idea of using the slide potentiometer to mimic a throttle control for changing the depth of the submarine, so it was important to clearly convey this to the user. Because I intended for my project to resemble an arcade-styled game, I began to draw concepts that used a board-like interface that contained both the controls for the game, as well as the information on how to play.

                I really liked how this looked and thought that as long as I did a good job with the actual designs on it, the controller should have no problem achieving my intentions stated before. I found a strong and in-tact piece of cardboard to use as the base. I then carefully made cuts to make ideal dimensions for the board, as well as a space that perfectly would fit the slide potentiometer. Since the overlay that contained all the text and illustrations needed to be sophisticated, I couldn’t just draw directly onto the cardboard. It was clear to me that this overlay would be best if made with the use of software and then printed out and glued to the cardboard. However, the cardboard was already cut, which meant that the overlay I would print out had to perfectly align with it. I downloaded Adobe Illustrator since the professor suggested that it would be easiest to achieve this in. I carefully copied the dimensions of the cardboard and then created the size of the canvas in Illustrator accordingly.

               After printing the colored overlay out and gluing it to the cardboard, I was very happy with the result. I placed the sliding potentiometer into the designated space and secured it with a piece of tape on the back. In order to fully accomplish my design, I needed to attach some sort of piece to the slide potentiometer that resembled a handle. Luckily, I found the perfect piece while scavenging through the storage room. After using hot glue to secure it to the potentiometer, my controller was complete.

After completion, I realized that I forgot to change the name of the game to something more creative. Also, this photo was taken after our final was presented, and the “handle” I attached fell off when transporting the board

 

 Below is a demonstration of playing the finalized game with the control board being used.

 

               

 

 

//////////////////////_____ARDUINO____////////////////////////

  int sensor1 = A0;
   int a = 0;
  
void setup() {
  Serial.begin(9600);
}
void loop() {
  a = analogRead(sensor1);
  Serial.print(a);
  Serial.println(); // add linefeed after sending the last sensor value
  // too fast communication might cause some latency in Processing
  // this delay resolves the issue.
  delay(20);
}



////////////////____PROCESSING___//////////////////


//*******Submarine Explorer********//
// NYUSH IMA
// Final Project
// Jake Scavone
// **Credit to original author of "Flappy Pong" processing game for providing tutorial how to make many of the elements included
//*********************************//


// Arduino Communication - Import Processing Values
import processing.serial.*;
String myString = null;
Serial myPort;
int NUM_OF_VALUES = 1;  
int[] sensorValues;      /** this array stores values from Arduino **/

// Sound Files
import processing.sound.*;
SoundFile gameplay;
SoundFile crashing;

// Sprites - Change Image depending on health
int gameScreen = 0;
PImage photo;
//PImage[] ship = new PImage[2];
PImage photo2;
//PImage[] ship = new PImage[2];
PImage photo3;
//PImage[] ship = new PImage[2];
PImage explosion;
PImage heart;

// Scoring
int score = 0;
int maxHealth = 100;
float health = 100;
float healthDecrease = 1;
int healthBarWidth = 60;

// collision settings
float ballX, ballY;
float ballSize = 50;
color ballColor = color(0);

// Background Bubbles
Drop[] drops = new Drop[20];
PImage bubble;

//Background Image
PImage ocean;
int x=0;

//Rock Image
PImage rock;

// Wall Settings
int wallSpeed = 10;
int wallInterval = 1700;
float lastAddTime = 0;
int minGapHeight = 100;
int maxGapHeight = 300;
int wallWidth = 200;
color wallColors = color(94, 102, 96);
ArrayList<int[]> walls = new ArrayList<int[]>();

/********* SETUP BLOCK *********/

void setup() {
  size(1500, 1000);
  ballX=200;
  ballY=400;
  setupSerial();
  gameplay = new SoundFile(this, "gameplay.mp3");
  crashing = new SoundFile(this, "crash.mp3");
  gameplay.play();
  ocean = loadImage("ocean.png");
  ocean.resize(1200, 1000);
  photo = loadImage("ship.png");
  photo2 = loadImage("ship2.png");
  photo3 = loadImage("ship3.png");
  heart = loadImage("heart.png");
  //  ship[0] = loadImage("ship1.png");
  //  ship[1] = loadImage("ship2.png");
  rock = loadImage("rock.jpg");
//  explosion = loadImage("explosion.gif");
  smooth();
  
  //bubbles
  bubble = loadImage("bubble.png");
  for (int i = 0; i < drops.length; i++) {
    drops[i] = new Drop();
  }
}


/********* DRAW BLOCK *********/

void draw() {  // Display the contents of the current screen
  if (gameScreen == 0) { 
    initScreen();
  } else if (gameScreen == 1) { 
    gameScreen();
  } else if (gameScreen == 2) { 
    gameOverScreen();
  }
}

/********* SCREEN CONTENTS *********/

void initScreen() { // Starting Screen
  background(158, 205, 216);

// Bubbles
  for (int i = 0; i < drops.length; i++) {
    drops[i].fall();
    drops[i].show();
  }
// Start Screen Text Contents:
  textAlign(CENTER);
  fill(52, 73, 94);
  textSize(70);
  text("Submarine Explorer", width/2, height/2);
  textSize(20);
  text("An Interactive Game by Jake Scavone", width/2, height/2+50);
  textSize(30); 
  text("Press any Key to Start!", width/2, height-30);
}






void gameScreen() { // Level of the Game
  updateSerial();
  tint(255, 255); // Tint the bubbles by opacity
  background(236, 240, 241);
  image(ocean, x, 0);
  // Loop ocean background
  image(ocean, x+ocean.width, 0);
  x--;
  if (x<-ocean.width) 
    x=0;
  {
    for (int i = 0; i < drops.length; i++) {
      drops[i].fall();
      drops[i].show();
    }
  }
  
  tint(255, 255); // Tint back to Normal Opacity (So it doesn't affect the environment)
  
  // Collision and Sprite animation images
  drawBall();
  {
    if (health > 80) {
      image(photo, 120, sensorValues[0] - 60);
      photo.resize(130, 100);
    } else if (health > 30) {
      image(photo2, 120, sensorValues[0] - 60);
    } else {
      image(photo3, 120, sensorValues[0] - 60);
    }
  }
  photo.resize(130, 100);
  // image(photo, 120, sensorValues[0] - 60);

// Place Classes
  drawHealthBar();
  wallAdder();
  wallHandler();
  printScore();
}




void gameOverScreen() { // Game Over Screen
  background(158, 205, 216);
//gameplay.stop();
// Bubbles
  for (int i = 0; i < drops.length; i++) {
    drops[i].fall();
    drops[i].show();
  }
  
  // Text on Screen
  textAlign(CENTER);
  fill(236, 240, 241);
  textSize(40);
  text("Your Score:", width/2, height/2 - 120);
  textSize(130);
  text(score, width/2, height/2);

// Custom Ending Messages
  textSize(30);
  if (score < 5) {
    text("That's a pretty low score, you should probably practice...", width/2, height/2 + 50);
  } else if (score < 15) {
    text("Not bad! Try again...", width/2, height/2 + 50);
  } else if (score < 25) {
    text("Wow! You're a pro!", width/2, height/2 + 50);
  } else if (score < 100) {
    text("You hold the record!", width/2, height/2 + 50);      // Add more in the future
  }
  textSize(30);
  text("Press any Key to Restart!", width/2, height-30);
}


/********* INPUTS *********/

public void keyPressed() {
  // if we are on the initial screen when clicked, start the game 
  if (gameScreen==0) { 
    startGame();
  }
  
  // if we are on the end screen when clicked, restart the game
  if (gameScreen==2) {
    crashing.jump(0);
    restart();
  }
}



/********* OTHER FUNCTIONS *********/

// This method sets the necessery variables to start the game  
void startGame() {
  gameScreen=1;
}
void gameOver() {
  gameScreen=2;
}

void restart() {
  score = 0;
  health = maxHealth;
  //  ballX=width/4;
  //  ballY=height/5;
  drawBall();
  lastAddTime = 0;
  walls.clear();
  gameScreen = 1;
}


// Collision Object
void drawBall() {
  fill(ballColor);
  ellipse(ballX, sensorValues[0], ballSize, ballSize);
}



void wallAdder() {
  if (millis()-lastAddTime > wallInterval) {
    int randHeight = round(random(minGapHeight, maxGapHeight));
    int randY = round(random(0, height-randHeight));
    // {gapWallX, gapWallY, gapWallWidth, gapWallHeight, scored}
    int[] randWall = {width, randY, wallWidth, randHeight, 0}; 
    walls.add(randWall);
    lastAddTime = millis();
  }
}
void wallHandler() {
  for (int i = 0; i < walls.size(); i++) {
    wallRemover(i);
    wallMover(i);
    wallDrawer(i);
    watchWallCollision(i);
  }
}
void wallDrawer(int index) {
  int[] wall = walls.get(index);
  // get gap wall settings 
  int gapWallX = wall[0];
  int gapWallY = wall[1];
  int gapWallWidth = wall[2];
  int gapWallHeight = wall[3];
  // draw actual walls

  //  rectMode(CORNER);
  //  noStroke();
  //  stroke(130, 130, 130);
  //  strokeWeight(5);
  //  strokeCap(ROUND);

  //  texture(rock);
  fill(wallColors);
  {
    rect(gapWallX-10, 0, gapWallWidth+20, gapWallY, 0, 0, 15, 15);
    rect(gapWallX-10, gapWallY+gapWallHeight, gapWallWidth+20, height-(gapWallY+gapWallHeight), 15, 15, 0, 0);
    image(rock, gapWallX, 0, gapWallWidth, gapWallY);
    image(rock, gapWallX, gapWallY+gapWallHeight, gapWallWidth, height-(gapWallY+gapWallHeight));
  }
}



void wallMover(int index) {
  int[] wall = walls.get(index);
  wall[0] -= wallSpeed;
}





void wallRemover(int index) {
  int[] wall = walls.get(index);
  if (wall[0]+wall[2] <= 0) {
    walls.remove(index);
  }
}


// Detecting if Ball collides with walls
void watchWallCollision(int index) {
  int[] wall = walls.get(index);
  
  // get gap wall settings 
  int gapWallX = wall[0];
  int gapWallY = wall[1];
  int gapWallWidth = wall[2];
  int gapWallHeight = wall[3];
  int wallScored = wall[4];
  int wallTopX = gapWallX;
  int wallTopY = 0;
  int wallTopWidth = gapWallWidth;
  int wallTopHeight = gapWallY;
  int wallBottomX = gapWallX;
  int wallBottomY = gapWallY+gapWallHeight;
  int wallBottomWidth = gapWallWidth;
  int wallBottomHeight = height-(gapWallY+gapWallHeight);

  if (
    (ballX+(ballSize/2)>wallTopX) &&
    (ballX-(ballSize/2)<wallTopX+wallTopWidth) &&
    (sensorValues[0]+(ballSize/2)>wallTopY) &&
    (sensorValues[0]-(ballSize/2)<wallTopY+wallTopHeight)
    ) {
    decreaseHealth();
    crashing.play();
  }
  if (
    (ballX+(ballSize/2)>wallBottomX) &&
    (ballX-(ballSize/2)<wallBottomX+wallBottomWidth) &&
    (sensorValues[0]+(ballSize/2)>wallBottomY) &&
    (sensorValues[0]-(ballSize/2)<wallBottomY+wallBottomHeight)
    ) {
    decreaseHealth();
    crashing.play();
  }
  
// Adding a point to score when pass wall
  if (ballX > gapWallX+(gapWallWidth/2) && wallScored==0) {
    wallScored=1;
    wall[4]=1;
    score();
  }
}


void drawHealthBar() {
  noStroke();
  fill(189, 195, 199);
  rectMode(CORNER);
  rect(ballX-(healthBarWidth/2) - 20, sensorValues[0] - 70, healthBarWidth, 5);
  if (health > 60) {
    fill(46, 204, 113);
  } else if (health > 30) {
    fill(230, 126, 34);
  } else {
    fill(231, 76, 60);
  }
  rectMode(CORNER);
  rect(ballX-(healthBarWidth/2) - 20, sensorValues[0] - 70, healthBarWidth*(health/maxHealth), 5);
}




void decreaseHealth() {
  health -= healthDecrease;
  if (health <= 0) {

    gameOver();
  }
}
void score() {
  score++;
}



void printScore() {
  fill(89, 188, 255);
  stroke(27, 129, 198);
  strokeWeight(3);
  rect(40, 30, 130, 50, 7);
  textAlign(CENTER);
  fill(255);
  textSize(30); 
  text(score, 150, 67);
  textSize(30); 
  text("Score:", 90, 67);
}



// Reading Inputs from Arduino
void setupSerial() {
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[ 0 ], 9600);
  // WARNING!
  // You will definitely get an error here.
  // Change the PORT_INDEX to 0 and try running it again.
  // And then, check the list of the ports,
  // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" 
  // and replace PORT_INDEX above with the index number of the port.

  myPort.clear();
  // Throw out the first reading,
  // in case we started reading in the middle of a string from the sender.
  myString = myPort.readStringUntil( 10 );  // 10 = 'n'  Linefeed in ASCII
  myString = null;

  sensorValues = new int[NUM_OF_VALUES];
}

void updateSerial() {
  while (myPort.available() > 0) {
    myString = myPort.readStringUntil( 10 ); // 10 = 'n'  Linefeed in ASCII
    if (myString != null) {
      String[] serialInArray = split(trim(myString), ",");
      if (serialInArray.length == NUM_OF_VALUES) {
        for (int i=0; i<serialInArray.length; i++) {
          sensorValues[i] = int(serialInArray[i]);
        }
      }
    }
  }
}

Working with Electrons | Final Project – Pellegrino (Cossovich)

Final Project | Power Bank

Presentation: Final Project Powerpoint

Objective:

The objective of this project is to build a power bank as DIY as possible for the purpose of learning, experimentation, and for exploring using different chips, navigating blueprints, printing PCB and more. Ultimately, my goal is to build a functioning power bank as “from scratch” as possible. So if it’s possible for me to print the PCBs for both circuits and assemble it, that’s the best option. However, if it’s only possible to print one, or simply to use preassembled modules, that’s also an option although it’s slightly less to my objective of building it completely DIY. Overall, my objective is an explorative inquiry into understanding how a power bank works through building one as DIY as possible.

Inspiration:

My original inspiration for this project simply comes from Shanghai in general. I use my phone a lot when navigating the city both for directions, transportation, and payment alike. However, my phone has, on far too many occasions, run out or nearly run out of battery while I’m out in the middle of the city. For this reason, I’ve always wanted to invest in a power bank or portable charger so as not to run into this danger again. Additionally, I didn’t previously know very much about portable chargers or how they work. Therefore, for my final project, I decided to build a power bank so that I would have one for my phone if needed, so I could learn how it works, and for the satisfaction of building something myself.

How it works:

In it’s most basic sense, a power bank contains two circuits that work as follows: the first is the charging circuit which is designed to charge a Lithium-Ion rechargeable battery. Then the second circuit, the booster circuit, is designed to step-up the voltage from the battery from 3V to 5V so that it can be output to a phone or device at the required 5V.

The basic function of the power bank.

Additionally, when shopping for a power bank, it’s usually customary to check for two main things. The first is the bank’s size in mAh. mAh, or milliampere hours, is the capacity of the battery which is equal to its average amperage multiplied by the number of charging hours. In conventional power banks, this range is generally from 2,000 to 12,000 mAh. Essentially, the higher the mAh, the more times you will be able to charge your phone from it before needing to recharge the bank itself.

Another thing to check when looking for a power bank is its average amperage, or current, that is drawn by the phone or device. Generally, at least 1A is required to register that a device is charging, but overall, banks average between 1-4.8A. The higher the amperage, the faster your phone will charge. So both capacity and speed are the two major components that differentiate various power banks.

The charging circuit itself is usually a TP4056 module. This module is specifically designed to charge single-cell lipo batteries and requires an input voltage of 5V and runs at a fixed 4.2V. The module itself can have customized amperage depending on which resistor is used in the pin 2 connection to ground. The recommended amperage is roughly 37-40% of the battery capacity. In this case, it should be configured to roughly 814-880mA for the 2200mAh battery (described below) which would require using roughly a 1.33k ohm resistor (1.5k ohm –> 780mA; 1.33k ohm –> 900mA). However, as will be explained below in my procedures, I left the module untouched with its standard 1.2k ohm resistor that provides the maximum amperage of 1000mA.

TP4056 Module

This module includes two LEDs which indicate charging. The red LED indicates the device is charging while the green LED indicates standby. If the input voltage is too low (within 30mV of the battery’s voltage) the module will enter standby mode, dropping current output to less than 2uA. In this case, the LEDs will be off. Furthermore, the LEDs will be off if the temperature of the battery is either too high or too low (this is monitored with an NTC thermistor), or if there is no battery output connected.

The battery is a 18650 Lithium-Ion Cell designed with a nominal capacity of 2200 mAh and a nominal voltage of 3.7 V.

As for the booster circuit, there is no clear or defined module. The circuit itself is a DC-to-DC step-up power converter intended to step up the voltage between the input and output while stepping down the current. Most modules function with at least a diode and transistor, to help control the current flow, along with a capacitor and inductor, to help store energy.

Basic Booster Converter

Additionally, the general function enacts through a MOSFET switch (other switches can be used, but generally booster circuits use a MOSFET). The MOSFET works as a transistor that switches between an open and closed state. In the closed state, the inductor receives current flow and generates a magnetic field which stores some energy. In the open state, the magnetic field collapses in order for the current to continue flowing towards the output. This actually reverses the current flow through the inductor and puts it in series with the source. With the inductor and source in series, a higher voltage is attained.

Additionally, the capacitor is charged in parallel with the device at the same boosted voltage. Therefore, when the switch goes back to the closed state, thus reversing the current flow in the inductor and generating a magnetic field while eliminating the inductor and source working in series, the capacitor, protected by a diode to flow to the source, continues to provide the same voltage to the output load.

In essence, the booster circuit works through a switch, generally a MOSFET, that alternates between an open and closed state. The voltage is boosted through the inductor’s reaction to the alternating switch, which puts it in series with the source. Then this voltage output is sustained through the capacitor which is charged simultaneously with the load while the switch is open and then charges the load itself when the switch is closed.

Part I: Booster Circuit Research

After the preliminary research into how the power bank functioned both as a whole and through its individual circuits/components, my next step was determining which booster circuit I should use. While the charging circuit was clearly defined with the TP4056 module, I needed to decide which booster circuit would be best. In this case, I define ‘best’ as being a chip with a clear and readable schematic, datasheet, and explanation of functionality, it should be easy to acquire/available through a Taobao order at a reasonable price, it should be relatively easy to solder (the shape of the component itself shouldn’t be too small and the legs should be well-spaced), and it should have a decently high current so as to provide effective and efficient charging to my device.

Some of the chips that I researched included the HT7750A, MAX641, and LT1111. While I won’t go into too much detail since I didn’t use any of the above chips, they were all configurable booster converters which allowed for stepping-up 3V to 5V, which we needed, or could be configured to step-up a variety of range of voltages. The biggest thing to consider between the above chips was their amperage and their shape. The HT7750A provided the highest amperage, but only at 200mA which is not high enough to be readable by a phone that requires a minimum of 1000mA. Additionally, most of the chips were made to be soldered to a PCB through a machine and are not designed in a friendly way to soldering free-hand.

In the end, we settled on the PAM2401 which, although still providing a challenge to solder, was easily accessible through Taobao, provided 1000mA, and could be configured to boost 0.9-4.75V input to 2.5-5V output (but we just need the 3V-5V configuration).

Part II: Developing Schematics & Board

Now that I knew both circuits required in the power bank, the TP4056 to charge the battery & the PAM2401 to charge the phone, the next step was actually developing the schematic for each and printing the board. Unfortunately, this part, along with the previous research portion, required a lot more time than I had anticipated which will be more evident in the later parts of this inquiry. Because the research process took so long, I didn’t have time to really sit with the schematics or designs as much which explains why there are so many different trials and attempts before settling on a single PCB blueprint that I downloaded prearranged.

TP4056 (trial 1):

I first attempted to recreate the above schematic from the TP4056 datasheet in Eagle. The biggest challenge in this stage was ensuring I used the correct library so the components that I placed would be the correct dimensions for the physical pieces. Additionally, neither Eagle or the Sparkfun library that I had downloaded included a model for the TP4056 chip and I had trouble finding another library that had it.

TP4056 (trial 2):

As a second path, I found the above prearranged Eagle schematic from e-radionica‘s GitHub. This looked complete, however, I had difficulty matching it exactly to the datasheet’s schematic. Additionally, it used a different chip in the Eagle schematic (a DIO5158 instead of the TP4056). To the best of my knowledge, the creator of this schematic used the DIO5158 under the assumption that it has the same dimensions and physical construction of the TP4056 which allows it to sit as a placeholder in the schematic. I attempted to move forward with the downloaded schematic, however, and went about replacing the resistors (which were previously surface-level) with through-hole resistors to make the soldering process easier. However, this was quite time-consuming and I was still unsure if this was the correct schematic so, as will be explained below, I switched to the double-sided complete schematic.

TP4056 (trial 3):

In my second attempt, I found another premade schematic from circuitdigest. However, this used a different opensource software called easyeda rather than Eagle. This schematic came complete with both the charging module and the booster module, however, I isolated the charger module in the below schematic.

I found this schematic much easier to read and it included the correct central chip so I felt more comfortable moving forward with it. The next step, similar to the above attempt in Eagle, was replacing the resistors so that they were through-hole resistors. I then exported it to a board where the long journey of placing/arranging the components began. Two of the attempted iterations are below, however, there were many many many more iterations that I didn’t document.

After spending a good number of hours trying to puzzle through a convenient placement, I decided it was time to move on. Unfortunately, because the initial research and schematic organization process took so much time, I did not have enough time to keep attempting the placement process. However, through the process, I learned a lot about placement theory, such as the order in which components should be placed depending on their nature (i.e. the USB should be at the edge of the board no matter what so it can be connected while the chip should be placed relatively center since it is the focus) along with orientation (i.e. it’s good practice for all components to be oriented in the same direction, either vertically or horizontally).

PAM2401 (trial 1):

For the PAM2401, I used Eagle to design the schematic based on the datasheet configuration.

Datasheet Schematic

Eagle Schematic

This process was much easier since I’m more familiar with the schematic drawing software from working with both Eagle and easyeda. However, after completing the schematic, I realized that the chip I’d been using provided in an Eagle library was different from the chip used in the schematic in that it was missing the PG pin. While they are the same chip, it turns out there are different models/variations of the chip. Due to the impending time constraint, I decided not to pursue the research to correctly wire the model of the chip found in Eagle.

TP4056 & XL6009:

In the end, I settled on using the preassembled schematic and circuit board found through easyeda. Whereas before I’d isolated the TP4056 portion of the circuit, I decided it would be more time effective to simply leave it together with the booster circuit so that they could be printed all at once.

 

While the charger portion of the circuit utilizes the same TP4056 module, the booster side of the circuit uses a different chip, the XL6009. While this chip is still a DC-to-DC boost converter, according to its datasheet its typical uses are designed for higher voltages. For example, the general voltage input range should be between 5V to 32V. While the absolute minimum voltage the chip can take is said to be between -0.3V and 36V, it’s typical configurations are aimed at inputs of 5V or higher. Our booster converter, again, should be 3V to 5V so, while there’s a little concern as to whether this will be an effective booster, at the very least the schematic is readable and the PCB board is already assembled for printing which, at this point in the project, is essential for saving time.

Part III: Printing the PCB

Printing the actual PCB was probably the most exciting process of this project (aside from soldering just because I really do love soldering). The PCB blueprint was for a two-sided PCB, which made it a bit more complicated, but the machine itself was very explanatory.

Attempt 1:

In printing, the biggest thing to pay attention to was which drill the machine required to ensure that it could remove the correct bits of copper effectively.

In the first printing attempt, I accidentally flipped the board without checking that it was aligned in the same position. This caused the backside of the PCB to be printed slightly off-center from the front which blocked some of the holes.

Attempt 2:

On the second attempt, the PCB printed fine overall, however, it did not remove the excess copper from the top layer.

Because of the excess copper on the board, it would be nearly impossible to solder it because any solder that overflows onto the excess copper would force unintentional connections in the wiring.

In the end, not only did the final PCB have excess copper on the surface, but the PCB printing machine we have is not equipped to print the small VIA (vertical interconnect access) holes which the board design requires to make connections between the two sides of the PCB.

Even though the board was relatively unusable, I still wanted to at least try soldering the small TP4056 chip onto its surface. Unlike the perf board that I’d used in the mid-term which functioned entirely with through-holes, the chip in this circuit is only surface level. I soldered it by first adding just a small dot of solder to each point on the PCB that had a connection. Then I did the same to each leg of the chip. Finally, I used the iron to basically melt the two together. In the end, I think it is slightly crooked, so if the circuit was fully assembled it would not work properly, however, it was still good practice for the full ‘DIY’ experience.

Part IV: Circuit Assembly

Despite all of my research and groundwork provided in the previous steps with the goal of creating a completely DIY power bank, in the end, I had to compromise to assembling the circuit with premade circuit modules for both the TP4056 and the booster circuit.

Since the circuits were already assembled into PCBs with USB connectors, the most challenging aspect of this part was simply figuring out how to solder the battery. After watching a video tutorial, I soldered it by first scratching the surface of the battery end a little before applying a healthy amount of flux and then soldering by continually feeding the solder until it finally stuck. Then I used hot glue to ensure it wouldn’t pop off.

Part V: Does it work?

Now that the power bank is assembled, the biggest remaining question is, does it work? So the first test was simply to see if it worked at all.

I used Kevin’s phone, which was completely dead and turned off, to test and it takes a micro-USB cable. After plugging it in and turning on the booster module with the switch, the phone did register charging because a white light started blinking at the base. After about a minute, the phone actually powered itself on, as dead phones do when they charge, which, without acute measurements, means that at the very least, the power bank works to charge a phone. Once the phone was on, it did not register on the screen itself that it was charging, however, very gradual the battery life would increase.

When I tested it on my phone, which is an iPhone requiring the lightning bolt adapter, it similarly did not register the charging state on the phone itself, however, the overall charge percentage would gradually increase. The overall charging is very slow, however, due to the low current of the booster circuit (which will be explored below). For example, I kept Kevin’s phone charging throughout the entirety of our project presentations last Thursday (roughly 2 hours) and it went from completely dead to 10% charge. So although it is quite slow, it works.

Part VI: Measurements

Pre-Assembly Individual Circuit Voltage Measurements:

Before assembling the circuit at all, I measured the input/output voltages of each circuit uniquely. When provided 4.91V by the power regulator, the TP4056 module maintained a constant output of 4.1V. Additionally, the booster circuit (which is a mysterious circuit we found in the lab, who’s exact chip or core is unknown), when given 3.06V from the power regulator, output 5.06V.

TP4056 Module:

In terms of the TP4056 module, Rudi helped me wire it with a multimeter that can read current.

While in standby mode (green LED, not charging), the current measured at about 0.1uA.

In charging mode (red LED), the current measured at roughly 340mA and an output voltage of roughly 4.15V.

Using the above measurements, we can calculate the circuit’s wattage using current * voltage: 1.411 W = 4.15 V x 0.34 A.

Additionally, we wanted to test the charging trend over time. The battery itself was already almost charged. Initially, it read 3.96V and, after running the charging module for roughly 5min while we measured the current, the voltage had increased to 4.2V. In that short time, it was evident that, as the voltage increased, the current decreased (which makes sense in order to satisfy Ohm’s law that current is proportional to the voltage across two points).

In order to explore this concept further, we first had to discharge more of the battery.

Using the booster circuit, I attached two wires to the USB output.

I then connected the booster circuit to a motor. The motor draws a high current so, after turning on the module, it was effective in rapidly discharging the battery.

As stated above, the battery initially had 4.2 V. After 30 minutes of charging the motor, the battery had decreased to 3.874 V. In further inquiry, I would continue discharging the battery using the motor and monitor not only the voltage but the current as well. From there, I would use the TP4056 module to charge the battery and, similarly, monitor the current and voltage in 5-10 minute increments. With this information, I would calculate the circuit’s overall average efficiency using the efficiency formula [(Poutput / Pinput) x 100%].

Booster Module:

As for the booster module, I would like to follow a similar line of inquiry as above and monitor its charging of a specific device (ideally a phone) over time and, additionally, calculate its average efficiency.

In terms of actual measurements, I compared the current and voltage output of the module when connected to my Bluetooth earbuds and to my iPhone.

***** disclaimer [start] *****

When completing the measurements, I recorded all measures of current in mA. However, as evidenced by the measurements below, 1.35 mA is frighteningly small and relatively impossible for charging a phone that requires a minimum 1A. Therefore, while I will keep the measurements as I have in my notes to maintain their integrity, it’s possible that the measurements between these disclaimers should be in A rather than mA (ex. 1.35mA –> 1.35A) as a result of poor recording.

First, the quiescent current (or measurement of current when there was no load attached) measured at roughly 2.05mA and 5V.

When attached to my Bluetooth earbuds, the red light on my earbuds illuminated to indicate charging. The current measured at 1.72mA (see disclaimer) and the voltage at 5.045 V.

Finally, when connected to my iPhone, the iPhone itself did not indicate that it was charging. However, the charge did increase from 13% to 14% and the current measured at 1.35 mA (see disclaimer) and the voltage at 5.09 V.

Additionally, I think there is a discrepancy because, even if we switch all the measurements of current into A, it doesn’t seem likely that the quiescent current should be higher than the current when there is a load attached. Therefore, I think it’s possible that the quiescent current is accurate at 2.05 mA and I forgot to switch units when measuring higher currents with the load. Altogether, I’m not entirely sure where the error is in these measurements, but my best guess is that they should read 2.05mA (quiescent), 1.72A (earbuds), and 1.35A (iPhone).

***** disclaimer [end] *****

Part VI: Summary of Measurements

Overall, the power bank works in the sense that it is capable of re-charging a lipo battery and can then discharge the battery through the booster circuit in order to charge a device. While the TP4056 module functions with similar general parameters as was expected through its datasheet, continued inquiry would involve both monitoring its usage overtime along with calculating its efficiency so as to have better comparable evidence of its function.

Additionally, with the booster module, I would like to continue with a similar inquiry into its usage over time along with its efficiency. However, the module itself is still a mystery to me because it doesn’t appear to have incorporated a specific chip. So, while I don’t have a datasheet to reference it with, based on the general input/output measurements it seems to function like a basic boost converter as I explained above in Preliminary Research. It would be good to know more about how this circuit works to see if its possible to modify it for higher currents. While overall the power bank functions effectively, it is not very efficient because the loads on the booster converter are unable to draw a high enough current.

Part VII: Housing Fabrication

Now that the circuit is functioning and we have gathered some measurements of it, the final step is to actually encase it in something so it is functional for everyday use. My goal for the power bank’s design is to be both small and to be comfortable to hold in your hand so it is more effective as a transportable device.

I first used hot glue to arrange all of the components around the battery. I tried to keep it as compact as possible while also keeping the USB connectors and button in a reachable location. Additionally, the glue helps to create a surface for the modules so that they’re supported in the back when you plug in a chord. However, it’s important to avoid gluing directly behind any of the module’s central chips since its possible they could heat up and melt the glue.

I decided to crochet the case out of yarn because it is softer than a 3D or laser cut fabrication which would make it more comfortable to carry in a pocket. My only concern with the crocheted case is that it might insulate heat when the modules are engaged. However, I made sure to use a relatively looser stitch which will hopefully allow the circuit to breath.

   

I made sure to leave a hole on either side of the case for the USB chords and, additionally, left a small hole on the top for accessing the button. In the end, it doesn’t look like your conventional power bank, but with its small size and soft texture I think it works nicely for carrying it easily and comfortably in a pocket.

After closing the case, I realized that I forgot to include a space in the crochet for viewing the LEDs on the charging module which is essential to knowing whether the battery is charged/charging. However, after testing the charging circuit in the case, it turns out that the LEDs reflect really well and are visible through the holes in the crochet. So even though they’re not entirely clear, they are readable.

Materials: 

The materials list really depends on which construction you follow. As elaborated above, I initially researched a number of different circuit configurations before settling on using the assembled modules.

For Module Based Assembly:

  • 18650 Lithium-Ion Rechargeable Battery (x1)
  • TP4056 Lipo Charging Module (x1)
  • 3V to 5V DC-to-DC Booster Module (x1)
  • Slide Switch (x1)
  • Wires (xMany)
  • Hot Glue
  • Yarn & Crochet Hooks

For Measurements:

  • Multimeter with current reading capabilities (x1)
  • Alligator Clips (xMany)

For Complete DIY Assembly:

  • TP4056 Chip (x1)
  • XL6009 Chip (x1)
  • 1k ohm resistor (x6)
  • Red LED (x1)
  • Green LED (x1)
  • Micro-USB (x1)
  • 5k ohm resistor (x1)
  • 220uF capacitor (x1)
  • 47uF capacitor (x1)
  • 1uF capacitor (x2)
  • 1N5824 Diode (x1)
  • 10uF capacitor (x2)
  • 33uH inductor (x1)
  • NTC thermistor (x1)
  • USB-A3 (x1)
  • 18650 Lithium Ion Battery (x1)
  • Zener Diode (x1)

Depending on which construction you make, further materials lists can be made by referencing the relevant datasheet linked above.

Improvements:

The most significant improvement that I would like to make with respect to this inquiry as a whole would be overall time management. I spent roughly 75% of the process researching how power banks work, how each circuit in the bank works, along with researching so many different chips for the booster converter that when it came time to actually design the power bank, I didn’t have enough time to really sit with and test various schematic constructions, PCB blueprints, or to thoroughly measure and document the end circuit’s functionality. While I certainly learned a lot through the research process, it’s time consumption prevented me from creating a completely DIY circuit as I had intended.

In terms of the power bank itself, some improvements that I’d like to implement in a future iteration would be:

  • Using a slide switch rather than a push button to activate the booster circuit,
  • Research into the mysterious booster circuit module that I used and see if there’s any way it can accommodate a higher current so as to facilitate faster device charging,
  • To more thoroughly document the two circuit’s current/voltage relationship over time along with their efficiency, and
  • To wire exterior LEDs to the charging circuit so they are more visible to the user.

Final Remarks:

I entered this project with the goal of creating a power bank as DIY as possible. While I, unfortunately, was unable to use my own designed or printed PCB for the final power bank, I did get a taste for the process of designing your own. Through the extensive pre-assembly process, I got much more comfortable referencing and reading datasheets, understanding how specific components function in a circuit, and, more specifically, how slight changes in resistors or other components can modify the circuit’s stats. Additionally, I familiarized myself with importing/modifying/designing schematics using both Eagle and easyeda software and gained a new respect for the process of organizing components on a PCB for printing. Finally, even though there are possible discrepancies in my measurements above, I think I gained a better understanding not only of how to complete these measurements, but also in how to compare them back to their respective datasheet and use the measurements to better understand the circuit functionality itself.

In the end, while the final power bank was a simple assembly, the many failed attempts and trials to create it completely DIY were extremely rewarding and fundamental to the overall learning process.

Works Cited

https://www.belkin.com/us/resource-center/portable-charging

https://circuitdigest.com/electronic-circuits/power-bank-circuit-on-pcb

https://circuitdigest.com/electronic-circuits/power-bank-circuit

http://www.learnabout-electronics.org/PSU/psu32.php

https://en.wikipedia.org/wiki/Boost_converter

https://en.wikipedia.org/wiki/MOSFET

Interaction Lab Final Project: Bobby (Ding Wang)

  • Name: Ding Wang
  • Professor: Eric&Young
  • Partner: Frank


CONCEPTION AND DESIGN

Conception

After Frank and I decided to choose “sustainability” as a significant issue for our project. We started from this point and thought about how can we raise the awareness of the environment protection. The first design came to our mind is a game. Because a game is an interesting way to attract people to get access to this problem. Firstly, Frank reminds me of the Pacman. We wanted to make some creative changes for this old game. Later, we thought maybe Pacman is not the most suitable game for us. So we began to design our original game. We integrated the concepts as garbage sorting and recycling and encouraging people to take more stairs into our game. We transformed different concepts into different functions in the game and finally had our final game.


FABRICATION AND PRODUCTION

I think there are three significant and hard steps in the fabrication and production process. The first step is at first when we are building the basic function for our game. Frank and I work on different functions at first. And both of us met many problems in the coding process.

The second step is making the controller. Sometimes the design is not practical as we thought, so we need to adjust our design according to the actual effect.

The third step is that after the user testing, we made some adjustments based on the suggestions from the users. An impressive thing for me is that, when we finished our project, I tried it first, and I told Frank maybe it’s a little easy. But most users reported that game control is too difficult and the instruction is not clear enough. And I think this is a difference between the game designers and users.  Because we are the designers, we are familiar with the game and we also even know many details about it. This difference immediately made me realize the importance of the user test session. So after the user testing, we add a more detailed instruction before the game to guide the user to finish the instruction step by step.


CONCLUSIONS

The goal of our project is by making a game to raise the awareness of environmental protection. From some response in IMA show, I think getting good game experience and participation in the game satisfies my definition of interaction. But I think our control system is not very good at achieving the purpose of interaction. This is also an improvement I want to make adding more interactive elements in the controller.

This is an interesting process for me to learn some further knowledge. And how to connect my knowledge with the practical design. The final project is a lesson for me to be familiar with all the processes from designing to adjusting finally.

import processing.serial.*;
import processing.sound.*;

SoundFile file;


Cleaner frank;
Bad ding, coco, ying, tina; 

PImage[] imgRubbish = new PImage[4];
PImage imgb, imgr, imgg, imgy, imgl1, imgl2, imgl3, imgflr1, imgflr2, imgflr3, imgrbt, imgrbtB, imgppr, imgele, imgmstOrg, imgmstGrn, imgmstBlu, imgmstYlw, imgflrA, back, imgRK1, imgRK2, imgRK3, imgRK4, imgItf; 

color cla = color(255, 0, 0), clb = color(255, 200, 0), clc = color(0, 200, 0), cld = color(20, 100, 255);
float badX, badY;
int m;
int xPos, yPos;
int ladderWidth = 75; 
int food = 0;
int elevatorTimes = 100 ;
int interval = 100;
int start;
int direcS = 1;
int x1 = 400;
int clickCounter = 0;
int currentButtonValue = 0;
int previousButtonValue = 0;


String BGM = "BGM.mp3";
String path;
String[] strings = {"You've been caught", "Time Up"}; 
color[] colors = {cla, clb, clc, cld};

boolean textState = true;
boolean textState1 = true;
boolean carry = false;
boolean freeze = false;
boolean tutorial = true;


//arduino

String myString = null;
Serial myPort;


int NUM_OF_VALUES = 7;  
int[] sensorValues;     


void setup() {

  //set up the music
  path = sketchPath(BGM);
  file = new SoundFile(this, path);
  file.loop();

  fullScreen();
  setupSerial();

  start = millis();


  //setup the good
  frank = new Cleaner(1300, 850);

  //set up the bad
  ding = new Bad( width/2-80, 598, 30);
  coco = new Bad( width/2+100, 346, 30);
  ying = new Bad( width/2-40, 94, 30);
  tina = new Bad( width/2 + 30, 850, 30);

  //set up the image
  imgItf = loadImage("InterFace.png");
  imgRK1 = loadImage("RK1.png");
  imgRK2 = loadImage("RK2.png");
  imgRK3 = loadImage("RK3.png");
  imgb = loadImage("blueTrashcan.png");
  imgr = loadImage("redTrashcan.png");
  imgg = loadImage("greenTrashcan.png");
  imgy = loadImage("yellowTrashcan.png");
  imgl1 = loadImage("lader1.png");
  imgl2 = loadImage("lader2.png");
  imgl3 = loadImage("lader3.png");
  imgflr1 = loadImage("floor.png");
  imgflr2 = loadImage("floor.png");
  imgflr3 = loadImage("floor.png");
  imgrbt = loadImage("rbt copy1.png");
  imgrbtB = loadImage("rbt copy.png");
  imgele = loadImage("elevator.png");
  imgmstOrg = loadImage("monsterOr.png");
  imgmstGrn = loadImage("mosterGr.png");
  imgmstBlu = loadImage("mosterBl.png");
  imgmstYlw = loadImage("mosterYe.png");
  imgflrA = loadImage("brick.png");
  back = loadImage("back.png");
  imgRubbish[0] = loadImage("coca.png");
  imgRubbish[1] = loadImage("bag.png");
  imgRubbish[2] = loadImage("beer.png");
  imgRubbish[3] = loadImage("paper.png");
}
void mouseClicked() {
  clickCounter ++;
}
void draw() {

  frank.keyPressed();
  if (tutorial == true) {
    updateSerial();
    printArray(sensorValues[2]);
    frank.leftRight();
    frank.upDown();
    frank.changefloor();
    switch(clickCounter) {
      //intro1
    case 0:
      background(0);
      textSize(60);
      fill(10, 255, 40);
      text("Bobby –––– The Trash Collector", width/2-400, height/2);
      fill(230, 65, 240);
      text("Bobby –––– The Trash Collector", width/2-405, height/2-5);
      textSize(20);
      fill(255);
      text("Click the Mouse to Continue", width/2 - 400, height-100);
      break;
    case 1:
      background(0);
      textSize(60);
      text("Three steps to learn the game", width/2-400, height/2);
      textSize(20);
      text("Click the Mouse to Continue", width/2 - 400, height-100);
      break;
    case 2:
      background(0);
      textSize(60);
      image(imgItf, 100, 100);
      imgItf.resize(5*1728/7, 3*1296/5);
      textSize(20);
      fill(255);
      text("Click the Mouse to Continue", width/2 - 400, height-100);
      break;
    case 3:
      xPos = 1300;
      yPos = 850;
      back();
      setImage();
      frank.robot();
      frank.floorPic();
      frank.elevatorTrack();
      frank.elevatorPic();
      frank.border();
      textSize(45);
      fill(231, 22, 3);
      text("Elevator Times: " + elevatorTimes, width/2- 700, height/2-230);
      textSize(20);
      text("in the real game, elevator times is limited", width/2- 700, height/2);
      text("You need to collect trash to get more elevator times", width/2- 700, height/2+30);
      textSize(20);
      fill(0);
      text("Click the Mouse to Continue", width/2 - 700, height-100);
      break;
    case 4:
      background(0);
      textSize(60);
      text("Step 2", width/2-100, 60);
      textSize(35);
      fill(255);
      text("Next step, pick up the trashes", width/2-500, height/2-55);
      fill(0, 255, 0);
      text("&&", width/2-450, height/2);
      fill(255);
      text("Throw them into the right trashcans", width/2-500, height/2+ 55);
      textSize(20);
      fill(255);
      text("Click the Mouse to Continue", width/2 - 400, height-100);
      break;

    case 5:
      xPos = 1300;
      yPos = 850;
      back();
      setImage();
      frank.robot();
      frank.elevatorTrack();
      frank.floorPic();
      frank.elevatorPic();
      frank.displayC();
      frank.throwRubbish();
      frank.rubbish();
      frank.border();
      textSize(45);
      fill(231, 22, 3);
      text("Elevator Times: " + elevatorTimes, width/2- 700, height/2-230);
      textSize(20);
      fill(0);
      text("Click the Mouse to Continue", width/2 - 700, height-100);
      break;
    case 6:
      background(0);
      textSize(60);
      text("Step 3", width/2-100, 60);
      fill(255);
      textSize(35);
      text("Now, monsters are on your way", width/2-600, height/2-55);
      fill(255, 0, 0);
      text("Don't be caught", width/2-600, height/2);
      fill(255);
      text("You can hide behind the elevator track or the rocks on each floors", width/2-600, height/2+ 55);
      textSize(20);
      //fill(255);
      //text("Click the Mouse to Continue", width/2 - 400, height-100);
      fill(249, 250, 20);
      textSize(50);
      text(" Press the ENTER. You have 100s", width/2-400, height/2+400);  
      break;
    }
  } else {


    //arduino
    updateSerial();
    printArray(sensorValues);

    m = millis() - start;

    frank.displayC();

    //set up the sence
    back();
    setImage();
    textShow();


    frank.robot();
    frank.elevatorTrack();
    frank.floorPic();
    frank.elevatorPic();
    frank.monsters();
    frank.rocks();
    frank.rubbish();
    frank.displayC();
    frank.keyPressed();
    frank.throwRubbish();
    frank.gameOver1();
    frank.leftRight();
    frank.upDown();
    frank.border();
    frank.changefloor();

    // the bad + end the game
    if (freeze == false) {

      //theBad
      ding.runningAround1();
      coco.runningAround2();
      ying.runningAround3();
      tina.runningAround4();

      timer();
      rank();
    } else {
      timer();
      frank.xPos = frank.xPos;
      carry = false;
      textAlign(CENTER);
      textSize(60);
      fill(233, 43, 123);
      textState1 = false;
      if (textState == true) {
        text(strings[0], width/2, height/2);
        
      }
      if (previousTime >= interval) {
        textState = false;
        //pushMatrix();
        //translate(0, 20);
        text(strings[1], width/2, height/2);
        //popMatrix();
      }
    }
  }
}

//************************************************Text**********************************************


void textShow() {
  textAlign(CENTER);
  textSize(50);
  fill(22, 22, 211);
  text("Trash: " + food, width/2- 500, height/2-280);
  fill(255, 116, 190);
  text("Trash: " + food, width/2- 500-2, height/2-280-2);
  textSize(45);
  fill(22, 22, 211);
  text("Elevator Times: " + elevatorTimes, width/2- 480, height/2-230);
  fill(255, 116, 190);
  text("Elevator Times: " + elevatorTimes, width/2- 480-2, height/2-230-2);
  if ( elevatorTimes == 0) {
    textSize(30);
    fill(231, 22, 3);
    text("Run out of Elevator Times", width/2-500, height/2);
    text("GET MORE TRASH !", width/2-500, height/2+50);
  }
  //showTime = interval - (millis() / 1000)%interval;
  if (textState1 == true) {
    fill(22, 22, 211);
    textSize(50);
    text("Time: " + (interval - (m / 1000)%interval), width/2-500, 115);
    fill(255, 116, 190);
    text("Time: " + (interval - (m / 1000)%interval), width/2-500-2, 115-2);
  }
  if (textState1 == false) {

    fill(39, 240, 60, 200);
    rect(width/2-300, height/2-50, 600, 200);
    //pushMatrix();
    //translate(0, 20);
    textSize(50);
    fill(22, 22, 211);
    text("Best Protector: " +hScore, width/2, height/2 + 100);
    text("Your Score: " + (food + elevatorTimes), width/2, height/2 + 50);
    fill(255, 116, 190);
    text("Best Protector: " +hScore, width/2-2, height/2 + 100-2);
    text("Your Score: " + (food + elevatorTimes), width/2-2, height/2 + 50-2);
    //popMatrix();
  }
}

//************************************************Timer*********************************************

int currentTime;
int previousTime = 0;
int pastTime = 0;
int showTime = interval;
int addTime =0;
int newTime =0;
int time = 0;

void timer() {
  //text("cu" + currentTime, width/2-300, height/2);
  //text("pr" + previousTime, width/2-300, height/2+50);
  //text("sh" + showTime, width/2-300, height/2+100);
  //text("pa" + pastTime, width/2-300, height/2+150);
  //text("ne" + newTime, width/2-300, height/2+200);
  currentTime = (m / 1000)%interval+1;
  if (currentTime - previousTime >= interval) {
    previousTime = currentTime;
  }

  textAlign(CENTER);
  textSize(50);
  fill(colors[0]);

  if (previousTime>= interval) {
    textAlign(CENTER);
    textSize(60);
    fill(233, 43, 123);
    text("Time Up", width/2, height/2);
    freeze = true;
  }

  // add the past time
}

//**********************************************Arduino*********************************************
void setupSerial() {
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[ 5 ], 9600);
  // WARNING!
  // You will definitely get an error here.
  // Change the PORT_INDEX to 0 and try running it again.
  // And then, check the list of the ports,
  // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" 
  // and replace PORT_INDEX above with the index number of the port.

  myPort.clear();
  // Throw out the first reading,
  // in case we started reading in the middle of a string from the sender.
  myString = myPort.readStringUntil( 10 );  // 10 = 'n'  Linefeed in ASCII
  myString = null;

  sensorValues = new int[NUM_OF_VALUES];
}



void updateSerial() {
  while (myPort.available() > 0) {
    myString = myPort.readStringUntil( 10 ); // 10 = 'n'  Linefeed in ASCII
    if (myString != null) {
      String[] serialInArray = split(trim(myString), ",");
      if (serialInArray.length == NUM_OF_VALUES) {
        for (int i=0; i<serialInArray.length; i++) {
          sensorValues[i] = int(serialInArray[i]);
        }
      }
    }
  }
}

//**********************************************back*********************************************
void back() {
  image(back, 0, 0);
}

//*********************************************cleaner*********************************************

class Cleaner {
  //member variables
  float  yPos = 0;
  float xPos = 1000;
  int[] Hcleaner = {6, 258, 510, 762};
  int i = 3;
  int rubbishFloor = int(random(3));
  int currentRubbish =0;
  int formerRubbish = 0;
  int noRubbish = 4;
  int floor1 = 850;
  int floor2 = 596;
  int floor3 = 344;
  int floor4 = 95;
  int climbSpeed = 5;
  int[] Hrubbish = {floor1, floor2, floor3, floor4};
  int r = 0;
  int distThrow = 110;
  int speedC = 8;
  int ladderWidth =100;
  int previousValue3 = 0;
  int previousValue4 = 0;
  int previousValue5 = 0;
  int previousValue6 = 0;


  float Xrubbish = 1200;

  boolean carry = false;
  boolean state = false;
  boolean showImg = false;







  //constructor
  Cleaner(int x, int y) {
    xPos = x;
    yPos = y;
  }

  //functionality

  //show the cleaner
  void displayC() {

    //pick the rubbish
    if (dist(xPos, yPos, Xrubbish, Hrubbish[r])<26 && carry == false) {
      background(255);
      r = (int) random(3);
      Xrubbish = random(455, 1340);
      formerRubbish = currentRubbish;
      currentRubbish = (int) random(3);
      food++;
      elevatorTimes ++;
      carry = true;
      showImg = true;
    }
  }

  //throw into the trashcan
  void throwRubbish() {
    if (colors[formerRubbish] == cla && dist(xPos, yPos, width/2+30, 22*height/25) < distThrow) {
      carry = false;
      showImg = false;
      pushMatrix();
      translate(125, height/2-200);
      noStroke();
      fill(255);
      ellipse(width/2, height/2, 30, 30);
      ellipse(width/2-30, height/2+25, 20, 20);
      ellipse(width/2+60, height/2-40, 100, 50);
      fill(255, 0, 0);
      text("Yummy", width/2+60, height/2-32);
      popMatrix();
    } else if (colors[formerRubbish] == clb && dist(xPos, yPos, 6*width/11+30, 15*height/25) < distThrow) {
      carry = false;
      showImg = false;
      pushMatrix();
      translate(220, 0);
      noStroke();
      fill(255);
      ellipse(width/2, height/2, 30, 30);
      ellipse(width/2-30, height/2+25, 20, 20);
      ellipse(width/2+60, height/2-40, 100, 50);
      fill(252, 219, 28);
      translate(-5, 0);
      text("Yummy", width/2+60, height/2-32);
      popMatrix();
    } else if (colors[formerRubbish] == clc && dist(xPos, yPos, 7*width/12+30, 8*height/25) < distThrow) {
      carry = false;
      showImg = false;
      pushMatrix();
      translate(250, -250);
      noStroke();
      fill(255);
      ellipse(width/2, height/2, 30, 30);
      ellipse(width/2-30, height/2+25, 20, 20);
      ellipse(width/2+60, height/2-40, 100, 50);
      fill(83, 252, 28);
      text("Yummy", width/2+60, height/2-32);
      popMatrix();
    } else if (colors[formerRubbish] == cld && dist(xPos, yPos, 8*width/13, height/25) < distThrow) {
      carry = false;
      showImg = false;
      noStroke();
      fill(255);
      ellipse(width/2, height/2, 30, 30);
    }
  }


  //game over
  void gameOver1() {
    if (xPos > width/2+100+270 || xPos < width/2+270) {
      if (dist(xPos, yPos, ding.badX, ding.badY) < 10 || dist(xPos, yPos, tina.badX, tina.badY) < 30 || dist(xPos, yPos, ying.badX, ying.badY) < 30 || dist(xPos, yPos, coco.badX, coco.badY) < 30 && freeze == false) {
        freeze = true;
        textState = true;
      }
    }
  }
  //moving image


  void robot() {


    if (yPos == 850 || yPos == 596 || yPos == 344 || yPos == 95 ) {
      image (imgrbt, xPos-50, yPos-80);
      imgrbt.resize(3*271/9, 3*356/9);
    } else {    
      image (imgrbtB, xPos-50, yPos-80);
      imgrbtB .resize(3*271/9, 3*356/9);
    }
  }


  void elevatorTrack() {
    noStroke();
    fill(0, 10, 255);
    if (xPos < width/2+100+270 && xPos > width/2+270) {
      fill(255, 0, 0);
    }
    rect(width/2+290, 0, 60, height-30);
    fill(255);
    rect(width/2+305, 0, 30, height-30);
    fill(23);
    fill(188, 42, 255);
    rect(width/2+310, 0, 20, height-30);

    fill(250, 58, 58);
    ellipse(width/2+321-13+12, height/2+250-10, 45, 45);
    fill(255);
    ellipse(width/2+321-13+12, height/2+250-10, 40, 40);
    textSize(25);
    fill(250, 58, 58);
    text("F1", width/2+321-13+12, height/2+250);

    fill(250, 241, 58);
    ellipse(width/2+321-13+12, height/2-10, 45, 45);
    fill(255);
    ellipse(width/2+321-13+12, height/2-10, 40, 40);
    textSize(25);
    fill(250, 241, 58);
    text("F2", width/2+321-13+12, height/2);

    fill(58, 241, 58);
    ellipse(width/2+321-13+12, height/2-250-10, 45, 45);
    fill(255);
    ellipse(width/2+321-13+12, height/2-250-10, 40, 40);
    textSize(25);
    fill(58, 241, 58);
    text("F3", width/2+321-13+12, height/2-250);

    fill(0, 10, 255);
    ellipse(width/2+321-13+12, height/2-400-10, 45, 45);
    fill(255);
    ellipse(width/2+321-13+12, height/2-400-10, 40, 40);
    textSize(25);
    fill(0, 10, 255);
    text("F4", width/2+321-13+12, height/2-400);
  }



  void floorPic() {
    image(imgflr1, 250, height/2-100);
    image(imgflr1, 170, height/2+150);
    image(imgflr1, 350, height/2-350);
    image(imgflr1, 440, height/2-600);
    imgflr1.resize(3*800/2, 9*240/8);
    for (int i = 0; i < 1200; i += 25) {
      image(imgflrA, width/2+i-455, height/2+168);
      imgflrA.resize(260/5, 220/5);
    }
    for (int i = 0; i < 1300; i += 25) {
      image(imgflrA, width/2+i-550, height/2+418);
      imgflrA.resize(260/5, 220/5);
    } 
    for (int i = 0; i < 1200; i += 25) {
      image(imgflrA, width/2+i-380, height/2-82);
      imgflrA.resize(260/5, 220/5);
    }
    for (int i = 0; i < 1200; i += 25) {
      image(imgflrA, width/2+i-280, 118);
      imgflrA.resize(260/5, 220/5);
    }
  }

  void elevatorPic() {
    pushMatrix();
    translate(-width/2+350, 0);
    image (imgele, width-195, Helevator[i]-110);
    imgele.resize(4*612/9, 4*612/9);
    popMatrix();
  }

  void rocks() {
    image(imgRK1, width/2-480, height/2+100);
    imgRK1. resize(1*837/4, 1*257/3);
    image(imgRK2, width/2-550, height/2+340);
    imgRK2. resize(1*837/4, 1*257/3);
    image(imgRK3, width/2-400, height/2-150);
    imgRK3. resize(1*837/4, 1*257/3);
    image(imgRK3, width-160, height/2+100);
    imgRK3. resize(1*837/4, 1*257/3);
    image(imgRK1, width-160, height/2+350);
    imgRK1. resize(1*837/4, 1*257/3);
    image(imgRK2, width-160, height/2-150);
    imgRK2. resize(1*837/4, 1*257/3);
  }


  void rubbish() {
    if (currentRubbish == 0) {    
      image (imgRubbish[0], Xrubbish-80, Hrubbish[r]-45+20);
      imgRubbish[0].resize(2*332/7, 2*152/7);
    }
    if (formerRubbish == 0  && showImg == true) {    
      image (imgRubbish[0], xPos-100, yPos-65+20);
      imgRubbish[0].resize(2*332/7, 2*152/7);
    }

    if (currentRubbish == 1) {    
      image (imgRubbish[1], Xrubbish-50, Hrubbish[r]-70+20);
      imgRubbish[1].resize(2*216/7, 2*233/7);
    }        
    if (formerRubbish == 1 && showImg == true) {    
      image (imgRubbish[1], xPos-80, yPos-70+20);
      imgRubbish[1].resize(2*216/7, 2*233/7);
    }

    if (currentRubbish == 2) {    
      image (imgRubbish[2], Xrubbish-75, Hrubbish[r]-80+20);
      imgRubbish[2].resize(1*800/11, 1*800/11);
    }
    if (formerRubbish == 2 && showImg == true) {    
      image (imgRubbish[2], xPos-80, yPos-80+20);
      imgRubbish[2].resize(1*800/11, 1*800/11);
    }

    if (currentRubbish == 3) {    
      image (imgRubbish[3], Xrubbish-40, Hrubbish[r]-50+20);
      imgRubbish[3].resize(3*267/7, 3*189/7);
    }
    if (formerRubbish == 3 && showImg == true) {    
      image (imgRubbish[3], xPos-80, yPos-70+20);
      imgRubbish[3].resize(3*267/7, 3*189/7);
    }
  }

  void monsters() {
    image(imgmstOrg, tina.badX-100, tina.badY-80);
    imgmstOrg.resize(305/2, 229/2);

    image(imgmstGrn, coco.badX-100, coco.badY-80);
    imgmstGrn.resize(319/2, 220/2);

    image(imgmstBlu, ying.badX-100, ying.badY-80);
    imgmstBlu.resize(306/2, 272/2);

    image(imgmstYlw, ding.badX-100, ding.badY-80);
    imgmstYlw.resize(328/2, 225/2);
  }

  void leftRight() {
    if (yPos == 596 || yPos == 850 || yPos == 344 || yPos == 95) {
      if (sensorValues[0] < 20) {
        xPos -= speedC;
      }
      if (sensorValues[1] < 20) {
        xPos += speedC;
      }
    }
  }

  void upDown () {

    //1 to 2
    if (xPos<width/2-400+ladderWidth && xPos>width/2-400 && yPos <= floor1 && yPos >= floor2) {
      if (sensorValues[2] < 20) {       
        yPos -= climbSpeed;
        if (yPos <= floor2 && yPos >= floor2 - 5) {
          yPos = floor2;
        }
      } else if (sensorValues[0] < 20 && sensorValues[1] < 20) {
        yPos += climbSpeed;
        if (yPos >= floor1 && yPos <= floor1 + 5) {
          yPos = floor1;
        }
      }
    }    
    if (xPos<width/2+630+ladderWidth && xPos>width/2+630 && yPos <= floor1 && yPos >= floor2) {
      if (sensorValues[2] < 20) {       
        yPos -= climbSpeed;
        if (yPos <= floor2 && yPos >= floor2 - 5) {
          yPos = floor2;
        }
      } else if (sensorValues[0] < 20 && sensorValues[1] < 20) {
        yPos += climbSpeed;
        if (yPos >= floor1 && yPos <= floor1 + 5) {
          yPos = floor1;
        }
      }
    }

    //2 to 3
    if (xPos<width/2+200 + ladderWidth && xPos>width/2+200 && yPos <= floor2 && yPos >= floor3 ) {
      if (sensorValues[2] < 20) {       
        yPos -= climbSpeed;
        if (yPos <= floor3 && yPos >= floor3 - 5) {
          yPos = floor3;
        }
      } else if (sensorValues[0] < 20 && sensorValues[1] < 20) {
        yPos += climbSpeed;
        if (yPos >= floor2 && yPos <= floor2 + 5) {
          yPos = floor2;
        }
      }
    }
    if (xPos<width/2-82 + ladderWidth && xPos>width/2-82 && yPos <= floor2 && yPos >= floor3 ) {
      if (sensorValues[2] < 20) {       
        yPos -= climbSpeed;
        if (yPos <= floor3 && yPos >= floor3 - 5) {
          yPos = floor3;
        }
      } else if (sensorValues[0] < 20 && sensorValues[1] < 20) {
        yPos += climbSpeed;
        if (yPos >= floor2 && yPos <= floor2 + 5) {
          yPos = floor2;
        }
      }
    }

    //3 to 4
    if (xPos<2*width/8+100 + ladderWidth && xPos>2*width/8+100 && yPos >= floor4 && yPos <= floor3) {
      if (sensorValues[2] < 20) {       
        yPos -= climbSpeed;
        if (yPos <= floor4 && yPos >= floor4 - 5) {
          yPos = floor4;
        }
      } else if (sensorValues[0] < 20 && sensorValues[1] < 20) {
        yPos += climbSpeed;
        if (yPos >= floor3 && yPos <= floor3 + 5) {
          yPos = floor3;
        }
      }
    }
    if (xPos<width/2+630 + ladderWidth && xPos>width/2+630 && yPos >= floor4 && yPos <= floor3) {
      if (sensorValues[2] < 20) {       
        yPos -= climbSpeed;
        if (yPos <= floor4 && yPos >= floor4 - 5) {
          yPos = floor4;
        }
      } else if (sensorValues[0] < 20 && sensorValues[1] < 20) {
        yPos += climbSpeed;
        if (yPos >= floor3 && yPos <= floor3 + 5) {
          yPos = floor3;
        }
      }
    }
  }

  void changefloor() {

    if (elevatorTimes >0) {
      if (sensorValues[3] ==1 && previousValue3 == 0) {
        i = 3;
        elevatorTimes--;
      } else if (sensorValues[4] ==1 && previousValue4 == 0) {
        i = 2;     
        elevatorTimes--;
      } else if (sensorValues[5] ==1 && previousValue5 == 0) {
        i = 1;
        elevatorTimes--;
      } else if (sensorValues[6] ==1 && previousValue6 == 0) {
        i = 0;
        elevatorTimes--;
      }
    }


    if (xPos < width/2+100+270 && xPos > width/2+270 && elevatorTimes > 0) {
      if (sensorValues[3] ==1 && previousValue3 == 0) {
        i = 3;
        yPos = floor1;
        xPos = width/2+340;
      } else if (sensorValues[4] ==1 && previousValue4 == 0) {
        i = 2;
        yPos = floor2;
        xPos = width/2+340;
      } else if (sensorValues[5] ==1 && previousValue5 == 0) {      
        i = 1;
        yPos = floor3;
        xPos = width/2+340;
      } else if (sensorValues[6] ==1 && previousValue6 == 0) {
        i = 0;
        yPos = floor4;
        xPos = width/2+340;
      }
    }
    previousValue3 = sensorValues[3];
    previousValue4 = sensorValues[4];
    previousValue5 = sensorValues[5];
    previousValue6 = sensorValues[6];
  }
  void border() {

    //border
    if (yPos == floor1 && xPos < width/8+20) {
      xPos = width/8+20;
    } else if (yPos == floor1 && xPos > width - 10) {
      xPos = width - 10;
    } else if (yPos == floor2 && xPos < width/8+110) {
      xPos = width/8+110;
    } else if (yPos == floor2 && xPos > width - 10) {
      xPos = width - 10;
    } else if (yPos == floor3 && xPos < width/8+200) {
      xPos = width/8+200;
    } else if (yPos == floor3 && xPos > width - 10) {
      xPos = width - 10;
    } else if (yPos == floor4 && xPos < width/8+300) {
      xPos = width/8+300;
    } else if (yPos == floor4 && xPos > width - 10) {
      xPos = width - 10;
    }
  }
  void keyPressed() {

    if (keyPressed) {
      if (yPos == 596 || yPos == 850 || yPos == 344 || yPos == 95)
        if (key == CODED) {
          if (keyCode == LEFT) {
            xPos -= speedC;
          } else if (key == CODED) {
            if (keyCode == RIGHT) {
              xPos += speedC;
            }
          }
        }

      //change the floors
      if (xPos < width/2+100+270 && xPos > width/2+270 && elevatorTimes > 0) {
        if (key =='1') {
          i = 3;
          yPos = floor1;
          xPos = width/2+340;
        } else if (key =='2') {
          i = 2;
          yPos = floor2;
          xPos = width/2+340;
        } else if (key =='3') {      
          i = 1;
          yPos = floor3;
          xPos = width/2+340;
        } else if (key =='4' ) {
          i = 0;
          yPos = floor4;
          xPos = width/2+340;
        }
      }

      //step ladders

      //1 to 2
      if (xPos<width/2-400+ladderWidth && xPos>width/2-400 && yPos <= floor1 && yPos >= floor2) {
        if (key == CODED) {
          if (keyCode == UP) {       
            yPos -= climbSpeed;
            if (yPos <= floor2 && yPos >= floor2 - 5) {
              yPos = floor2;
            }
          } else if (keyCode == DOWN) {
            yPos += climbSpeed;
            if (yPos >= floor1 && yPos <= floor1 + 5) {
              yPos = floor1;
            }
          }
        }
      }
      if (xPos<width/2+630+ladderWidth && xPos>width/2+630 && yPos <= floor1 && yPos >= floor2) {
        if (key == CODED) {
          if (keyCode == UP) {       
            yPos -= climbSpeed;
            if (yPos <= floor2 && yPos >= floor2 - 5) {
              yPos = floor2;
            }
          } else if (keyCode == DOWN) {
            yPos += climbSpeed;
            if (yPos >= floor1 && yPos <= floor1 + 5) {
              yPos = floor1;
            }
          }
        }
      }

      //2 to 3
      if (xPos<width/2+200 + ladderWidth && xPos>width/2+200 && yPos <= floor2 && yPos >= floor3 ) {
        if (key == CODED) {
          if (keyCode == UP) {       
            yPos -= climbSpeed;
            if (yPos <= floor3 && yPos >= floor3 - 5) {
              yPos = floor3;
            }
          } else if (keyCode == DOWN) {
            yPos += climbSpeed;
            if (yPos >= floor2 && yPos <= floor2 + 5) {
              yPos = floor2;
            }
          }
        }
      }
      if (xPos<width/2-82 + ladderWidth && xPos>width/2-82 && yPos <= floor2 && yPos >= floor3 ) {
        if (key == CODED) {
          if (keyCode == UP) {       
            yPos -= climbSpeed;
            if (yPos <= floor3 && yPos >= floor3 - 5) {
              yPos = floor3;
            }
          } else if (keyCode == DOWN) {
            yPos += climbSpeed;
            if (yPos >= floor2 && yPos <= floor2 + 5) {
              yPos = floor2;
            }
          }
        }
      }

      //3 to 4
      if (xPos<2*width/8+100 + ladderWidth && xPos>2*width/8+100 && yPos >= floor4 && yPos <= floor3) {
        if (key == CODED) {
          if (keyCode == UP) {       
            yPos -= climbSpeed;
            if (yPos <= floor4 && yPos >= floor4 - 5) {
              yPos = floor4;
            }
          } else if (keyCode == DOWN) {
            yPos += climbSpeed;
            if (yPos >= floor3 && yPos <= floor3 + 5) {
              yPos = floor3;
            }
          }
        }
      }
      if (xPos<width/2+630 + ladderWidth && xPos>width/2+630 && yPos >= floor4 && yPos <= floor3) {
        if (key == CODED) {
          if (keyCode == UP) {       
            yPos -= climbSpeed;
            if (yPos <= floor4 && yPos >= floor4 - 5) {
              yPos = floor4;
            }
          } else if (keyCode == DOWN) {
            yPos += climbSpeed;
            if (yPos >= floor3 && yPos <= floor3 + 5) {
              yPos = floor3;
            }
          }
        }
      }

      if (key ==ENTER) {
        freeze = false;
        textState1 = true;
        previousTime = 0;
        pastTime = currentTime;
        food = 0; 
        elevatorTimes = 3;
        xPos = 1300;
        yPos = 850;
        start = millis();
        tutorial = false;
      }
      if (key == SHIFT) {
        clickCounter = 0;
      }
    }
  }
}

//*********************************************elevator*********************************************
int[] Helevator = {6, 258, 510, 762};
int i = 3;


void keyPressed() {
  if (elevatorTimes >0) {
    if (key =='1') {
      i = 3;
      elevatorTimes--;
    } else if (key =='2') {
      i = 2;     
      elevatorTimes--;
    } else if (key =='3') {
      i = 1;
      elevatorTimes--;
    } else if (key =='4') {
      i = 0;
      elevatorTimes--;
    }
  }
}

//*********************************************image*********************************************

void setImage() {
  

  
  image(imgb, width/2+120, -80);
  imgb.resize(2*210/3, 2*310/3);

  image(imgr, width/2-45, 18*height/25+20 );
  imgr.resize(2*210/3, 2*310/3);

  image(imgg, width/2+80, 5*height/25-10 );
  imgg.resize(2*210/3, 2*310/3);

  image(imgy, width/2+30, 12*height/25-10 );
  imgy.resize(2*210/3, 2*310/3);

  image(imgl1, width/2-400, height/2+190);
  imgl1.resize(4*121/5, 4*564/9);
  image(imgl2, width/2+200, height/2-60);
  imgl2.resize(4*121/5, 4*564/9);
  image(imgl3, 2*width/8+100, height/2-300);
  imgl3.resize(4*121/5, 4*564/9);
  image(imgl1, width/2+630, height/2+190);
  imgl1.resize(4*121/5, 4*564/9);
  image(imgl2, width/2-82, height/2-60);
  imgl2.resize(4*121/5, 4*564/9);
  image(imgl3, width/2+630, height/2-300);
  imgl3.resize(4*121/5, 4*564/9);
}

//*********************************************rank*********************************************
//byte score;
//byte[] highestScore = {score};
int hScore = 29;




int highFood = 14;
int highele = 15;

void rank() {
  hScore = highFood + highele;
  
  if (food >= highFood) {
    highFood = food;
  }
  if(elevatorTimes >= highele) {
  highele = elevatorTimes;
  }
  
}

//*********************************************the bad*********************************************

class Bad {
  //member variables
  float badX, badY, badSize;
  int direction = 1;
  int leftSide = 200;
  int rightSide = 200;
  




  //constructor
  Bad(float x, float y, float s) {
    badX = x;
    badY = y;
    badSize = s;
  }
  //functionalities


  //running around
  void runningAround1() {
    if (badY == 598 && badX < width/8+100 + leftSide || badX > width - rightSide) {
      direction *= -1;
    }
    badX += 4.8*direction;
  }
  void runningAround2() {
    if (badY == 346 && badX < width/8+200 + leftSide || badX > width - rightSide) {
      direction *= -1;
    }
    badX += 4*direction;
  }
  void runningAround3() {
    if (badY == 94 && badX < width/8+300 + leftSide || badX > width - rightSide) {
      direction *= -1;
    }
    badX += 5.3*direction;
  }
  void runningAround4() {
    if (badY == 850 && badX < width/8+ 80 + leftSide || badX > width - rightSide) {
      direction *= -1;
    }
    badX += 5*direction;
  }
}