Ideation
After comparing our lists of 50 ideas, we narrowed our favorites down to a couple. We thought of doing a robot which would react to taps around it, but chose to adapt that concept to a dog which would respond differently according to how many times it was pet. We believed the dog would be more interesting both for us and for the children.
As we discussed what our dog would do, we decided it would have four different actions: sticking its tongue out, wiggling its tail, shaking its ears, and moving around. As a finishing touch, we thought it would be cool to add some fur after the dog was done in order to make it look and feel more realistic.
Design
We began our design process by sketching what the dog should like, then proceeded to actually draw the parts in SolidWorks. The hardest part of our project was designing the tongue mechanism, since we had to somehow convert a servo’s rotational motion to a translational movement for the tongue to stick out.

Here is a sketch of the tongue mechanism (unfortunately we did not take any pictures; after repeated petting from the children, it is now broken):

Circuitry
Our circuits were rather simple, consisting only of servos and photoreceptors. The original concept also had DC motors for movement, but unfortunately we could not drive them along with everything else as our power supply could not provide enough current.
The photoreceptors were responsible for detecting ‘pets’ both to the dog’s head and back, while the servos moved the ears, tongue, and tail accordingly.
Code
Our software was responsible for detecting the ‘petting’ and controlling the servos according to the dog’s state. Whenever idle, the dog slowly wiggled its tail, as if asking for attention. The program is a state machine that changes state when a pet is detected. There is also a watchdog timer of 30s which reverts the dog to an idle state when no petting is found, which would make children have to pet it often.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | #include <Servo.h> const int HEAD_SEN_PIN = A1; const int BODY_SEN_PIN = A0; const int EAR_L_SVO_PIN = 8; const int EAR_R_SVO_PIN = 7; const int TAIL_SVO_PIN = 4; const int TONGUE_SVO_PIN = 2; const int MOT_L_PIN1 = 5; const int MOT_L_PIN2 = 6; const int MOT_R_PIN1 = 9; const int MOT_R_PIN2 = 10; Servo ear_l_svo, ear_r_svo, tail_svo, tongue_svo; const int PET_THRES = 500; const int PET_TIME_THRES = 1000; const int RESET_TIME_THRES = 30000; int count = 0; int pwm = 0; float counter = 0; long start_t = millis(); long prev_t = start_t; long last_pet_t = start_t; bool idle = true ; bool is_being_petted = false ; void setup() { ear_l_svo.attach(EAR_L_SVO_PIN); ear_r_svo.attach(EAR_R_SVO_PIN); tail_svo.attach(TAIL_SVO_PIN); tongue_svo.attach(TONGUE_SVO_PIN); pinMode(HEAD_SEN_PIN, INPUT); pinMode(BODY_SEN_PIN, INPUT); pinMode(MOT_L_PIN1, OUTPUT); pinMode(MOT_L_PIN2, OUTPUT); pinMode(MOT_R_PIN1, OUTPUT); pinMode(MOT_R_PIN2, OUTPUT); digitalWrite(MOT_L_PIN1, LOW); digitalWrite(MOT_L_PIN2, LOW); digitalWrite(MOT_R_PIN1, LOW); digitalWrite(MOT_R_PIN2, LOW); tail_svo.write(140); Serial.begin(9600); } void loop() { long curr_t = millis(); int head_val = analogRead(HEAD_SEN_PIN); int body_val = analogRead(BODY_SEN_PIN); if ((head_val <= PET_THRES || body_val <= PET_THRES) && curr_t - last_pet_t > PET_TIME_THRES) { count++; reset_all(); if (!is_being_petted) { is_being_petted = true ; start_t = curr_t; } last_pet_t = curr_t; } if (curr_t - start_t >= RESET_TIME_THRES) { count = 0; pwm = 0; is_being_petted = false ; reset_all(); } int state = count % 9; Serial.print(state); Serial.print( "\t" ); Serial.println(head_val); if (idle) { move_tail_idle(curr_t); } switch (state) { case 1: move_ears(curr_t); idle = true ; break ; case 2: move_tail(curr_t); move_ears_during_tail(curr_t); idle = false ; break ; case 3: move_tongue(curr_t); idle = true ; break ; case 4: move_tail(curr_t); move_ears(curr_t); idle = false ; break ; case 5: move_tongue(curr_t); move_tail(curr_t); idle = false ; break ; case 6: move_ears(curr_t); move_tongue(curr_t); idle = true ; break ; case 7: move_tail(curr_t); move_tongue(curr_t); break ; case 8: move_ears(curr_t); move_tail(curr_t); move_tongue(curr_t); break ; default : idle = true ; break ; } prev_t = curr_t; } void move_ears( long curr_t) { int a = 20; ear_l_svo.write(a*sinf(( float )curr_t/150) + 90); ear_r_svo.write(a*sinf(( float )curr_t/150) + 90); } void move_ears_during_tail( long curr_t) { int a = 10 * sinf(( float )curr_t/500) + 5; ear_l_svo.write(a*sinf(( float )curr_t/150) + 90); ear_r_svo.write(a*sinf(( float )curr_t/150) + 90); } void move_tail( long curr_t) { tail_svo.write(20*sinf(( float )curr_t/100) + 90); } void move_tail_idle( long curr_t) { int a = 7 * sinf(( float )curr_t/500) + 15; tail_svo.write(a*sinf(( float )curr_t/100) + 140); } void move_tongue( long curr_t) { int val = 40*sinf(( float )curr_t/200) + 110; tongue_svo.write(val); } void move_forward( long curr_t) { if (pwm <= 150) { pwm += 5; } move_motors(pwm, pwm); } void move_backward( long curr_t) { if (pwm >= -150) { pwm -= 5; } move_motors(pwm, pwm); } void move_motors( int pwm_l, int pwm_r) { set_motor_pwm(pwm_r, MOT_L_PIN1, MOT_L_PIN2); set_motor_pwm(pwm_l, MOT_R_PIN1, MOT_R_PIN2); } void set_motor_pwm( int pwm, int IN1_PIN, int IN2_PIN) { if (pwm < 0) { analogWrite(IN1_PIN, -pwm); digitalWrite(IN2_PIN, LOW); } else { digitalWrite(IN1_PIN, LOW); analogWrite(IN2_PIN, pwm); } } void reset_motors() { set_motor_pwm(0, MOT_L_PIN1, MOT_L_PIN2); set_motor_pwm(0, MOT_R_PIN1, MOT_R_PIN2); } void reset_all() { reset_motors(); ear_l_svo.write(90); ear_r_svo.write(90); tongue_svo.write(90); } |
Results and Comments
While we were very pleased with our final version of our dog, the children were not as interested on it as we expected. One of the teachers, however, mentioned that the children liked the dog very much.
Active engagement with our dog lasted for an average of 30 to 45 seconds, with children being generally curious and exploratory, but after about a minute they became more neutral and bored. We acted as facilitators for most of them, while a few started petting the dog as soon as they saw it. During their curious moments, many children asked us what were the sensors since a “normal” dog did not have those.
After our visit, we believe our project had two main problems: it was too subtle and too restrict. First, many children did not understand the moving tail and ears as a symbol of the dog being excited, likely because their motion was slow, which made it seem like the dog was calm and quiet. Second, our interface was rather constrained, as the children had basically one task which was to pet the dog. Both of these factors contributed to our dog being a fun, yet short experience for them.
Even though at first the children were less interested on the dog as we expected, towards the end they came up with a new way to play with it. They took coins from Quincy and Patricia’s dinosaur to feed our dog, which seemed to make the children very engaged. With some sleights of hand, Caio made it seem like the dog was “pooping” the coins, which made them even more excited. Although we had not thought of playing with our dog like that, the children discovered this new, fun way of interacting with our project that made them very happy.
Leave a Reply
You must be logged in to post a comment.