Introduction: Da Duck(Auto-Following &Mood-Changing Robot)

Introduction

The original design intention of the da duck is to be a security robot that using the ultrasonic sensors to detect the objects in front and automatically follow the target until it stopped. With the aim to further develop the idea and add extra flexibility in movement, our team has made some technical enhancements by adding additional servo motor and OLED displays screen to achieve hand movement and change in facial expression, thus bringing extra vividness to machine duck. Story Background No one knows since when there are some rubber ducks start to appear at Daniels building. In the beginning, there only a few of them emerge on the campus, and no one minds where they came from. However, as there are more and more emerged on the campus and invaded the school, this has raised the awareness of a year three architecture student. The secret behind the mysterious duck starts to unfold as the student finds out the existence of the machine da duck....

Step 1: Introduction/ Motivation

Introduction

The original design intention of the da duck is to be a security robot that using the ultrasonic sensors to detect the objects in front and automatically follow the target until it stopped. With the aim to further develop the idea and add extra flexibility in movement, our team has made some technical enhancements by adding additional servo motor and OLED displays screen to achieve hand movement and change in facial expression, thus bringing extra vividness to machine duck.

Story Background

No one knows since when there are some rubber ducks start to appear at Daniels building. In the beginning, there only a few of them emerge on the campus, and no one minds where they came from. However, as there are more and more emerged on the campus and invaded the school, this has raised the awareness of a year three architecture student. The secret behind the mysterious duck starts to unfold as the student finds out the existence of the machine da duck....

Step 2: Video

Attached are the videos showing the function and story of Da Duck.

Step 3: Parts, Materials and Tools

