{"id":485,"date":"2019-08-25T15:05:50","date_gmt":"2019-08-25T15:05:50","guid":{"rendered":"https:\/\/www.protowrxs.com\/?page_id=485"},"modified":"2019-08-25T15:17:14","modified_gmt":"2019-08-25T15:17:14","slug":"tweety-bot","status":"publish","type":"page","link":"https:\/\/www.protowrxs.com\/index.php\/robotics\/tweety-bot\/","title":{"rendered":"Tweety Bot"},"content":{"rendered":"\n<p><strong>November 2015<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" width=\"768\" height=\"1024\" src=\"https:\/\/www.protowrxs.com\/wp-content\/uploads\/2019\/08\/BirdyBot-768x1024.jpg\" alt=\"\" class=\"wp-image-486\" srcset=\"https:\/\/www.protowrxs.com\/wp-content\/uploads\/2019\/08\/BirdyBot-768x1024.jpg 768w, https:\/\/www.protowrxs.com\/wp-content\/uploads\/2019\/08\/BirdyBot-225x300.jpg 225w, https:\/\/www.protowrxs.com\/wp-content\/uploads\/2019\/08\/BirdyBot.jpg 1024w\" sizes=\"(max-width: 768px) 85vw, 768px\" \/><\/figure>\n\n\n\n<p>\n<strong>Tweety Bot started out an a much more ambitious project. <\/strong>\n\n<\/p>\n\n\n\n<p>I\n would hope so I guess since all he actually does is sit around and \nTweet. \nAnyhow, the original goal was to build a birdy bot that could sit on \nyour arm or shoulder and use a gryo\/accel sensor to stay upright.\n<\/p>\n\n\n\n<p>\nI worked up some micro servos that would allow at least two different \naxis of movement and made up a duck looking head for the body.\nThat one was called JABB (Just Another Bird Bot). After messing with \nJABB for a while and realizing how ugly the body was going to be with \na full ProMini hanging onto it and liking the idea of a little bird like\n robot, I thought about simplifying things. VERY simple in fact.\n\n<\/p>\n\n\n\n<p>\nTweety&#8217;s brain is a very simple ATiny85 like I used in other bots like \nBuford, Buzz and PuP. This allowed me to get the whole CPU, \nUS sensor, and a light sensor to fit inside it&#8217;s little head. After \nmessing with JABB I thought it would be fun to have a simply \nlittle tweeting bird bot that was not mobile.\n<\/p>\n\n\n\n<p>\nIn TweetyBot, a single servo allows his head to pan left and right. A \nsmall light sensor is on top of his head to know how bright things are\nand a yellow LED was stuffed inside his beak to activate along with his \ntweeting sounds \nso his beak lights up when he makes sounds. Very simply but kind of \nentertaining as well.\n\n<\/p>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"TweetyBot - Boring little Tweeter\" width=\"840\" height=\"473\" src=\"https:\/\/www.youtube.com\/embed\/u5d5JMWze3U?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" width=\"640\" height=\"853\" src=\"https:\/\/www.protowrxs.com\/wp-content\/uploads\/2019\/08\/Birdhead1.jpg\" alt=\"\" class=\"wp-image-487\" srcset=\"https:\/\/www.protowrxs.com\/wp-content\/uploads\/2019\/08\/Birdhead1.jpg 640w, https:\/\/www.protowrxs.com\/wp-content\/uploads\/2019\/08\/Birdhead1-225x300.jpg 225w\" sizes=\"(max-width: 640px) 85vw, 640px\" \/><\/figure>\n\n\n\n<p>\nWhen TweetyBot first starts up he does a right to left pan looking for \nthe closet object. He then moves to that spot and just starts randomly\ntweeting and moving his head around. The light sensor is used to &#8220;go to \nsleep&#8221; when it&#8217;s dark or when his little cover is put over him.\nKind of like a real bird as well.\n\n\nThere \nare some &#8220;features&#8221;, which to most would be &#8220;bugs&#8221;, in the code where the head \ndoesn&#8217;t do a perfect pan on startup which actually adds a little more realisim \nto his actions.<\/p>\n\n\n\n<h2>Construction<\/h2>\n\n\n\n<p>\nConstruction is very straight forward. A hacked up 3d printable owl body\n was used from one of the many on Thingiverse.com. \nI didn&#8217;t want or need the head so I chopped it off of the digital model \nbefore printing and hollowed out the back to make room for the\nneck servo. The servo mounts in the hollow area and the head fits on the\n servo output.\n<\/p>\n\n\n\n<p>TweetyBot&#8217;s head is from Roxanna77, the owner of <strong>\n<a target=\"_blank\" href=\"http:\/\/www.CoolKidsRobots.com\" rel=\"noreferrer noopener\">http:\/\/www.CoolKidsRobots.com<\/a><\/strong>, design and it just looked like a perfect bird head to me.\nYou can find it here:&nbsp; \n<a target=\"_blank\" href=\"http:\/\/www.thingiverse.com\/thing:1054142\" rel=\"noreferrer noopener\">http:\/\/www.thingiverse.com\/thing:1054142\n<\/a>\n<\/p>\n\n\n\n<p>\nTweetyBot runs off 5v or so and can be powered by most any supply including a battery pack, solar \nchargeable pack, or just a USB port if you want.\n<\/p>\n\n\n\n<p>I wish I would have made him a little more heavy at the base or added some material as it is a little top heavy and unless\nyou have him glued to a base he moves around and eventually finds the edge of the desk. So I guess he <strong>IS<\/strong> a little mobile after all.\n\n<\/p>\n\n\n\n<h2>What Does He Do?<\/h2>\n\n\n\n<p>\nLike most of my creations he really doesn&#8217;t do much. Just randomly moves his head and tweets sometimes. \nI did have to dial down the randomness some as he does get annoying if he is making a racket too often.\n<\/p>\n\n\n\n<p>\nHe does get annoyed if you get in his face and starts moving his head back and forth to get away from you.\n\nApparently another &#8220;feature&#8221; is in there somewhere as he occasionlly doesn&#8217;t \nreally move his head but just buzzes there for a moment. Not sure what that is \nbut I like it too.<\/p>\n\n\n\n<p>\nHe also quiets down when it gets dark enough or when you put his \ngoodnight cloth (black cloth) over him as he thinks it dark and time to \nshut up.\n<br>\nOnce you take the cloth off he restarts his routine and spins his head around and starts tweeting again. \n\n<\/p>\n\n\n\n<h2>The Bad Stuff<\/h2>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" width=\"640\" height=\"853\" src=\"https:\/\/www.protowrxs.com\/wp-content\/uploads\/2019\/08\/BirdyBotBack.jpg\" alt=\"\" class=\"wp-image-488\" srcset=\"https:\/\/www.protowrxs.com\/wp-content\/uploads\/2019\/08\/BirdyBotBack.jpg 640w, https:\/\/www.protowrxs.com\/wp-content\/uploads\/2019\/08\/BirdyBotBack-225x300.jpg 225w\" sizes=\"(max-width: 640px) 85vw, 640px\" \/><\/figure>\n\n\n\n<p>The\n bad stuff mostly is my screw up in design. He really only needs three \nconnections to\/from his head. The + power, the ground and then the \ncontrol going back to the neck servo. I thought it&#8217;d be simple to just \nadd three pins sticking out his head and hook \nup to that feeding\nthe plus and ground both to the inside of the head and back to the \nservo. It does work but it also can fail easily as the head moves back\nand forth eventually breaking wires.\n\n<br><\/p>\n\n\n\n<h2>TweetyBots Future<\/h2>\n\n\n\n<p>TweetyBot will get his wires cleaned up and mounted to a better base. Maybe a little wooden platform or something. I&#8217;ve \nalready added\na USB cable to power him so he can sit somewhere and be powered off a computer or power pack and do his thing. \nHe seems like a reasonbly happy bird.<\/p>\n\n\n\n<h2>TweetyBot Resources<\/h2>\n\n\n\n<p>If you have some weird desire to build your own here are the modified models:<\/p>\n\n\n\n<p><a href=\"\/robotics\/TweetyBotBody.stl\">TweetyBotBody.stl<\/a> &#8211; Modified from an Owl  version from ThingiVerse with hollow back <\/p>\n\n\n\n<p><a href=\"\/robotics\/TweetyBotBeak.stl\">TweetyBotBeak.stl<\/a> &#8211; Print with zero infill to  have a hollow beak for LED to shine through<\/p>\n\n\n\n<h2>Example Code<\/h2>\n\n\n\n<p>\nI&#8217;m sure there are still some bugs and problems here but it&#8217;s working \nfor what I want it to do. I think there are some pieces not even used \nand the chirping parts are from some sample code online elsewhere.\n\n<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\n\n\/\/** TweetyBot - ATTiny85 Version of JABB\n\/\/** \n\/\/** v1.00 - 11\/1\/2015 - Stephen W Nolen \/ aka Protowrxs\n\n\/\/ ATTiny85 Pin Uses\n\/\/ -----\n\/\/ 1 Rest (5) |o | 8 Vcc\n\/\/ 2 Sonar(3) | | 7 (2) LDR light D2\/A1\n\/\/ 3 Speak(4) | | 6 (1) Output to 2N2222 driving pager vib motor\n\/\/ 4 Gnd | | 5 (0) Head Servo D0\n\/\/ -----\n\n#include &lt;SoftwareServo.h> \nSoftwareServo headServo; \n\nint speakerPin = A3;\nint headServopin = 0;\nint motorPin = 1; \/\/ Yes, looks the same as the ADC but that is apparently how it works\n\nint headPosition;\nint headCenter = 90;\nint headLeft = 130;\nint headRight = 50;\n\n\/\/ vars used to determine random moves of the head and direction\nint headOffset;\nint headDirection;\n\n\/\/ US sensor used for location and annoying him\nbyte TRIGGER_PIN = 3;\nbyte ECHO_PIN = 3;\nint uScm;\nint closePosition;\nint uScmClose;\n\nboolean activeMode; \/\/ if we are active or not. Used by light sensor to shutup in the dark or be more active in the light\n\nint lightPin = 1; \/\/ LDR Input pin on A1 (ATTiny85 pin 7)\nint lightLevel; \/\/ LDR Light level as read - gets quite at dark, active in light by changing the random high\/low values?\n\n\/\/ Timers used for various random activity\nlong generalTimer1;\nlong generalTimer2;\nlong generalTimer3;\nlong nextHeadMove;\n\n\/\/** H)ead, T)weet, L)owC)hirp and H)ighC)hirp random low\/highs to allow light controls\n\/\/** eventually we want to increment \/ decrements these based on the ambient light levels to be more active during bright light\nint Hlow = 5000;\nint Hhigh = 60000;\nint Tlow = 10000;\nint Thigh = 20000;\nint LClow = 10000;\nint LChigh = 20000;\nint HClow = 10000;\nint HChigh = 20000;\n\nlong myDelay;\n\nint currentPhase; \/\/ we step through phases for chirps - not sure why, might be best to randomize?\n\nvoid setup()\n{\n\/\/ This is from an AdaFruit example here: \n\/\/https:\/\/learn.adafruit.com\/trinket-gemma-servo-control\/code\n\/\/ Set up the interrupt that will refresh the servo for us automagically\nOCR0A = 0xAF; \/\/ any number is OK\nTIMSK |= _BV(OCIE0A); \/\/ Turn on the compare interrupt (below!)\n\n\/\/Setup speaker output\npinMode(speakerPin,OUTPUT);\npinMode(motorPin, OUTPUT);\n\n\/\/Psudeo randomness\nrandomSeed(analogRead(0));\n\n\/\/Setup this for ADC input but I think ADread does it already\npinMode(lightPin,INPUT); \/\/LDR light sensor\n\n\/\/This may not be needed either\npinMode(headServopin, OUTPUT); \/\/This should be done in servo code though\n\n\/\/** Attach the head servo\nheadServo.attach(headServopin);\n\/\/ headServo.setMaximumPulse(2200); \/\/ do not think we need this as it's working as is\n\nheadServo.write(headCenter);\n\n\/\/ Tweet, find closest objecgt and then chirp on start up\n\/\/ Also does similar when the light returns from being dark\ntweet(random(2,4),random(1,5)); \/\/ startup tune\nfindCloseObject();\nhighChirp(random(1,5), random(1,10));\n\npeck(250,200);\n\ngeneralTimer1 = millis();\ngeneralTimer2 = millis();\ngeneralTimer3 = millis();\n\nactiveMode = true;\n\n}\n\nvoid loop()\n{\nuScm = ReadSonar();\n\nif (uScm &lt; 10)\n{ \nheadServo.write(headLeft);\nheadPosition = headLeft;\ntweet(random(1,3),random(1,5)); \n}\n\nif (uScm &lt; 5) \n{\nheadServo.write(headRight);\nheadPosition = headRight;\nhighChirp(random(1,5), random(1,5)); \n}\n\nlightLevel = analogRead(lightPin);\n\nif (activeMode)\n{\n\/\/ if it gets dark then shut up after last chirp\nif (lightLevel &lt; 150)\n{ \nactiveMode = false;\nlowChirp(5,5);\n}\n\n\/\/ if really bright just keep on chirping\nif (lightLevel > 900)\n{\nhighChirp(5,5);\n}\n\n\/\/If random timer is up then jump to the next phase of randomness\nif (millis() > myDelay)\nswitch (currentPhase)\n{\ncase 0: \nhighChirp(random(2,6),random(1,6));\nheadPosition = random(headRight,headLeft);\nheadServo.write(headPosition);\nmyDelay = millis() + random(HClow,HChigh); \ncurrentPhase++;\nbreak;\ncase 1:\nlowChirp(random(2,6),random(1,10));\nheadPosition = random(headRight,headLeft);\nheadServo.write(headPosition);\nmyDelay = millis() + random(LClow,LChigh); \ncurrentPhase++;\nbreak;\ncase 2: \ntweet(random(2,4),random(1,5));\nheadPosition = random(headRight,headLeft);\nheadServo.write(headPosition);\nmyDelay = millis() + random(Tlow,Thigh); \ncurrentPhase++;\nbreak;\ncase 3: \nheadPosition = random(headRight,headLeft);\nheadServo.write(headPosition);\npeck(random(100,400),random(75,500));\nmyDelay = millis() + random(Tlow,Thigh); \ncurrentPhase = 0;\nbreak;\n} \/\/ End Case\n} \/\/ end mydelay timer\n\n\/\/ Else we are inactive so see if we have enough light to wake up or not\nelse\n{\nif (lightLevel > 150)\n{\nactiveMode = true;\ntweet(5,5);\nfindCloseObject();\ndelay(2000); \/\/just sit there a few and look at that thing\ntweet(5,5);\n}\n\n} \/\/ End Active if\/then\ndelay(10); \n\n} \/\/End main loop\n\nvoid buzzMotor(int chirpsNumber)\n{\n\nint i;\nint x;\n\nfor (int veces=0; veces&lt;=chirpsNumber;veces++)\n{\nfor (i=0; i&lt;200; i++)\n{\ndigitalWrite(motorPin, HIGH);\ndelayMicroseconds(i);\ndigitalWrite(motorPin, LOW);\ndelayMicroseconds(i);\n}\n\nfor (i=90; i>200; i--)\n{\ndigitalWrite(motorPin, HIGH);\ndelayMicroseconds(i);\ndigitalWrite(motorPin, LOW);\ndelayMicroseconds(i);\n}\n}\n}\n\n\n\/\/ Low chirp sound\nvoid lowChirp(int intensity, int chirpsNumber)\n{\nint i;\nint x;\n\nfor (int veces=0; veces&lt;=chirpsNumber;veces++)\n{\nfor (i=0; i&lt;200; i++)\n{\ndigitalWrite(speakerPin, HIGH);\ndelayMicroseconds(i);\ndigitalWrite(speakerPin, LOW);\ndelayMicroseconds(i);\n}\n\nfor (i=90; i>200; i--)\n{\ndigitalWrite(speakerPin, HIGH);\ndelayMicroseconds(i);\ndigitalWrite(speakerPin, LOW);\ndelayMicroseconds(i);\n}\n}\n}\n\n\/\/High chirp sound\nvoid highChirp(int intensity, int chirpsNumber)\n{\nint i;\nint x;\n\nfor (int veces=0; veces&lt;=chirpsNumber;veces++)\n{\nfor (i=100; i>0; i--)\n{\nfor (x=0; x&lt;intensity; x++)\n{\ndigitalWrite(speakerPin, HIGH);\ndelayMicroseconds(i);\ndigitalWrite(speakerPin, LOW);\ndelayMicroseconds(i);\n}\n}\n}\n}\n\n\/\/ Tweet sound\nvoid tweet(int intensity, int chirpsNumber)\n{\nint i;\nint x;\n\nfor (int veces=0; veces&lt;=chirpsNumber;veces++)\n{\nfor (i=80; i>0; i--)\n{\nfor (int x=0; x&lt;intensity; x++)\n{\ndigitalWrite(speakerPin, HIGH);\ndelayMicroseconds(i);\ndigitalWrite(speakerPin, LOW);\ndelayMicroseconds(i);\n}\n}\n}\n}\n\n\/\/ ** returns the ET in millis for timer variable passed\nlong getET(long mytimer){\nlong result;\nresult = (millis() - mytimer);\nreturn result;\n}\n\n\/\/ just move randomly a little bit - not used at the moment\nvoid RandomHeadMove()\n{\nheadOffset = random(0,2);\nheadDirection = random(1,10);\nif (headDirection &lt;= 5)\n{\nheadPosition = headPosition - headOffset;\n}\nelse\n{\nheadPosition = headPosition + headOffset;\n}\nheadServo.write(headPosition);\ngeneralTimer1 = millis();\nSoftwareServo::refresh();\n}\n\nlong ReadSonar()\n{\nlong duration, distance;\n\npinMode(TRIGGER_PIN, OUTPUT);\ndigitalWrite(TRIGGER_PIN, LOW);\ndelayMicroseconds(2);\ndigitalWrite(TRIGGER_PIN, HIGH);\ndelayMicroseconds(10);\ndigitalWrite(TRIGGER_PIN, LOW);\n\npinMode(ECHO_PIN, INPUT);\n\nduration = pulseIn(ECHO_PIN, HIGH);\ndistance = duration \/ 29 \/ 2;\nif (distance == 0)\n{\ndistance = 9999;\n}\nreturn distance;\n\n}\n\n\/\/ This is from an AdaFruit example here: \n\/\/https:\/\/learn.adafruit.com\/trinket-gemma-servo-control\/code\n\/\/ We'll take advantage of the built in millis() timer that goes off\n\/\/ to keep track of time, and refresh the servo every 20 milliseconds\n\/\/ The SIGNAL(TIMER0_COMPA_vect) function is the interrupt that will be\n\/\/ Called by the microcontroller every 2 milliseconds\nvolatile uint8_t counter = 0;\nSIGNAL(TIMER0_COMPA_vect) {\n\/\/ this gets called every 2 milliseconds\ncounter += 2;\n\/\/ every 20 milliseconds, refresh the servos!\nif (counter >= 20) {\ncounter = 0;\nSoftwareServo::refresh();\n}\n}\n\nvoid findCloseObject()\n{\nint pos;\nuScmClose = 9999; \/\/Start with way out there, otherwise it's zero and that doesn't work silly\nfor (pos = 0; pos &lt;= 180; pos += 1) \n{ \/\/ goes from 0 degrees to 180 degrees\nheadServo.write(pos);\ndelay(10); \/\/wait for slow servo stuff to move\nuScm = ReadSonar(); \nif (uScm &lt; uScmClose)\n{\nclosePosition = pos; \/\/Save the position for now\nuScmClose = uScm; \/\/Save the closest value to check\n}\n}\nheadServo.write(closePosition);\n}\n\nvoid peck(int peckSpeed, int peckTime)\n{\nanalogWrite(motorPin, peckSpeed);\ndelay(peckTime);\nanalogWrite(motorPin,0);\n}\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>November 2015 Tweety Bot started out an a much more ambitious project. I would hope so I guess since all he actually does is sit around and Tweet. Anyhow, the original goal was to build a birdy bot that could sit on your arm or shoulder and use a gryo\/accel sensor to stay upright. I &hellip; <a href=\"https:\/\/www.protowrxs.com\/index.php\/robotics\/tweety-bot\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Tweety Bot&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":19,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"spay_email":""},"categories":[],"tags":[],"_links":{"self":[{"href":"https:\/\/www.protowrxs.com\/index.php\/wp-json\/wp\/v2\/pages\/485"}],"collection":[{"href":"https:\/\/www.protowrxs.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.protowrxs.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.protowrxs.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.protowrxs.com\/index.php\/wp-json\/wp\/v2\/comments?post=485"}],"version-history":[{"count":3,"href":"https:\/\/www.protowrxs.com\/index.php\/wp-json\/wp\/v2\/pages\/485\/revisions"}],"predecessor-version":[{"id":493,"href":"https:\/\/www.protowrxs.com\/index.php\/wp-json\/wp\/v2\/pages\/485\/revisions\/493"}],"up":[{"embeddable":true,"href":"https:\/\/www.protowrxs.com\/index.php\/wp-json\/wp\/v2\/pages\/19"}],"wp:attachment":[{"href":"https:\/\/www.protowrxs.com\/index.php\/wp-json\/wp\/v2\/media?parent=485"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.protowrxs.com\/index.php\/wp-json\/wp\/v2\/categories?post=485"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.protowrxs.com\/index.php\/wp-json\/wp\/v2\/tags?post=485"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}