COMPONENT

    - Uno Rev 3

    - L298N Motor Driver

    - Ultrasonic Sensor X3

    - Jumper Wire XN

    - Male- Female Wire

    - Resistor XN

    - Gear Motor X2

    - Rotation DC Motor X2

    - UNO Cable

    - 9V Battery X2

    - 6V Battery

    - Potentiometer

    - OLED Display X2

    - Breadboard

    - Wheel X2


    MATERIAL

    - 3mm Plywood X2

    - 3mm Plexiglass X2


    TOOLS

      - Spray Paint

      - Hot Glue Gun

      - Masking Tape

      - Screwdrivers

      - Screw

      - Drill

      EQUIPTMENT

        - Laser Cutter

        - Computer

        - Printer

        Step 4: Circuit

        Attached is the Fritzing circuit diagram showing how to connect each components.

        Step 5: Machine Making

        1. Use Rhino6 to design the 3D structure of the robot duck

        2. Layout each part of the duck and create laser cut file for the components

        3. The 3D model of the duck and the lasercut file can be downloaded as below

        4. Laser cut all the components on 1 sheet of 3mm plywood

        5. Put the components together with glue as shown in the image below

        6. Glue the 2 side of the duck after the arduino circuit is installed in the body

        7.Use duct tape to secure the unstable parts

        Step 6: Programming

        OLED Display

        #include

        #include

        Servo myservo; // create servo object to control a servo // twelve servo objects can be created on most boards

        int pos = 0; // variable to store the servo position int TrgPin = A3; int EcoPin = A2; int distance; float dist;

        #include #include #include #include

        #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 32 // OLED display height, in pixels

        // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

        #define NUMFLAKES 10 // Number of snowflakes in the animation example

        #define LOGO_HEIGHT 16 #define LOGO_WIDTH 16 static const unsigned char PROGMEM logo_bmp[] = { B00000000, B11000000, B00000001, B11000000, B00000001, B11000000, B00000011, B11100000, B11110011, B11100000, B11111110, B11111000, B01111110, B11111111, B00110011, B10011111, B00011111, B11111100, B00001101, B01110000, B00011011, B10100000, B00111111, B11100000, B00111111, B11110000, B01111100, B11110000, B01110000, B01110000, B00000000, B00110000 };

        void setup() { Serial.begin(9600); pinMode(TrgPin, OUTPUT); pinMode(EcoPin, INPUT); // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever }

        // Show initial display buffer contents on the screen -- // the library initializes this with an Adafruit splash screen. display.display(); delay(2000); // Pause for 2 seconds

        // Clear the buffer display.clearDisplay();

        // display.display() is NOT necessary after every single drawing command, // unless that's what you want...rather, you can batch up a bunch of // drawing ope\\\\\\\\\\\\\\\I;rations and then update the screen all at once by calling // display.display(). These examples demonstrate both approaches...

        }

        void loop() { digitalWrite(TrgPin, LOW); delayMicroseconds(5); digitalWrite(TrgPin, HIGH);

        delayMicroseconds(5); digitalWrite(TrgPin, LOW);

        dist = pulseIn(EcoPin, HIGH) / 58.00; distance= dist *0.034/2; if(dist > 20) {

        display.clearDisplay(); // Clear display buffer display.fillTriangle(130, 0, 0, display.height(),130,display.height(), SSD1306_WHITE); display.display(); // Update screen with each newly-drawn line } else if (distance <20){

        display.clearDisplay(); // Clear display buffer

        display.fillRect(0, 0, display.width(), display.height(), SSD1306_WHITE); display.display(); // Update screen with each newly-drawn line

        }

        }

        Wheels +Hands
        #include Servo myservo; int pos = 0;

        int Echo1 = A4; int Trig1 = A5; int Echo2 = A2; int Trig2 = A3; int Echo3 = A0; int Trig3 = A1;

        int in1 = 7; int in2 = 6; int in3 = 5; int in4 = 4; int ENA = 10; int ENB = 3; int ABS = 200; int Left_Distance = 0,Right_Distance = 0, Middle_Distance = 0; void _mStop() {

        digitalWrite(in1,LOW); digitalWrite(in2,LOW); digitalWrite(in3,LOW); digitalWrite(in4,LOW); // digitalWrite(ENA,LOW); //digitalWrite(ENB,LOW); Serial.println("ROBOT_STOP"); } void _mForward() {

        digitalWrite(in1,LOW); digitalWrite(in2,HIGH); digitalWrite(in3,LOW); digitalWrite(in4,HIGH); analogWrite(ENA,ABS); analogWrite(ENB,ABS); Serial.println("ROBOT_MOVING_FORWARD"); } void _mBack() {

        digitalWrite(in1,HIGH); digitalWrite(in2,LOW); digitalWrite(in3,HIGH); digitalWrite(in4,LOW); // analogWrite(ENA,ABS); // analogWrite(ENB,ABS); Serial.println("ROBOT_MOVING_BACKWARD"); }

        void _mleft() {

        digitalWrite(in1,LOW); digitalWrite(in2,HIGH); digitalWrite(in3,HIGH); digitalWrite(in4,LOW); // analogWrite(ENA,ABS); // analogWrite(ENB,ABS); Serial.println("ROBOT_MOVING_LEFT"); }

        void _mright() {

        digitalWrite(in1,HIGH); digitalWrite(in2,LOW); digitalWrite(in3,LOW); digitalWrite(in4,HIGH); // analogWrite(ENA,ABS); // analogWrite(ENB,ABS); Serial.println("ROBOT_MOVING_RIGHT"); } int Left_Distance_test() { digitalWrite(Trig1,LOW); delayMicroseconds(2); digitalWrite(Trig1,HIGH); delayMicroseconds(20); digitalWrite(Trig1,LOW); float Fdistance = pulseIn(Echo1,HIGH); delay(10);

        Fdistance = Fdistance/ 29/ 2; return (int)Fdistance; } int Middle_Distance_test() { digitalWrite(Trig2,LOW); delayMicroseconds(2); digitalWrite(Trig2,HIGH); delayMicroseconds(20); digitalWrite(Trig2,LOW); float Fdistance = pulseIn(Echo2,HIGH); delay(10); Fdistance = Fdistance/ 29/ 2; return (int)Fdistance; } int Right_Distance_test() { digitalWrite(Trig3,LOW); delayMicroseconds(2); digitalWrite(Trig3,HIGH); delayMicroseconds(20); digitalWrite(Trig3,LOW); float Fdistance = pulseIn(Echo3,HIGH); delay(10); Fdistance = Fdistance/ 29/ 2; return (int)Fdistance; } void setup() { // put your setup code here, to run once: Serial.begin (9600); pinMode(Echo1,INPUT); pinMode(Trig1,OUTPUT); pinMode(Echo2,INPUT); pinMode(Trig2,OUTPUT); pinMode(Echo3,INPUT); pinMode(Trig3,OUTPUT); pinMode(in1,OUTPUT); pinMode(in2,OUTPUT); pinMode(in3,OUTPUT); pinMode(in4,OUTPUT); pinMode(ENA,OUTPUT); pinMode(ENB,OUTPUT); myservo.attach(9); _mStop(); }

        void loop() { // put your main code here, to run repeatedly: Left_Distance = Left_Distance_test(); delay(10); Middle_Distance = Middle_Distance_test(); delay(10); Right_Distance = Right_Distance_test(); delay(10); Serial.println("Left_Distance\tMiddle_Distance\tRight_Distance\tStatus\n"); Serial.print(Left_Distance); Serial.print("cm\t\t"); Serial.print(Middle_Distance); Serial.print("cm\t\t"); Serial.print(Right_Distance); Serial.print("cm\t\t");

        if(Middle_Distance<=20) {_mStop(); delay(1000);} if(Middle_Distance<=50 && Middle_Distance>=20) { if(Right_Distance<=Middle_Distance) { if (Right_Distance<=20) {_mStop(); delay(1000); // _mBack(); // delay(100); } else{ _mright(); delay(100); for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees // in steps of 1 degree myservo.write(pos); // tell servo to go to position in variable 'pos' delay(2 ); // waits 15ms for the servo to reach the position }

        } } else if (Left_Distance<=Middle_Distance) { if (Left_Distance<=20) {_mStop(); delay(1000); //_mBack(); //delay(100); } else{ _mleft(); delay(100); for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees // in steps of 1 degree myservo.write(pos); // tell servo to go to position in variable 'pos' delay(2 ); // waits 15ms for the servo to reach the position }

        } } } else if (Right_Distance<=20) { _mStop(); delay(200); //_mleft(); //delay(50); } else if (Right_Distance>=20&& Right_Distance<=50) { _mright(); delay(100); for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees // in steps of 1 degree myservo.write(pos); // tell servo to go to position in variable 'pos' delay(2 ); // waits 15ms for the servo to reach the position }

        //_mleft(); //delay(50); } else if (Left_Distance>=20&& Left_Distance<=50) { _mleft(); delay(100); for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees // in steps of 1 degree myservo.write(pos); // tell servo to go to position in variable 'pos' delay(2 ); // waits 15ms for the servo to reach the position }

        //_mleft(); //delay(50); } else if (Left_Distance<=20) { _mStop(); delay(200); // _mright(); //delay(50); } else { _mForward(); } }

        Step 7: Results and Reflection

        Da duck is working successfully after been through several stages of modification. It is able to follow objects within 20cm and switch its expression and movement to different modes accordingly. During the design process, we had made several adjustments in bringing the machinery to a higher capability. The first one was using OLED screen to replace LCD screen since the OLED has more pixels in the display, which allow a vivid representation of duck's expression. The second adjustment was to separate the control of OLED and wheels. We separated three the circuit into three control boards and batteries that enable the currents to be more stable and efficient.

        For further enhancement of the project, we would add a remote switch to control the power of the duck; thus, we do not need to open the duck to switch on and off. In addition, we will pay more consideration of the materiality of the material, such as weight, friction, and thickness in order to avoid overweight and overheat on the machine body.

        This Useless Machine assignment is completed for the Physical Computing class at the Daniels Faculty. Our team had worked efficiently together throughout the whole design process. From the early exploration of the coding to the final assemblage of the machinery, each one of us plays an significant role in the team and bringing extra glamour to the final result.

        Step 8: Reference

        Step 9: Credit

        This Useless Machine assignment is completed for the Physical Computing class at the Daniels Faculty

        John H. Daniels Faculty of Architecture, Landscape, and Design University of Toronto

        Team:

        Haiyen Chen

        Junjie Shen

        Jiayu Huang

        Jianghong Dai