CINXE.COM
Hey Robot! Build Your Own AI Companion - Make:
<!DOCTYPE html> <html lang="en-US" xmlns:fb="http://ogp.me/ns/fb#" xmlns:fb="https://www.facebook.com/2008/fbml"> <!-- Hey makers! Happy to see you here, poke around and have some fun! If you're looking for any puzzle answers or social security numbers, you might need to dig a little deeper. ;) --> <head><meta charset="UTF-8"><script>if(navigator.userAgent.match(/MSIE|Internet Explorer/i)||navigator.userAgent.match(/Trident\/7\..*?rv:11/i)){var href=document.location.href;if(!href.match(/[?&]nowprocket/)){if(href.indexOf("?")==-1){if(href.indexOf("#")==-1){document.location.href=href+"?nowprocket=1"}else{document.location.href=href.replace("#","?nowprocket=1#")}}else{if(href.indexOf("#")==-1){document.location.href=href+"&nowprocket=1"}else{document.location.href=href.replace("#","&nowprocket=1#")}}}}</script><script>(()=>{class RocketLazyLoadScripts{constructor(){this.v="1.2.6",this.triggerEvents=["keydown","mousedown","mousemove","touchmove","touchstart","touchend","wheel"],this.userEventHandler=this.t.bind(this),this.touchStartHandler=this.i.bind(this),this.touchMoveHandler=this.o.bind(this),this.touchEndHandler=this.h.bind(this),this.clickHandler=this.u.bind(this),this.interceptedClicks=[],this.interceptedClickListeners=[],this.l(this),window.addEventListener("pageshow",(t=>{this.persisted=t.persisted,this.everythingLoaded&&this.m()})),this.CSPIssue=sessionStorage.getItem("rocketCSPIssue"),document.addEventListener("securitypolicyviolation",(t=>{this.CSPIssue||"script-src-elem"!==t.violatedDirective||"data"!==t.blockedURI||(this.CSPIssue=!0,sessionStorage.setItem("rocketCSPIssue",!0))})),document.addEventListener("DOMContentLoaded",(()=>{this.k()})),this.delayedScripts={normal:[],async:[],defer:[]},this.trash=[],this.allJQueries=[]}p(t){document.hidden?t.t():(this.triggerEvents.forEach((e=>window.addEventListener(e,t.userEventHandler,{passive:!0}))),window.addEventListener("touchstart",t.touchStartHandler,{passive:!0}),window.addEventListener("mousedown",t.touchStartHandler),document.addEventListener("visibilitychange",t.userEventHandler))}_(){this.triggerEvents.forEach((t=>window.removeEventListener(t,this.userEventHandler,{passive:!0}))),document.removeEventListener("visibilitychange",this.userEventHandler)}i(t){"HTML"!==t.target.tagName&&(window.addEventListener("touchend",this.touchEndHandler),window.addEventListener("mouseup",this.touchEndHandler),window.addEventListener("touchmove",this.touchMoveHandler,{passive:!0}),window.addEventListener("mousemove",this.touchMoveHandler),t.target.addEventListener("click",this.clickHandler),this.L(t.target,!0),this.S(t.target,"onclick","rocket-onclick"),this.C())}o(t){window.removeEventListener("touchend",this.touchEndHandler),window.removeEventListener("mouseup",this.touchEndHandler),window.removeEventListener("touchmove",this.touchMoveHandler,{passive:!0}),window.removeEventListener("mousemove",this.touchMoveHandler),t.target.removeEventListener("click",this.clickHandler),this.L(t.target,!1),this.S(t.target,"rocket-onclick","onclick"),this.M()}h(){window.removeEventListener("touchend",this.touchEndHandler),window.removeEventListener("mouseup",this.touchEndHandler),window.removeEventListener("touchmove",this.touchMoveHandler,{passive:!0}),window.removeEventListener("mousemove",this.touchMoveHandler)}u(t){t.target.removeEventListener("click",this.clickHandler),this.L(t.target,!1),this.S(t.target,"rocket-onclick","onclick"),this.interceptedClicks.push(t),t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation(),this.M()}O(){window.removeEventListener("touchstart",this.touchStartHandler,{passive:!0}),window.removeEventListener("mousedown",this.touchStartHandler),this.interceptedClicks.forEach((t=>{t.target.dispatchEvent(new MouseEvent("click",{view:t.view,bubbles:!0,cancelable:!0}))}))}l(t){EventTarget.prototype.addEventListenerWPRocketBase=EventTarget.prototype.addEventListener,EventTarget.prototype.addEventListener=function(e,i,o){"click"!==e||t.windowLoaded||i===t.clickHandler||t.interceptedClickListeners.push({target:this,func:i,options:o}),(this||window).addEventListenerWPRocketBase(e,i,o)}}L(t,e){this.interceptedClickListeners.forEach((i=>{i.target===t&&(e?t.removeEventListener("click",i.func,i.options):t.addEventListener("click",i.func,i.options))})),t.parentNode!==document.documentElement&&this.L(t.parentNode,e)}D(){return new Promise((t=>{this.P?this.M=t:t()}))}C(){this.P=!0}M(){this.P=!1}S(t,e,i){t.hasAttribute&&t.hasAttribute(e)&&(event.target.setAttribute(i,event.target.getAttribute(e)),event.target.removeAttribute(e))}t(){this._(this),"loading"===document.readyState?document.addEventListener("DOMContentLoaded",this.R.bind(this)):this.R()}k(){let t=[];document.querySelectorAll("script[type=rocketlazyloadscript][data-rocket-src]").forEach((e=>{let i=e.getAttribute("data-rocket-src");if(i&&!i.startsWith("data:")){0===i.indexOf("//")&&(i=location.protocol+i);try{const o=new URL(i).origin;o!==location.origin&&t.push({src:o,crossOrigin:e.crossOrigin||"module"===e.getAttribute("data-rocket-type")})}catch(t){}}})),t=[...new Map(t.map((t=>[JSON.stringify(t),t]))).values()],this.T(t,"preconnect")}async R(){this.lastBreath=Date.now(),this.j(this),this.F(this),this.I(),this.W(),this.q(),await this.A(this.delayedScripts.normal),await this.A(this.delayedScripts.defer),await this.A(this.delayedScripts.async);try{await this.U(),await this.H(this),await this.J()}catch(t){console.error(t)}window.dispatchEvent(new Event("rocket-allScriptsLoaded")),this.everythingLoaded=!0,this.D().then((()=>{this.O()})),this.N()}W(){document.querySelectorAll("script[type=rocketlazyloadscript]").forEach((t=>{t.hasAttribute("data-rocket-src")?t.hasAttribute("async")&&!1!==t.async?this.delayedScripts.async.push(t):t.hasAttribute("defer")&&!1!==t.defer||"module"===t.getAttribute("data-rocket-type")?this.delayedScripts.defer.push(t):this.delayedScripts.normal.push(t):this.delayedScripts.normal.push(t)}))}async B(t){if(await this.G(),!0!==t.noModule||!("noModule"in HTMLScriptElement.prototype))return new Promise((e=>{let i;function o(){(i||t).setAttribute("data-rocket-status","executed"),e()}try{if(navigator.userAgent.indexOf("Firefox/")>0||""===navigator.vendor||this.CSPIssue)i=document.createElement("script"),[...t.attributes].forEach((t=>{let e=t.nodeName;"type"!==e&&("data-rocket-type"===e&&(e="type"),"data-rocket-src"===e&&(e="src"),i.setAttribute(e,t.nodeValue))})),t.text&&(i.text=t.text),i.hasAttribute("src")?(i.addEventListener("load",o),i.addEventListener("error",(function(){i.setAttribute("data-rocket-status","failed-network"),e()})),setTimeout((()=>{i.isConnected||e()}),1)):(i.text=t.text,o()),t.parentNode.replaceChild(i,t);else{const i=t.getAttribute("data-rocket-type"),s=t.getAttribute("data-rocket-src");i?(t.type=i,t.removeAttribute("data-rocket-type")):t.removeAttribute("type"),t.addEventListener("load",o),t.addEventListener("error",(i=>{this.CSPIssue&&i.target.src.startsWith("data:")?(console.log("WPRocket: data-uri blocked by CSP -> fallback"),t.removeAttribute("src"),this.B(t).then(e)):(t.setAttribute("data-rocket-status","failed-network"),e())})),s?(t.removeAttribute("data-rocket-src"),t.src=s):t.src="data:text/javascript;base64,"+window.btoa(unescape(encodeURIComponent(t.text)))}}catch(i){t.setAttribute("data-rocket-status","failed-transform"),e()}}));t.setAttribute("data-rocket-status","skipped")}async A(t){const e=t.shift();return e&&e.isConnected?(await this.B(e),this.A(t)):Promise.resolve()}q(){this.T([...this.delayedScripts.normal,...this.delayedScripts.defer,...this.delayedScripts.async],"preload")}T(t,e){var i=document.createDocumentFragment();t.forEach((t=>{const o=t.getAttribute&&t.getAttribute("data-rocket-src")||t.src;if(o&&!o.startsWith("data:")){const s=document.createElement("link");s.href=o,s.rel=e,"preconnect"!==e&&(s.as="script"),t.getAttribute&&"module"===t.getAttribute("data-rocket-type")&&(s.crossOrigin=!0),t.crossOrigin&&(s.crossOrigin=t.crossOrigin),t.integrity&&(s.integrity=t.integrity),i.appendChild(s),this.trash.push(s)}})),document.head.appendChild(i)}j(t){let e={};function i(i,o){return e[o].eventsToRewrite.indexOf(i)>=0&&!t.everythingLoaded?"rocket-"+i:i}function o(t,o){!function(t){e[t]||(e[t]={originalFunctions:{add:t.addEventListener,remove:t.removeEventListener},eventsToRewrite:[]},t.addEventListener=function(){arguments[0]=i(arguments[0],t),e[t].originalFunctions.add.apply(t,arguments)},t.removeEventListener=function(){arguments[0]=i(arguments[0],t),e[t].originalFunctions.remove.apply(t,arguments)})}(t),e[t].eventsToRewrite.push(o)}function s(e,i){let o=e[i];e[i]=null,Object.defineProperty(e,i,{get:()=>o||function(){},set(s){t.everythingLoaded?o=s:e["rocket"+i]=o=s}})}o(document,"DOMContentLoaded"),o(window,"DOMContentLoaded"),o(window,"load"),o(window,"pageshow"),o(document,"readystatechange"),s(document,"onreadystatechange"),s(window,"onload"),s(window,"onpageshow");try{Object.defineProperty(document,"readyState",{get:()=>t.rocketReadyState,set(e){t.rocketReadyState=e},configurable:!0}),document.readyState="loading"}catch(t){console.log("WPRocket DJE readyState conflict, bypassing")}}F(t){let e;function i(e){return t.everythingLoaded?e:e.split(" ").map((t=>"load"===t||0===t.indexOf("load.")?"rocket-jquery-load":t)).join(" ")}function o(o){function s(t){const e=o.fn[t];o.fn[t]=o.fn.init.prototype[t]=function(){return this[0]===window&&("string"==typeof arguments[0]||arguments[0]instanceof String?arguments[0]=i(arguments[0]):"object"==typeof arguments[0]&&Object.keys(arguments[0]).forEach((t=>{const e=arguments[0][t];delete arguments[0][t],arguments[0][i(t)]=e}))),e.apply(this,arguments),this}}o&&o.fn&&!t.allJQueries.includes(o)&&(o.fn.ready=o.fn.init.prototype.ready=function(e){return t.domReadyFired?e.bind(document)(o):document.addEventListener("rocket-DOMContentLoaded",(()=>e.bind(document)(o))),o([])},s("on"),s("one"),t.allJQueries.push(o)),e=o}o(window.jQuery),Object.defineProperty(window,"jQuery",{get:()=>e,set(t){o(t)}})}async H(t){const e=document.querySelector("script[data-webpack]");e&&(await async function(){return new Promise((t=>{e.addEventListener("load",t),e.addEventListener("error",t)}))}(),await t.K(),await t.H(t))}async U(){this.domReadyFired=!0;try{document.readyState="interactive"}catch(t){}await this.G(),document.dispatchEvent(new Event("rocket-readystatechange")),await this.G(),document.rocketonreadystatechange&&document.rocketonreadystatechange(),await this.G(),document.dispatchEvent(new Event("rocket-DOMContentLoaded")),await this.G(),window.dispatchEvent(new Event("rocket-DOMContentLoaded"))}async J(){try{document.readyState="complete"}catch(t){}await this.G(),document.dispatchEvent(new Event("rocket-readystatechange")),await this.G(),document.rocketonreadystatechange&&document.rocketonreadystatechange(),await this.G(),window.dispatchEvent(new Event("rocket-load")),await this.G(),window.rocketonload&&window.rocketonload(),await this.G(),this.allJQueries.forEach((t=>t(window).trigger("rocket-jquery-load"))),await this.G();const t=new Event("rocket-pageshow");t.persisted=this.persisted,window.dispatchEvent(t),await this.G(),window.rocketonpageshow&&window.rocketonpageshow({persisted:this.persisted}),this.windowLoaded=!0}m(){document.onreadystatechange&&document.onreadystatechange(),window.onload&&window.onload(),window.onpageshow&&window.onpageshow({persisted:this.persisted})}I(){const t=new Map;document.write=document.writeln=function(e){const i=document.currentScript;i||console.error("WPRocket unable to document.write this: "+e);const o=document.createRange(),s=i.parentElement;let n=t.get(i);void 0===n&&(n=i.nextSibling,t.set(i,n));const c=document.createDocumentFragment();o.setStart(c,0),c.appendChild(o.createContextualFragment(e)),s.insertBefore(c,n)}}async G(){Date.now()-this.lastBreath>45&&(await this.K(),this.lastBreath=Date.now())}async K(){return document.hidden?new Promise((t=>setTimeout(t))):new Promise((t=>requestAnimationFrame(t)))}N(){this.trash.forEach((t=>t.remove()))}static run(){const t=new RocketLazyLoadScripts;t.p(t)}}RocketLazyLoadScripts.run()})();</script> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="view-transition" content="same-origin"> <title>Hey Robot! Build Your Own AI Companion - Make:</title> <link rel="preload" as="font" href="https://makezine.com/wp-content/themes/makezine/fonts/fa-brands-400.ttf" crossorigin> <link rel="preload" as="font" href="https://makezine.com/wp-content/themes/makezine/fonts/fa-solid-900.ttf" crossorigin> <link rel="preload" as="font" href="https://makezine.com/wp-content/themes/makezine/fonts/Roboto-Regular.ttf" crossorigin> <link rel="preload" as="font" href="https://makezine.com/wp-content/themes/makezine/fonts/Roboto-Bold.ttf" crossorigin> <link rel="preload" as="font" href="https://makezine.com/wp-content/themes/makezine/fonts/Roboto-Light.ttf" crossorigin><style id="rocket-critical-css">https://make.co/wp-content/universal-assets/v2/css/universal-frontload.min.css</style><link rel="preload" data-rocket-preload as="image" href="https://makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg" fetchpriority="high"> <link rel="preload" as="image" href="https://makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg" imagesrcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg?w=1920&ssl=1 1920w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg?resize=750%2C422&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg?resize=1024%2C576&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg?resize=450%2C253&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg?resize=768%2C432&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg?resize=1536%2C864&ssl=1 1536w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg?w=1280&ssl=1 1280w"> <meta name="twitter:widgets:csp" content="on"> <meta name="p:domain_verify" content="c4e1096cb904ca6df87a2bb867715669" > <meta name="norton-safeweb-site-verification" content="4g4w71jm7qt9e7ghe2dxdhiq0mnnkwom6ue80rdet53q3figx8ooxrffbgkkl9kzo3qi85l2j-txt-fh8w-p2z5769ht01z8s6sxq3-8r7cojmimgp00homsjjjv96ww" /> <meta property="fb:admins" content="1612614584" /> <link rel="profile" href="http://gmpg.org/xfn/11"> <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"> <link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32"> <link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16"> <link rel="manifest" href="/manifest.json"> <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5"> <meta name="theme-color" content="#ffffff"> <script type="text/javascript"> var templateUrl = 'https://makezine.com'; var logoutURL = 'https://makezine.com/wp-login.php?action=logout&redirect_to=https%3A%2F%2Fmakezine.com&_wpnonce=c2749da17e'; </script> <!-- Begin Chartbeat Code --> <script type="text/javascript">var _sf_startpt=(new Date()).getTime()</script> <!-- End Chartbeat Code --> <meta name='robots' content='index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1' /> <!-- This site is optimized with the Yoast SEO Premium plugin v23.0 (Yoast SEO v23.7) - https://yoast.com/wordpress/plugins/seo/ --> <title>Hey Robot! Build Your Own AI Companion - Make:</title> <meta name="description" content="Chat with and command your own embedded-AI companion bot using local LLMs." /> <link rel="canonical" href="https://makezine.com/projects/hey-robot-build-your-own-ai-companion/" /> <meta property="og:locale" content="en_US" /> <meta property="og:type" content="article" /> <meta property="og:title" content="Hey Robot! Build Your Own AI Companion" /> <meta property="og:description" content="Chat with and command your own embedded-AI companion bot using local LLMs." /> <meta property="og:url" content="https://makezine.com/projects/hey-robot-build-your-own-ai-companion/" /> <meta property="og:site_name" content="Make: DIY Projects and Ideas for Makers" /> <meta property="article:publisher" content="https://www.facebook.com/makemagazine" /> <meta property="article:modified_time" content="2024-11-22T19:13:08+00:00" /> <meta property="og:image" content="https://makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg" /> <meta property="og:image:width" content="1920" /> <meta property="og:image:height" content="1080" /> <meta property="og:image:type" content="image/jpeg" /> <meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:site" content="@make" /> <script type="application/ld+json" class="yoast-schema-graph">{"@context":"https://schema.org","@graph":[{"@type":"TechArticle","@id":"https://makezine.com/projects/hey-robot-build-your-own-ai-companion/#article","isPartOf":{"@id":"https://makezine.com/projects/hey-robot-build-your-own-ai-companion/"},"author":[{"@id":"https://makezine.com/#/schema/person/image/1f102313bb092b5bf549fddff67c3820"}],"headline":"Hey Robot! Build Your Own AI Companion","datePublished":"2024-10-28T23:56:49+00:00","dateModified":"2024-11-22T19:13:08+00:00","mainEntityOfPage":{"@id":"https://makezine.com/projects/hey-robot-build-your-own-ai-companion/"},"wordCount":2101,"publisher":{"@id":"https://makezine.com/#organization"},"image":{"@id":"https://makezine.com/projects/hey-robot-build-your-own-ai-companion/#primaryimage"},"thumbnailUrl":"https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg?fit=1920%2C1080&ssl=1","keywords":["AI","artificial intelligence","companion","cosplay","expressive robots","Large Language Model","LLM","make91","raspberry pi"],"articleSection":["Artificial Intelligence","Costumes, Cosplay, and Props","Raspberry Pi","Robotics","Technology"],"inLanguage":"en-US"},{"@type":["WebPage","ItemPage"],"@id":"https://makezine.com/projects/hey-robot-build-your-own-ai-companion/","url":"https://makezine.com/projects/hey-robot-build-your-own-ai-companion/","name":"Hey Robot! Build Your Own AI Companion - Make:","isPartOf":{"@id":"https://makezine.com/#website"},"primaryImageOfPage":{"@id":"https://makezine.com/projects/hey-robot-build-your-own-ai-companion/#primaryimage"},"image":{"@id":"https://makezine.com/projects/hey-robot-build-your-own-ai-companion/#primaryimage"},"thumbnailUrl":"https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg?fit=1920%2C1080&ssl=1","datePublished":"2024-10-28T23:56:49+00:00","dateModified":"2024-11-22T19:13:08+00:00","description":"Chat with and command your own embedded-AI companion bot using local LLMs.","breadcrumb":{"@id":"https://makezine.com/projects/hey-robot-build-your-own-ai-companion/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https://makezine.com/projects/hey-robot-build-your-own-ai-companion/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https://makezine.com/projects/hey-robot-build-your-own-ai-companion/#primaryimage","url":"https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg?fit=1920%2C1080&ssl=1","contentUrl":"https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg?fit=1920%2C1080&ssl=1","width":1920,"height":1080,"caption":"Courtesy of DigiKey"},{"@type":"BreadcrumbList","@id":"https://makezine.com/projects/hey-robot-build-your-own-ai-companion/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://makezine.com/"},{"@type":"ListItem","position":2,"name":"Hey Robot! Build Your Own AI Companion"}]},{"@type":"WebSite","@id":"https://makezine.com/#website","url":"https://makezine.com/","name":"Make: DIY Projects and Ideas for Makers","description":"","publisher":{"@id":"https://makezine.com/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://makezine.com/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https://makezine.com/#organization","name":"Make: Community","url":"https://makezine.com/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https://makezine.com/#/schema/logo/image/","url":"https://i0.wp.com/makezine.com/wp-content/uploads/2018/01/make-logo_@2x.png?fit=251%2C76&ssl=1","contentUrl":"https://i0.wp.com/makezine.com/wp-content/uploads/2018/01/make-logo_@2x.png?fit=251%2C76&ssl=1","width":251,"height":76,"caption":"Make: Community"},"image":{"@id":"https://makezine.com/#/schema/logo/image/"},"sameAs":["https://www.facebook.com/makemagazine","https://x.com/make","https://instagram.com/makemagazine/","https://www.pinterest.com/makemagazine/","https://www.youtube.com/user/makemagazine","https://discord.gg/mpBkj2hhJ4","https://mastodon.social/@makemagazine"]},{"@type":"Person","@id":"https://makezine.com/#/schema/person/image/1f102313bb092b5bf549fddff67c3820","name":"Shawn Hymel","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https://makezine.com/#/schema/person/image/83224ab7e34a382dacd0ac0b03945d2d","url":"https://i0.wp.com/makezine.com/wp-content/uploads/2022/05/headshot-1.png?fit=150%2C150&ssl=1","contentUrl":"https://i0.wp.com/makezine.com/wp-content/uploads/2022/05/headshot-1.png?fit=150%2C150&ssl=1","width":150,"height":150,"caption":"Shawn Hymel"},"description":"is an embedded engineer, maker, technical content creator, and instructor. He loves finding fun uses of technology at the intersection of code and electronics, as well as swing dancing in his free time (pandemic permitting).","url":"https://makezine.com/author/shawn-hymel/"}]}</script> <!-- / Yoast SEO Premium plugin. --> <link rel='dns-prefetch' href='//kit.fontawesome.com' /> <link rel='dns-prefetch' href='//make.co' /> <link rel='dns-prefetch' href='//stats.wp.com' /> <link rel='dns-prefetch' href='//fonts.googleapis.com' /> <link rel='dns-prefetch' href='//code.jquery.com' /> <link rel='dns-prefetch' href='//securepubads.g.doubleclick.net' /> <link rel='dns-prefetch' href='//c0.wp.com' /> <link rel='dns-prefetch' href='//v0.wordpress.com' /> <link rel='dns-prefetch' href='//i0.wp.com' /> <link rel="alternate" type="application/rss+xml" title="Make: DIY Projects and Ideas for Makers » Feed" href="https://makezine.com/feed/" /> <link data-minify="1" rel='preload' href='https://makezine.com/wp-content/cache/min/1/p/jetpack/13.9.1/modules/related-posts/related-posts.css?ver=1731557386' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link data-minify="1" rel='preload' href='https://makezine.com/wp-content/cache/min/1/c/6.6.1/wp-includes/css/dist/block-library/style.min.css?ver=1731557386' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <style id='co-authors-plus-coauthors-style-inline-css' type='text/css'> .wp-block-co-authors-plus-coauthors.is-layout-flow [class*=wp-block-co-authors-plus]{display:inline} </style> <style id='co-authors-plus-avatar-style-inline-css' type='text/css'> .wp-block-co-authors-plus-avatar :where(img){height:auto;max-width:100%;vertical-align:bottom}.wp-block-co-authors-plus-coauthors.is-layout-flow .wp-block-co-authors-plus-avatar :where(img){vertical-align:middle}.wp-block-co-authors-plus-avatar:is(.alignleft,.alignright){display:table}.wp-block-co-authors-plus-avatar.aligncenter{display:table;margin-inline:auto} </style> <style id='co-authors-plus-image-style-inline-css' type='text/css'> .wp-block-co-authors-plus-image{margin-bottom:0}.wp-block-co-authors-plus-image :where(img){height:auto;max-width:100%;vertical-align:bottom}.wp-block-co-authors-plus-coauthors.is-layout-flow .wp-block-co-authors-plus-image :where(img){vertical-align:middle}.wp-block-co-authors-plus-image:is(.alignfull,.alignwide) :where(img){width:100%}.wp-block-co-authors-plus-image:is(.alignleft,.alignright){display:table}.wp-block-co-authors-plus-image.aligncenter{display:table;margin-inline:auto} </style> <link data-minify="1" rel='preload' href='https://makezine.com/wp-content/cache/min/1/c/6.6.1/wp-includes/js/mediaelement/mediaelementplayer-legacy.min.css?ver=1731557386' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link data-minify="1" rel='preload' href='https://makezine.com/wp-content/cache/min/1/c/6.6.1/wp-includes/js/mediaelement/wp-mediaelement.min.css?ver=1731557386' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <style id='jetpack-sharing-buttons-style-inline-css' type='text/css'> .jetpack-sharing-buttons__services-list{display:flex;flex-direction:row;flex-wrap:wrap;gap:0;list-style-type:none;margin:5px;padding:0}.jetpack-sharing-buttons__services-list.has-small-icon-size{font-size:12px}.jetpack-sharing-buttons__services-list.has-normal-icon-size{font-size:16px}.jetpack-sharing-buttons__services-list.has-large-icon-size{font-size:24px}.jetpack-sharing-buttons__services-list.has-huge-icon-size{font-size:36px}@media print{.jetpack-sharing-buttons__services-list{display:none!important}}.editor-styles-wrapper .wp-block-jetpack-sharing-buttons{gap:0;padding-inline-start:0}ul.jetpack-sharing-buttons__services-list.has-background{padding:1.25em 2.375em} </style> <style id='classic-theme-styles-inline-css' type='text/css'> /*! This file is auto-generated */ .wp-block-button__link{color:#fff;background-color:#32373c;border-radius:9999px;box-shadow:none;text-decoration:none;padding:calc(.667em + 2px) calc(1.333em + 2px);font-size:1.125em}.wp-block-file__button{background:#32373c;color:#fff;text-decoration:none} </style> <style id='global-styles-inline-css' type='text/css'> :root{--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgba(255,105,0,1) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgba(255, 255, 255, 1), 6px 6px rgba(0, 0, 0, 1);--wp--preset--shadow--crisp: 6px 6px 0px rgba(0, 0, 0, 1);}:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;} :where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;} :where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;} :root :where(.wp-block-pullquote){font-size: 1.5em;line-height: 1.6;} </style> <link data-minify="1" rel='preload' href='https://makezine.com/wp-content/cache/min/1/wp-content/plugins/auth0/assets/css/main.css?ver=1731557386' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel='preload' href='https://makezine.com/wp-content/plugins/search-filter-pro/public/assets/css/search-filter.min.css?ver=2.5.19' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link data-minify="1" rel='preload' href='https://makezine.com/wp-content/cache/min/1/wp-content/themes/news-vibrant-pro/style.css?ver=1731557386' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link data-minify="1" rel='preload' href='https://makezine.com/wp-content/cache/min/1/wp-content/themes/news-vibrant-pro/assets/css/nv-responsive.css?ver=1731557386' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel='preload' href='https://makezine.com/wp-content/plugins/elementor/assets/css/frontend.min.css?ver=3.25.4' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel='preload' href='https://makezine.com/wp-content/plugins/elementor/assets/css/widget-image.min.css?ver=3.25.4' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel='preload' href='https://makezine.com/wp-content/plugins/elementor/assets/css/widget-heading.min.css?ver=3.25.4' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel='preload' href='https://makezine.com/wp-content/plugins/elementor-pro/assets/css/widget-countdown.min.css?ver=3.25.2' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel='preload' href='https://makezine.com/wp-content/plugins/elementor/assets/lib/animations/styles/fadeIn.min.css?ver=3.25.4' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link data-minify="1" rel='preload' href='https://makezine.com/wp-content/cache/min/1/wp-content/plugins/elementor/assets/lib/swiper/v8/css/swiper.min.css?ver=1731557386' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel='preload' href='https://makezine.com/wp-content/plugins/elementor/assets/css/conditionals/e-swiper.min.css?ver=3.25.4' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel='preload' href='https://makezine.com/wp-content/uploads/elementor/css/post-553223.css?ver=1730849814' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel='preload' href='https://makezine.com/wp-content/plugins/elementor-pro/assets/css/conditionals/popup.min.css?ver=3.25.2' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link data-minify="1" rel='preload' href='https://makezine.com/wp-content/cache/min/1/wp-content/plugins/make-elementor-widgets/includes/css/style.css?ver=1731557386' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link data-minify="1" rel='preload' href='https://makezine.com/wp-content/cache/min/1/ui/1.13.2/themes/base/jquery-ui.css?ver=1731557386' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel='preload' href='https://makezine.com/wp-content/uploads/elementor/css/post-568005.css?ver=1730849814' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link data-minify="1" rel='preload' href='https://makezine.com/wp-content/cache/min/1/wp-content/plugins/tablepress/css/build/default.css?ver=1731557386' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel='preload' href='https://makezine.com/wp-content/themes/makezine/css/bootstrap-noglyphicons.min.css?ver=6.6.1' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link data-minify="1" rel='preload' href='https://makezine.com/wp-content/cache/min/1/wp-content/themes/makezine/css/style.min.css?ver=1731557386' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link data-minify="1" rel='preload' href='https://makezine.com/wp-content/cache/min/1/wp-content/universal-assets/v2/css/universal-firstload.min.css?ver=1731557386' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link data-minify="1" rel='preload' href='https://makezine.com/wp-content/cache/min/1/wp-content/universal-assets/v2/css/universal.min.css?ver=1731557386' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel='preload' href='https://makezine.com/wp-content/themes/makezine/css/style-projects.min.css?ver=1.0.765' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel='preload' href='https://makezine.com/wp-content/plugins/youtube-embed-plus-pro/styles/ytprefs.min.css?ver=14.2.1.2' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <style id='__EPYT__style-inline-css' type='text/css'> .epyt-gallery-thumb { width: 33.333%; } </style> <link rel='preload' href='https://makezine.com/wp-content/plugins/youtube-embed-plus-pro/scripts/lity.min.css?ver=14.2.1.2' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel='preload' href='https://makezine.com/wp-content/plugins/youtube-embed-plus-pro/scripts/embdyn.min.css?ver=14.2.1.2' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <style id='rocket-lazyload-inline-css' type='text/css'> .rll-youtube-player{position:relative;padding-bottom:56.23%;height:0;overflow:hidden;max-width:100%;}.rll-youtube-player:focus-within{outline: 2px solid currentColor;outline-offset: 5px;}.rll-youtube-player iframe{position:absolute;top:0;left:0;width:100%;height:100%;z-index:100;background:0 0}.rll-youtube-player img{bottom:0;display:block;left:0;margin:auto;max-width:100%;width:100%;position:absolute;right:0;top:0;border:none;height:auto;-webkit-transition:.4s all;-moz-transition:.4s all;transition:.4s all}.rll-youtube-player img:hover{-webkit-filter:brightness(75%)}.rll-youtube-player .play{height:100%;width:100%;left:0;top:0;position:absolute;background:url(https://makezine.com/wp-content/plugins/wp-rocket/assets/img/youtube.png) no-repeat center;background-color: transparent !important;cursor:pointer;border:none;} </style> <link rel='preload' href='https://fonts.googleapis.com/css?family=Roboto%3A100%2C100italic%2C200%2C200italic%2C300%2C300italic%2C400%2C400italic%2C500%2C500italic%2C600%2C600italic%2C700%2C700italic%2C800%2C800italic%2C900%2C900italic%7CRoboto+Slab%3A100%2C100italic%2C200%2C200italic%2C300%2C300italic%2C400%2C400italic%2C500%2C500italic%2C600%2C600italic%2C700%2C700italic%2C800%2C800italic%2C900%2C900italic&display=auto&ver=6.6.1' data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" type='text/css' media='all' /> <link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin><script type="text/javascript" id="jetpack_related-posts-js-extra"> /* <![CDATA[ */ var related_posts_js_options = {"post_heading":"h4"}; /* ]]> */ </script> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/p/jetpack/13.9.1/_inc/build/related-posts/related-posts.min.js?ver=1731557386" id="jetpack_related-posts-js" data-rocket-defer defer></script> <script type="text/javascript" src="https://c0.wp.com/c/6.6.1/wp-includes/js/jquery/jquery.min.js" id="jquery-core-js"></script> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/wp-content/plugins/make-elementor-widgets/includes/js/scripts.js?ver=1731557386" id="make-elementor-script-js" data-rocket-defer defer></script> <script type="text/javascript" id="news-vibrant-custom-script-js-extra"> /* <![CDATA[ */ var WowOption = {"mode":""}; /* ]]> */ </script> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/wp-content/themes/news-vibrant-pro/assets/js/nv-custom-scripts.js?ver=1731557386" id="news-vibrant-custom-script-js"></script> <script type="text/javascript" src="https://makezine.com/wp-content/themes/makezine/js/min/project-scripts.min.js?ver=1.0.765" id="make-projects-script-js" data-rocket-defer defer></script> <script type="text/javascript" defer src="https://makezine.com/wp-content/plugins/youtube-embed-plus-pro/scripts/lity.min.js?ver=14.2.1.2" id="__dispload__-js"></script> <script type="text/javascript" id="__ytprefs__-js-extra"> /* <![CDATA[ */ var _EPYT_ = {"ajaxurl":"https:\/\/makezine.com\/wp-admin\/admin-ajax.php","security":"c95d45a850","gallery_scrolloffset":"20","eppathtoscripts":"https:\/\/makezine.com\/wp-content\/plugins\/youtube-embed-plus-pro\/scripts\/","eppath":"https:\/\/makezine.com\/wp-content\/plugins\/youtube-embed-plus-pro\/","epresponsiveselector":"[\"iframe.__youtube_prefs__\",\"iframe[src*='youtube.com']\",\"iframe[src*='youtube-nocookie.com']\",\"iframe[data-ep-src*='youtube.com']\",\"iframe[data-ep-src*='youtube-nocookie.com']\",\"iframe[data-ep-gallerysrc*='youtube.com']\"]","epdovol":"1","version":"14.2.1.2","evselector":"iframe.__youtube_prefs__[src], iframe[src*=\"youtube.com\/embed\/\"], iframe[src*=\"youtube-nocookie.com\/embed\/\"]","ajax_compat":"","maxres_facade":"eager","ytapi_load":"light","pause_others":"","stopMobileBuffer":"1","facade_mode":"1","not_live_on_channel":"","not_live_showtime":"180","vi_active":"","vi_js_posttypes":[]}; /* ]]> */ </script> <script type="text/javascript" defer src="https://makezine.com/wp-content/plugins/youtube-embed-plus-pro/scripts/ytprefs.min.js?ver=14.2.1.2" id="__ytprefs__-js"></script> <script type="text/javascript" defer src="https://makezine.com/wp-content/plugins/youtube-embed-plus-pro/scripts/embdyn.min.js?ver=14.2.1.2" id="__dynload__-js"></script> <link rel="alternate" title="oEmbed (JSON)" type="application/json+oembed" href="https://makezine.com/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fmakezine.com%2Fprojects%2Fhey-robot-build-your-own-ai-companion%2F" /> <link rel="alternate" title="oEmbed (XML)" type="text/xml+oembed" href="https://makezine.com/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fmakezine.com%2Fprojects%2Fhey-robot-build-your-own-ai-companion%2F&format=xml" /> <style>img#wpstats{display:none}</style> <meta name="generator" content="Elementor 3.25.4; features: e_font_icon_svg, additional_custom_breakpoints, e_optimized_control_loading; settings: css_print_method-external, google_font-enabled, font_display-auto"> <meta property="fb:app_id" content="805939602930860" /> <style> .e-con.e-parent:nth-of-type(n+4):not(.e-lazyloaded):not(.e-no-lazyload), .e-con.e-parent:nth-of-type(n+4):not(.e-lazyloaded):not(.e-no-lazyload) * { background-image: none !important; } @media screen and (max-height: 1024px) { .e-con.e-parent:nth-of-type(n+3):not(.e-lazyloaded):not(.e-no-lazyload), .e-con.e-parent:nth-of-type(n+3):not(.e-lazyloaded):not(.e-no-lazyload) * { background-image: none !important; } } @media screen and (max-height: 640px) { .e-con.e-parent:nth-of-type(n+2):not(.e-lazyloaded):not(.e-no-lazyload), .e-con.e-parent:nth-of-type(n+2):not(.e-lazyloaded):not(.e-no-lazyload) * { background-image: none !important; } } </style> <link rel="icon" href="https://i0.wp.com/makezine.com/wp-content/uploads/2018/06/favicon-32x32.png?fit=32%2C32&ssl=1" sizes="32x32" /> <link rel="icon" href="https://i0.wp.com/makezine.com/wp-content/uploads/2018/06/favicon-32x32.png?fit=32%2C32&ssl=1" sizes="192x192" /> <link rel="apple-touch-icon" href="https://i0.wp.com/makezine.com/wp-content/uploads/2018/06/favicon-32x32.png?fit=32%2C32&ssl=1" /> <meta name="msapplication-TileImage" content="https://i0.wp.com/makezine.com/wp-content/uploads/2018/06/favicon-32x32.png?fit=32%2C32&ssl=1" /> <noscript><style id="rocket-lazyload-nojs-css">.rll-youtube-player, [data-lazy-src]{display:none !important;}</style></noscript><script> /*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */ (function(w){"use strict";if(!w.loadCSS){w.loadCSS=function(){}} var rp=loadCSS.relpreload={};rp.support=(function(){var ret;try{ret=w.document.createElement("link").relList.supports("preload")}catch(e){ret=!1} return function(){return ret}})();rp.bindMediaToggle=function(link){var finalMedia=link.media||"all";function enableStylesheet(){link.media=finalMedia} if(link.addEventListener){link.addEventListener("load",enableStylesheet)}else if(link.attachEvent){link.attachEvent("onload",enableStylesheet)} setTimeout(function(){link.rel="stylesheet";link.media="only x"});setTimeout(enableStylesheet,3000)};rp.poly=function(){if(rp.support()){return} var links=w.document.getElementsByTagName("link");for(var i=0;i<links.length;i++){var link=links[i];if(link.rel==="preload"&&link.getAttribute("as")==="style"&&!link.getAttribute("data-loadcss")){link.setAttribute("data-loadcss",!0);rp.bindMediaToggle(link)}}};if(!rp.support()){rp.poly();var run=w.setInterval(rp.poly,500);if(w.addEventListener){w.addEventListener("load",function(){rp.poly();w.clearInterval(run)})}else if(w.attachEvent){w.attachEvent("onload",function(){rp.poly();w.clearInterval(run)})}} if(typeof exports!=="undefined"){exports.loadCSS=loadCSS} else{w.loadCSS=loadCSS}}(typeof global!=="undefined"?global:this)) </script> <script> !(function () { window.googletag = window.googletag || {}; window.vmpbjs = window.vmpbjs || {}; window.vpb = window.vpb || {}; vpb.cmd = vpb.cmd || []; vpb.st=Date.now(); vpb.fastLoad = true; googletag.cmd = googletag.cmd || []; vmpbjs.cmd = vmpbjs.cmd || []; var cmds = []; try{ cmds = googletag.cmd.slice(0); googletag.cmd.length = 0; }catch(e){} var ready = false; function exec(cb) { return cb.call(googletag); } var overriden = false; googletag.cmd.push(function () { overriden = true; googletag.cmd.unshift = function (cb) { if (ready) { return exec(cb); } cmds.unshift(cb); if (cb._startgpt) { ready = true; for (var k = 0; k < cmds.length; k++) { exec(cmds[k]); } } }; googletag.cmd.push = function (cb) { if (ready) { return exec(cb); } cmds.push(cb); }; }); if(!overriden){ googletag.cmd.push = function (cb) { cmds.push(cb); }; googletag.cmd.unshift = function (cb) { cmds.unshift(cb); if (cb._startgpt) { ready = true; if (googletag.apiReady) { cmds.forEach(function (cb) { googletag.cmd.push(cb); }); } else { googletag.cmd = cmds; } } }; } var dayMs = 36e5, cb = parseInt(Date.now() / dayMs), vpbSrc = '//player.hb.selectmedia.asia/prebidlink/' + cb + '/wrapper_hb_758321_19448.js', pbSrc = vpbSrc.replace('wrapper_hb', 'hb'), gptSrc = '//securepubads.g.doubleclick.net/tag/js/gpt.js', c = document.head || document.body || document.documentElement; function loadScript(src, cb) { var s = document.createElement('script'); s.src = src; s.defer=false; c.appendChild(s); s.onload = cb; s.onerror = function(){ var fn = function(){}; fn._startgpt = true; googletag.cmd.unshift(fn); }; return s; } loadScript(pbSrc); loadScript(gptSrc); loadScript(vpbSrc); })() </script> <script async src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"></script> <!-- Page Ad Vars --> <script type='text/javascript'> var ad_vars = {"page":"projectshey-robot-build-your-own-ai-co","PostID":"568464","custom_target_name":null,"custom_target_value":null,"tags":["ai","artificial-intelligence","companion","cosplay","expressive-robots","large-language-model","llm","make91","raspberry-pi"],"cat":["artificial-intelligence","cosplay-props","raspberry-pi","robotics","technology"],"zone":"/3829728/Makezine/Blog/ArtificialIntelligence","sponsor":null}; </script> <!-- Time-tracking for Custom Dimensions --> <time itemprop="startDate" datetime="2024-10-28T16:56:49-07:00" style="display: none;"></time> <!-- nativo script --> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/serve/load.js?ver=1731557386" async></script> <!-- end nativo script --> <!-- Google Tag Manager --> <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-PC5R77');</script> <!-- End Google Tag Manager --> <!-- Google Universal Analytics --> <!-- Primary Categories Dimension Query --> <script type="text/javascript"> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-51157-1', 'auto'); ga('require', 'GTM-TXW38JQ'); ga('require', 'displayfeatures'); ga('send', 'pageview', { 'page': location.pathname + location.search + location.hash }); var dimensionValue11 = document.getElementsByTagName("time")[0].getAttribute("datetime"); ga('set', 'dimension11', dimensionValue11); ga('set', 'dimension13', ""); ga('set', 'dimension14', ""); </script> <!-- Google tag (gtag.js) GA4 --> <script async src="https://www.googletagmanager.com/gtag/js?id=G-45H78982HP"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-45H78982HP'); </script> <script type="text/javascript"> dataLayer = []; </script> <!-- Pinterest Tag --> <script> !function(e){if(!window.pintrk){window.pintrk=function(){window.pintrk.queue.push( Array.prototype.slice.call(arguments))};var n=window.pintrk;n.queue=[],n.version="3.0";var t=document.createElement("script");t.async=!0,t.src=e;var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(t,r)}} ("https://s.pinimg.com/ct/core.js"); pintrk('load', '2617466540835'); pintrk('page'); </script> <noscript><img height="1" width="1" style="display:none;" alt="" src="https://ct.pinterest.com/v3/?tid=2617466540835&noscript=1" /></noscript> <script>pintrk('track', 'pagevisit', {event_id: 'projects/hey-robot-build-your-own-ai-companion'});</script> <noscript><img height="1" width="1" style="display:none;" alt="" src="https://ct.pinterest.com/v3/?tid=2617466540835&event=pagevisit&noscript=1" /> </noscript> <!-- end Pinterest Tag --> <!-- noscript Pinterest Tag --> <img height="1" width="1" style="display:none;" alt="" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201%201'%3E%3C/svg%3E" data-lazy-src="https://ct.pinterest.com/v3/?event=init&tid=2617466540835&noscript=1" /><noscript><img height="1" width="1" style="display:none;" alt="" src="https://ct.pinterest.com/v3/?event=init&tid=2617466540835&noscript=1" /></noscript> </noscript> <!-- end noscript Pinterest Tag --> <style id="rocket-lazyrender-inline-css">[data-wpr-lazyrender] {content-visibility: auto;}</style><meta name="generator" content="WP Rocket 3.17.2" data-wpr-features="wpr_delay_js wpr_defer_js wpr_minify_js wpr_preload_fonts wpr_async_css wpr_lazyload_images wpr_lazyload_iframes wpr_automatic_lazy_rendering wpr_oci wpr_minify_css wpr_desktop wpr_dns_prefetch wpr_preload_links" /></head> <body class="projects-template-default single single-projects postid-568464 makezine group-blog right-sidebar fullwidth_layout header-default nv-image-zoomin single-layout1 elementor-default elementor-kit-553223"> <!-- Google Tag Manager (noscript) --> <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-PC5R77" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> <!-- End Google Tag Manager (noscript) --> <div id="page" class="site"> <a class="skip-link screen-reader-text" href="#content">Skip to content</a> <div id="search-modal"> <form role="search" method="get" class="search-form" action="/"> <label class="sb-search-label" for="search">Search</label> <input class="sb-search-input search-field" placeholder="What are you searching for?" value="" name="s" id="search" title="" type="text"> <input class="sb-search-submit" name="submit" value="Search" type="submit"> </form> <div id="popular-links"> <h5>POPULAR SEARCHES:</h5> <ul class="pop-links-list"> <li><a href="/?s=arduino" target="_self">Arduino</a></li> <li><a href="/?s=cnc" target="_self">CNC</a></li> <li><a href="/?s=raspberry pi" target="_self">Raspberry Pi</a></li> <li><a href="/?s=wood working" target="_self">Woodworking</a></li> </ul> <ul class="pop-links-list"> <li><a href="/?s=3d printing" target="_self">3D Printing</a></li> <li><a href="/?s=iot" target="_self">IOT</a></li> <li><a href="/?s=robot" target="_self">Robot</a></li> <li><a href="/?s=maker faire" target="_self">Maker Faire</a></li> </ul> </div> </div> <header id="masthead" class="site-header-custom"> <!--<div id="pseudo-me"> This is Pseudome content <div id="pmCloseBtn"></div> </div>--> <div class="wrapper-fluid site-header-container flex default-header"> <a href="#" class="mobile-toggle-panel" aria-label="Mobile Navigation Toggle"><i aria-hidden="true" class="fas fa-bars"></i></a> <div id="site-logo" class="site-branding"> <h2 class="site-title"> <a href="https://makezine.com" rel="home" class="makezine-logo"> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20100%2040'%3E%3C/svg%3E" id="navLogo" class="nav-logo" alt="Make: Magazine Logo" width="100" height="40" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/make_logo.svg"><noscript><img loading="lazy" src="https://make.co/wp-content/universal-assets/v2/images/make_logo.svg" id="navLogo" class="nav-logo" alt="Make: Magazine Logo" width="100" height="40"></noscript> </a> <a href="https://make.co" rel="home" class="makeco-logo"> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20103%2030'%3E%3C/svg%3E" class="nav-logo" alt="Make: Community Logo" width="103" height="30" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/make_co_logo.webp"><noscript><img loading="lazy" src="https://make.co/wp-content/universal-assets/v2/images/make_co_logo.webp" class="nav-logo" alt="Make: Community Logo" width="103" height="30"></noscript> </a> <a href="https://makershed.com" rel="home" class="makershed-logo"> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20170%2040'%3E%3C/svg%3E" class="nav-logo" alt="Maker Shed Logo" width="170" height="40" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/maker-shed-logo.webp"><noscript><img loading="lazy" src="https://make.co/wp-content/universal-assets/v2/images/maker-shed-logo.webp" class="nav-logo" alt="Maker Shed Logo" width="170" height="40"></noscript> </a> <a href="https://makercamp.make.co" rel="home" class="makercamp-logo"> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20176%2040'%3E%3C/svg%3E" class="nav-logo" alt="Maker Camp Logo" width="176" height="40" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/makercamp-logo.webp"><noscript><img loading="lazy" src="https://make.co/wp-content/universal-assets/v2/images/makercamp-logo.webp" class="nav-logo" alt="Maker Camp Logo" width="176" height="40"></noscript> </a> <a href="https://makerspaces.make.co" rel="home" class="makerspaces-logo"> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20175%2040'%3E%3C/svg%3E" class="nav-logo" alt="Make: Makerspaces Logo" width="175" height="40" data-lazy-src="/wp-content/universal-assets/v2/images/makerspace_logo.webp"><noscript><img loading="lazy" src="/wp-content/universal-assets/v2/images/makerspace_logo.webp" class="nav-logo" alt="Make: Makerspaces Logo" width="175" height="40"></noscript> </a> <a href="https://learn.make.co" rel="home" class="makelearn-logo"> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2094%2040'%3E%3C/svg%3E" class="nav-logo" alt="Make: Learning Labs Logo" width="94" height="40" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/make-learning-labs-logo.webp"><noscript><img loading="lazy" src="https://make.co/wp-content/universal-assets/v2/images/make-learning-labs-logo.webp" class="nav-logo" alt="Make: Learning Labs Logo" width="94" height="40"></noscript> </a> <a href="https://makerfaire.com" rel="home" class="makerfaire-logo"> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20165%2030'%3E%3C/svg%3E" class="nav-logo" alt="Maker Faire Logo" width="165" height="30" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/Maker_Faire_Logo.svg"><noscript><img loading="lazy" src="https://make.co/wp-content/universal-assets/v2/images/Maker_Faire_Logo.svg" class="nav-logo" alt="Maker Faire Logo" width="165" height="30"></noscript> </a> </h2> </div> <nav id="site-navigation-custom" class="main-navigation" data-menu-space="120"> <div id="primary-navbar"> <h3 class="subnav-title"><a href="//make.co"></a></h3> <span class='mobile-subscribe-btn' style="display:none;"><a class='universal-btn-red' href='https://make.co/join/?utm_source=make&utm_medium=universalnav&utm_campaign=subscribe-mobile&utm_content=launch'>Subscribe</a></span> <ul id="primary-menu" class="primary-menu"> </ul> <div id="navbar-collapse" class="hasItems"> <a class="more-button" href="#" aria-label="More Navigation Options"><i aria-hidden="true" class="fas fa-ellipsis-h"></i></a> <ul id="navbar-extend" class="sub-menu"> <li class="menu-item top-menu menu-item-has-children"> <a href="#">Explore</a> <ul class="sub-menu sub-menu-parent"> <li class="menu-item bottom-menu menu-item-has-children"> <a href="https://makezine.com/?utm_source=make&utm_medium=universalnav&utm_campaign=makezine&utm_content=launch">Make: Magazine</a> <ul class="sub-menu sub-menu-full-height"> <li class="menu-item"> <a href="https://makezine.com/?utm_source=make&utm_medium=universalnav&utm_campaign=makezine&utm_content=launch">The premier publication of maker projects, skill-building tutorials, in-depth reviews, and inspirational stories, accessible by all ages and skill ranges.</a> </li> </ul> </li> <li class="menu-item bottom-menu menu-item-has-children"> <a href="https://makerfaire.com/?utm_source=make&utm_medium=universalnav&utm_campaign=makerfaire&utm_content=launch">Maker Faire</a> <ul class="sub-menu sub-menu-full-height"> <li class="menu-item"> <a href="https://makerfaire.com/?utm_source=make&utm_medium=universalnav&utm_campaign=makerfaire&utm_content=launch">A celebration of the Maker Movement, a family-friendly showcase of invention and creativity that gathers together tech enthusiasts, crafters, educators across the globe.</a> </li> </ul> </li> <li class="menu-item bottom-menu menu-item-has-children"> <a href="https://makershed.com/?utm_source=make&utm_medium=universalnav&utm_campaign=makershed&utm_content=launch">Maker Shed</a> <ul class="sub-menu sub-menu-full-height"> <li class="menu-item"> <a href="https://makershed.com/?utm_source=make&utm_medium=universalnav&utm_campaign=makershed&utm_content=launch">A smart collection of books, magazines, electronics kits, robots, microcontrollers, tools, supplies, and more curated by us, the people behind Make: and the Maker Faire.</a> </li> </ul> </li> <li class="menu-item bottom-menu menu-item-has-children"> <a href="https://www.makershed.com/collections/make-books-print/?utm_source=make&utm_medium=universalnav&utm_campaign=makebooks&utm_content=launch">Make: Books</a> <ul class="sub-menu sub-menu-full-height"> <li class="menu-item"> <a href="https://www.makershed.com/collections/make-books-print/?utm_source=make&utm_medium=universalnav&utm_campaign=makebooks&utm_content=launch">Maker-written books designed to inform and delight! Topics such as microcontrollers including Arduino and Raspberry Pi, Drones and 3D Printing, and more.</a> </li> </ul> </li> <!--<li class="menu-item bottom-menu menu-item-has-children"> <a href="https://makercamp.com/?utm_source=make&utm_medium=universalnav&utm_campaign=makercamp&utm_content=launch">Maker Camp</a> <ul class="sub-menu sub-menu-full-height"> <li class="menu-item"> <a href="https://makercamp.com/?utm_source=make&utm_medium=universalnav&utm_campaign=makercamp&utm_content=launch">A free program that lights children’s creative fires and allows them to explore projects in areas such as arts & crafts, science & engineering, design, and technology.</a> </li> </ul> </li>--> <!--<li class="menu-item bottom-menu menu-item-has-children"> <a href="https://make.co/join/?utm_source=make&utm_medium=universalnav&utm_campaign=makecommunity&utm_content=launch">Make: Membership</a> <ul class="sub-menu sub-menu-full-height"> <li class="menu-item"> <a href="https://make.co/join/?utm_source=make&utm_medium=universalnav&utm_campaign=makecommunity&utm_content=launch">Membership connects and supports the people and projects that shape our future and supports the learning initiatives for the next generation of makers.</a> </li> </ul> </li>--> </ul> </li> <li class="menu-item top-menu menu-item-has-children"> <a href="#">Learn</a> <ul class="sub-menu"> <li class="menu-item"> <a href="https://makezine.com/?utm_source=make&utm_medium=universalnav&utm_campaign=maker-updates&utm_content=launch"> <b>Maker Updates</b> <p>Read about the latest maker projects, skills, tool reviews and more.</p> </a> </li> <li class="menu-item"> <a href="https://www.makershed.com/collections/make-kit/?utm_source=make&utm_medium=universalnav&utm_campaign=books-kits&utm_content=launch"> <b>Books & Kits</b> <p>Get hands-on with kits, books, and more from the Maker Shed</p> </a> </li> <!--<li class="menu-item"> <a href="https://make.co/educationforum/?utm_source=make&utm_medium=universalnav&utm_campaign=learn&utm_content=launch"> <b>Professional Development for Educators</b> <p>Virtual Forum for Making in Education</p> </a> </li>--> <li class="menu-item"> <a href="https://makercamp.com/?utm_source=make&utm_medium=universalnav&utm_campaign=makercamp-project-library&utm_content=launch"> <b>Young Maker Projects</b> <p>Find projects for young makers</p> </a> </li> <li class="menu-item"> <a target="_none" href="https://www.youtube.com/channel/UChtY6O8Ahw2cz05PS2GhUbg?utm_source=make&utm_medium=universalnav&utm_campaign=watch-learn&utm_content=launch"> <b>Watch and Learn</b> <p>Skill builder, project tutorials, and more</p> </a> </li> </ul> </li> <li class="menu-item top-menu menu-item-has-children"> <a href="#">Experience</a> <ul class="sub-menu"> <li class="menu-item"> <a target="_none" href="https://www.mydigitalpublication.com/publication/?m=38377&l=1&utm_source=make&utm_medium=universalnav&utm_campaign=magazine-digital-portal&utm_content=launch"> <b>Magazine</b> <p>Subscribers' Digital Portal</p> </a> </li> <!--<li class="menu-item"> <a href="https://make.co/dashboard/?utm_source=make&utm_medium=universalnav&utm_campaign=dashboard&utm_content=launch"> <b>Membership</b> <p>Access Make: Community</p> </a> </li>--> <li class="menu-item"> <a href="https://makerfaire.com/globalmap/?utm_source=make&utm_medium=universalnav&utm_campaign=makerfaire-map&utm_content=launch"> <b>Maker Faire</b> <p>Find a faire.</p> </a> </li> <li class="menu-item"> <a href="https://makerspaces.make.co/?utm_source=make&utm_medium=universalnav&utm_campaign=makerspaces&utm_content=launch"> <b>Makerspaces</b> <p>Find a Makerspace near you</p> </a> </li> </ul> </li> <li class="menu-item top-menu menu-item-has-children"> <a href="https://make.co/?utm_source=make&utm_medium=universalnav&utm_campaign=participate&utm_content=launch">Participate</a> <ul class="sub-menu"> <li class="menu-item"> <a href="https://makerfaire.com/community/?utm_source=make&utm_medium=universalnav&utm_campaign=organize&utm_content=launch"> <b>Organize</b> <p>Start a local Maker Faire</p> </a> </li> <li class="menu-item"> <a href="https://make.co/submit-an-article-or-book-idea/?utm_source=make&utm_medium=universalnav&utm_campaign=write&utm_content=launch"> <b>Write</b> <p>Share a book or article proposal</p> </a> </li> <li class="menu-item"> <a href="https://make.co/make-cast/?utm_source=make&utm_medium=universalnav&utm_campaign=make-cast&utm_content=launch"> <b>Listen</b> <p>A podcast from Make: founder, Dale Dougherty</p> </a> </li> </ul> </li> <li class="menu-item top-menu menu-item-has-children"> <a href="https://www.makershed.com/?utm_source=make&utm_medium=universalnav&utm_campaign=share&utm_content=launch">Shop</a> <ul class="sub-menu"> <li class="menu-item"> <a href="https://www.makershed.com/?utm_source=make&utm_medium=universalnav&utm_campaign=books-kits-more&utm_content=launch"> <b>Kits, Books, & More</b> <p>Maker Shed, the official store of Make:</p> </a> </li> <li class="menu-item"> <a target="_none" href="https://subscribe.makezine.com/Make_subscribe?utm_source=make&utm_medium=universalnav&utm_campaign=magazine-subscribe&utm_content=launch"> <b>Make: Magazine</b> <p>Subscribe to the premier DIY magazine today</p> </a> </li> <!--<li class="menu-item"> <a href="https://make.co/join/?utm_source=make&utm_medium=universalnav&utm_campaign=make-membership&utm_content=launch"> <b>Make: Membership</b> <p>Community access, print, and digital Magazine, and more</p> </a> </li>--> </ul> </li> <li class="menu-item top-menu menu-item-has-children"> <a href="https://makerfaire.com/?utm_source=make&utm_medium=universalnav&utm_campaign=new&utm_content=launch" style="color:#ea002a;">New</a> <ul class="sub-menu"> <li class="menu-item"> <a href="https://makerspace.com/?utm_source=make&utm_medium=universalnav&utm_campaign=makerspaces&utm_content=launch"> <b>Makerspace Directory</b> <p>A comprehensive community driven directory</p> </a> </li> <li class="menu-item"> <a href="https://makerfaire.com/yearbook/?utm_source=make&utm_medium=universalnav&utm_campaign=yearbook&utm_content=launch"> <b>Maker Faire Yearbook</b> <p>A collection of projects from 2023's events</p> </a> </li> </ul> </li> </ul> </div> </div> <button class="close-mobile"><i class="fas fa-times"></i></button> </nav> <!-- start header aside --> <div id="header-aside" class="header-aside"> <div class="header-aside-inner"> <span id="make-login" class="login-section"> <a id="LoginBtn" href="/wp-login.php" title="Log In" target="_self">Log In</a> <div id="profile-view" class="dropdown v-select"> <a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <img class="avatar" alt="avatar" src="https://make.co/wp-content/universal-assets/v2/images/default-makey.png" width="50" height="50" /> <img class="avatar-banner" src="https://make.co/wp-content/universal-assets/v2/images/join-now-banner.png" alt="Join Now" width="90" height="90" /> </a> <div class="dropdown-menu profile-menu" aria-labelledby="dropdownMenuLink"> <div class="profile-info"> <img class="avatar" width="60" height="60" alt="avatar" src="https://make.co/wp-content/universal-assets/v2/images/default-makey.png" /> <div class="profile-text"> <div class="profile-name"></div> <div class="profile-email"></div> </div> </div> <div class="dropdown-links" id="profileLinks"> </div> <a id="LogoutBtn" href="/wp-login.php?action=logout" target="_self" title="Log Out">Log Out</a> </div> </div> </span> <span id="make-coin"></span> <span id="make-join" class="search-separator nav-separator"></span> <div class="search-button-wrapper"> <div class="subscribe-call-out"> <div class="subscribe-text"> <a target="_none" href="https://make.co/join/?utm_source=make&utm_medium=universalnav&utm_campaign=subscribe-call-out&utm_content=launch" target="_blank"> Subscribe </a> </div> <a target="_none" href="https://make.co/join/?utm_source=make&utm_medium=universalnav&utm_campaign=subscribe-call-out&utm_content=launch" target="_blank"> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2050%2070'%3E%3C/svg%3E" id="nav-subscribe-img" alt="Get Make: Magazine Issue 91" width="50" height="70.5" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/magazine-nav-subscribe-single.webp?v=91"><noscript><img src="https://make.co/wp-content/universal-assets/v2/images/magazine-nav-subscribe-single.webp?v=91" id="nav-subscribe-img" alt="Get Make: Magazine Issue 91" width="50" height="70.5"></noscript> </a> <div class="subscribe-pop-out"> <a target="_none" href="https://make.co/join/?utm_source=make&utm_medium=universalnav&utm_campaign=subscribe-popout&utm_content=launch" target="_blank"> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20296%20380'%3E%3C/svg%3E" alt="Subscribe Today to Make: Magazine" width="296" height="380.5" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/subscribe-today.webp?v=91"><noscript><img src="https://make.co/wp-content/universal-assets/v2/images/subscribe-today.webp?v=91" alt="Subscribe Today to Make: Magazine" width="296" height="380.5"></noscript> </a> </div> </div> <div id="sb-search" class="sb-search"></div> </div> </div> <!-- end header aside --> </div> </div> </header> <div id="universal-subnav" class="nav-level-2"> <ul id="menu-secondary_universal_menu" class="nav navbar-nav"><li itemscope="itemscope" itemtype="https://www.schema.org/SiteNavigationElement" id="menu-item-539713" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-539713"><a title="All Stories" href="/blog/"><span>All Stories</span></a></li> <li itemscope="itemscope" itemtype="https://www.schema.org/SiteNavigationElement" id="menu-item-539714" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-539714"><a title="Magazine Projects" href="/projects/"><span>Magazine Projects</span></a></li> <li itemscope="itemscope" itemtype="https://www.schema.org/SiteNavigationElement" id="menu-item-546920" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-546920"><a title="Board Guide" href="https://makezine.com/comparison/boards/"><span>Board Guide</span></a></li> <li itemscope="itemscope" itemtype="https://www.schema.org/SiteNavigationElement" id="menu-item-566162" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-566162"><a title="Make:cast" href="https://make.co/make-cast/"><span>Make:cast</span></a></li> <li itemscope="itemscope" itemtype="https://www.schema.org/SiteNavigationElement" id="menu-item-561923" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-561923"><a title="Magazine Issues" href="https://makezine.com/volumes"><span>Magazine Issues</span></a></li> <li itemscope="itemscope" itemtype="https://www.schema.org/SiteNavigationElement" id="menu-item-565008" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-565008"><a title="Maker Faire" target="_blank" href="https://www.makerfaire.com/"><span>Maker Faire</span></a></li> </ul> </div><!-- .nav-level-2 --> <script async id="tag_f45cd76a-c502-42b1-9d45-f3353d510ced" type="text/javascript" src="https://sm1.selectmedia.asia/cdn/tags/tag_f45cd76a-c502-42b1-9d45-f3353d510ced.js"></script> <div id="content" class="site-content"> <div class="cv-container"> <script type="text/javascript"> jQuery(document).ready(function() { jQuery('.project-content, .sidebar-wrapper').theiaStickySidebar({ additionalMarginTop: 130 }); }); // Smooth scroll on the step selector function gotoStep(target) { event.preventDefault(); jQuery('html, body').animate({ scrollTop: jQuery(target).offset().top - 130 }, 1000); } </script> <div class="project-container"> <article itemscope itemtype="https://schema.org/TechArticle"> <div class="projects-masthead masthead"> <h3><a href="//makezine.com/projects/" itemprop="publisher">Projects from Make: Magazine</a></h3> <h1 itemprop="name">Hey Robot! Build Your Own AI Companion</h1> </div> <div class="project-hero"> <img fetchpriority="high" class="hero-image skip-lazy" itemprop="image" src="https://makezine.com/wp-content/uploads/2024/10/dk-digit-02-Large.jpg" alt="Hey Robot! Build Your Own AI Companion" /> </div> <div class="project-innerwrapper"> <div class="project-content"> <div class="theiaStickySidebar"> <ul class="projects-meta"> <li>Time Required!: <span>1–3 Hours</span></li><li>Difficulty: <span itemprop="proficiencyLevel">Moderate</span></li><li>Price: <span>$51-$150</span></li> <meta itemprop="datePublished" content="October 28th, 2024" /> <li class="pull-right"> <a class="project-print-btn btn btn-xs btn-default print-page"> <i class="fa fa-print" aria-hidden="true"></i> Print this Project </a> </li> </ul> <header class="entry-header"> <div class="entry-meta"> <div class="author-wrapper"><img src="https://i0.wp.com/makezine.com/wp-content/uploads/2022/05/headshot-1.png?fit=150%2C150&resize=300%2C300&quality=70&strip=all#038;ssl=1&resize=198%2C198&strip=all" alt="Shawn Hymel" class="avatar avatar-198" width="198" height="198"><div class="author-name"><div class="bio-wrapper"><h3><a href="https://makezine.com/author/shawn-hymel">By Shawn Hymel</a></h3></div><div class="hover-info"><i class="fa fa-sort-asc sort-up fa-lg"></i><div class="author-wrapper"><div class="author-name"><h3><a href="https://makezine.com/author/shawn-hymel">Shawn Hymel</a></h3></div></div><p>is an embedded engineer, maker, technical content creator, and instructor. He loves finding fun uses of technology at the intersection of code and electronics, as well as swing dancing in his free time (pandemic permitting).</p> <a href="https://makezine.com/author/shawn-hymel">View more articles by Shawn Hymel <i class="fa fa-angle-right" aria-hidden="true"></i></a><div class="twitter-wrapper"></div></div></div></div><span class="posted-on"> <a href="https://makezine.com/projects/hey-robot-build-your-own-ai-companion/" rel="bookmark"><time class="entry-date published" datetime="2024-10-28T16:56:49-07:00">October 28th, 2024</time><time class="updated" datetime="2024-11-22T11:13:08-08:00">November 22nd, 2024</time></a></span><span class="byline"> </span> </div><!-- .entry-meta --> </header><!-- .entry-header --> <section class="article-body" itemprop="articleBody"> <div class="steps-shortcut-wrapper"><a href="#the-steps" class="steps-shortcut">Take me to the Steps</a></div><div class="wp-block-image"> <figure class="alignright size-full"><img data-recalc-dims="1" decoding="async" width="300" height="425" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20300%20425'%3E%3C/svg%3E" alt="" class="wp-image-568480" data-lazy-src="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/Make91_Cover-promo.jpg?resize=300%2C425&ssl=1"/><noscript><img data-recalc-dims="1" loading="lazy" decoding="async" width="300" height="425" src="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/Make91_Cover-promo.jpg?resize=300%2C425&ssl=1" alt="" class="wp-image-568480"/></noscript><figcaption class="wp-element-caption">This article appeared in Make: Vol. 91. <a href="https://subscribe.makezine.com/loading.do?omedasite=Make_subscribe" target="_blank" rel="noreferrer noopener">Subscribe</a> for more maker projects and articles!</figcaption></figure></div> <p>Chat and command your own embedded-AI companion bot using local LLMs.</p> <p>Imagine a fully autonomous robotic companion, like Baymax from Disney’s <em>Big Hero 6</em> — a friendly, huggable mechanical being that can walk, hold lifelike interactive conversations, and, when necessary, fight crime. Thanks to the advent of <em><strong>large language models (LLMs)</strong></em>, we’re closer to this science fiction dream becoming a reality — at least for lifelike conversations.</p> <p>In this guide I’ll introduce Digit, a companion bot that I helped create with Jorvon Moss (<a href="https://www.instagram.com/odd_jayy/" target="_blank" rel="noreferrer noopener">@Odd_jayy</a>). It uses a small LLM running locally on an embedded computer to hold conversations without the need for an internet connection.</p> <p>I’ll also walk you through the process of running a similar, lightweight LLM on a Raspberry Pi so you can begin making your own intelligent companion bot.</p> <h2 class="wp-block-heading" id="h-what-is-a-large-language-model-llm">What Is a Large Language Model (LLM)?</h2> <p>A large language model is a specific type of AI that can understand and generate natural, human-like text. The most popular example of an LLM right now is OpenAI’s ChatGPT, which is used to answer questions for the curious, automatically generate social media content, create code snippets and, to the chagrin of many English teachers, write term papers. LLMs are, in essence, the next evolution of chatbots.</p> <p>LLMs are based on the neural network architecture known as a <strong><em>transformer</em></strong>. Like all neural networks, transformers have a series of tunable <strong><em>weights </em></strong>for each node to help perform the mathematical calculations required to achieve their desired task. A weight in this case is just a number — think of it like a dial in a robot’s brain that can be turned to increase or decrease the importance of some piece of information. In addition to weights, transformers have other types of tunable dials, known as <strong><em>parameters</em></strong>, that help convert words and phrases into numbers as well as determine how much focus should be given to a particular piece of information.</p> <p>Instead of humans manually tuning these dials, imagine if the robot could tune them itself. That is the magic of <strong><em>machine learning</em></strong>: training algorithms adjust the values of the parameters (dials) automatically based on some goal set by humans. These training algorithms are just steps that a computer can easily follow to calculate the parameters. Humans set a goal and provide training data with correct answers to the training algorithms. The AI looks at the training data and guesses an answer. The training algorithm determines how far off the AI’s result is from the correct answer and updates the parameters in the AI to make it better next time. Rinse and repeat until the AI performs at some acceptable level.</p> <p>To give you an idea of complexity, a machine learning model that can read only the handwritten digits 0 through 9 with about 99% accuracy requires around 500,000 parameters. Comprehending and generating text are vastly more complicated. LLMs are trained on large quantities of human-supplied text, such as books, articles, and websites. The main goal of LLMs is to predict the next word in a sequence given a long string of previous words. As a result, the AI must understand the context and meaning of the text. To achieve this, LLMs are made up of massive amounts of parameters. ChatGPT-4, released in June 2023, is built from eight separate models, each containing around 220 billion parameters — about 1.7 <em>trillion </em>total.</p> <h2 class="wp-block-heading" id="h-why-a-local-llm">Why a Local LLM?</h2> <p>The billions of calculations needed for ChatGPT to hold a simple conversation require lots of large, internet-connected servers. If you tried to run ChatGPT on your laptop, assuming you even had enough memory to store the model, it would take hours or days to get a response! In most cases, relying on servers to do the heavy lifting is perfectly acceptable. After all, we use copious cloud services as consumers, such as video streaming, social media, file sharing, and email.</p> <p>However, running an LLM locally on a personal computer might be enticing for a few reasons:</p> <ul class="wp-block-list"> <li>Maybe you require access to your AI in areas with <strong>limited internet access</strong>, such as remote islands, tropical rainforests, underwater, underground caves, and most technology conferences!</li> <li>By running the LLM locally, you can also <strong>reduce network latency</strong> — the time it takes for packets to travel to and from servers. That being said, the extra computing power from the servers often makes up for the latency time for complex tasks like LLMs.</li> <li>Additionally, you can assume <strong>greater privacy and security</strong> for your data, which includes the prompts, responses, and model itself, as it does not need to leave the privacy of your computer or local network. If you’re an AI researcher developing the next great LLM, you can better protect your intellectual property by not exposing it to the outside.</li> <li>Personal computers and home network servers are often smaller than their corporate counterparts used to run commercial LLMs. While this might limit the size and complexity of your LLM, it often means <strong>reduced costs</strong> for such operations.</li> <li>Finally, most commercial LLMs contain a variety of guardrails and limits to prevent misuse. If you need an LLM to operate <strong>outside of commercial limits</strong> — say, to inject your own biases to help with a particular task, such as creative writing — then a local LLM might be your only option.</li> </ul> <p>Thanks to these benefits, local LLMs can be found in a variety of instances, including healthcare and financial systems to protect user data, industrial systems in remote locations, and some autonomous vehicles to interact with the driver without the need for an internet connection. While these commercial applications are compelling, we should focus on the real reason for running a local LLM: building an adorable companion bot that we can talk to.</p> <h2 class="wp-block-heading" id="h-introducing-digit">Introducing Digit</h2> <p>Jorvon Moss’s robotic designs have improved and evolved since his debut with Dexter (<a href="https://makezine.com/projects/a-monkey-companion-bot-named-dexter/" target="_blank" rel="noreferrer noopener"><em>Make:</em> Volume 73</a>), but his vision remains constant: create a fully functioning companion robot that can walk and talk. In fact, he often cites Baymax as his goal for functionality. In recent years, Moss has drawn upon insects and arachnids for design inspiration. “I personally love bugs,” he says. “I think they have the coolest design in nature.”</p> <p>Digit’s body consists of a white segmented exoskeleton, similar to a pill bug’s, that protects the sensitive electronics. The head holds an LED array that can express emotions through a single, animated “eye” along with a set of light-up antennae and controllable mandibles. It sits on top of a long neck that can be swept to either side thanks to a servomotor. Digit’s legs cannot move on their own but can be positioned manually.</p> <p>Like other companion bots, Digit can be perched on Moss’s shoulder to catch a ride. A series of magnets on Digit’s body and feet help keep it in place.</p> <div class="wp-block-image"> <figure class="aligncenter size-medium"><img data-recalc-dims="1" decoding="async" width="640" height="427" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20640%20427'%3E%3C/svg%3E" alt="" class="wp-image-568494" data-lazy-srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large.jpg?resize=750%2C500&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large.jpg?resize=1024%2C683&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large.jpg?resize=450%2C300&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large.jpg?resize=768%2C512&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large.jpg?resize=1536%2C1024&ssl=1 1536w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large.jpg?w=1620&ssl=1 1620w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large.jpg?w=1280&ssl=1 1280w" data-lazy-sizes="(max-width: 640px) 100vw, 640px" data-lazy-src="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large-750x500.jpg?resize=640%2C427&ssl=1" /><noscript><img data-recalc-dims="1" loading="lazy" decoding="async" width="640" height="427" src="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large-750x500.jpg?resize=640%2C427&ssl=1" alt="" class="wp-image-568494" srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large.jpg?resize=750%2C500&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large.jpg?resize=1024%2C683&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large.jpg?resize=450%2C300&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large.jpg?resize=768%2C512&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large.jpg?resize=1536%2C1024&ssl=1 1536w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large.jpg?w=1620&ssl=1 1620w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-01-cropped-Large.jpg?w=1280&ssl=1 1280w" sizes="(max-width: 640px) 100vw, 640px" /></noscript><figcaption class="wp-element-caption"><em>Courtesy of Jorvon Moss</em></figcaption></figure></div> <p>But Digit is unique from Moss’s other companion bots thanks to its advanced brain — an LLM running locally on an Nvidia Jetson Orin Nano embedded computer. Digit is capable of understanding human speech (English for now), generating a text response, and speaking that response aloud — without the need for an internet connection. To help maintain Digit’s relatively small size and weight, the embedded Jetson Orin Nano was mounted on a wooden slab along with an LCD for startup and debugging. Moss totes both the Orin Nano and the appropriate battery in a backpack. You could design your own companion bot differently to house the Orin Nano inside.</p> <div class="wp-block-image"> <figure class="aligncenter size-medium"><img data-recalc-dims="1" decoding="async" width="640" height="360" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20640%20360'%3E%3C/svg%3E" alt="" class="wp-image-568485" data-lazy-srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large.jpg?resize=750%2C422&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large.jpg?resize=1024%2C576&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large.jpg?resize=450%2C253&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large.jpg?resize=768%2C432&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large.jpg?resize=1536%2C864&ssl=1 1536w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large.jpg?w=1920&ssl=1 1920w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large.jpg?w=1280&ssl=1 1280w" data-lazy-sizes="(max-width: 640px) 100vw, 640px" data-lazy-src="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large-750x422.jpg?resize=640%2C360&ssl=1" /><noscript><img data-recalc-dims="1" loading="lazy" decoding="async" width="640" height="360" src="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large-750x422.jpg?resize=640%2C360&ssl=1" alt="" class="wp-image-568485" srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large.jpg?resize=750%2C422&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large.jpg?resize=1024%2C576&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large.jpg?resize=450%2C253&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large.jpg?resize=768%2C432&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large.jpg?resize=1536%2C864&ssl=1 1536w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large.jpg?w=1920&ssl=1 1920w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/dk-digit-01-Large.jpg?w=1280&ssl=1 1280w" sizes="(max-width: 640px) 100vw, 640px" /></noscript><figcaption class="wp-element-caption">Courtesy of DigiKey</figcaption></figure></div> <h2 class="wp-block-heading" id="h-how-digit-s-brain-works">How Digit’s Brain Works</h2> <p>I helped Moss design and program the software system to act as Digit’s AI brain. This system is comprised of three main components: a service running the LLM, a service running the text-to-speech system, and a client program that interacts with these two services.</p> <div class="wp-block-image"> <figure class="aligncenter size-medium"><img data-recalc-dims="1" decoding="async" width="640" height="360" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20640%20360'%3E%3C/svg%3E" alt="" class="wp-image-568486" data-lazy-srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large.png?resize=750%2C422&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large.png?resize=1024%2C576&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large.png?resize=450%2C253&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large.png?resize=768%2C432&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large.png?resize=1536%2C864&ssl=1 1536w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large.png?w=1920&ssl=1 1920w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large.png?w=1280&ssl=1 1280w" data-lazy-sizes="(max-width: 640px) 100vw, 640px" data-lazy-src="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large-750x422.png?resize=640%2C360&ssl=1" /><noscript><img data-recalc-dims="1" loading="lazy" decoding="async" width="640" height="360" src="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large-750x422.png?resize=640%2C360&ssl=1" alt="" class="wp-image-568486" srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large.png?resize=750%2C422&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large.png?resize=1024%2C576&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large.png?resize=450%2C253&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large.png?resize=768%2C432&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large.png?resize=1536%2C864&ssl=1 1536w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large.png?w=1920&ssl=1 1920w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/digit-ai-01a-Large.png?w=1280&ssl=1 1280w" sizes="(max-width: 640px) 100vw, 640px" /></noscript><figcaption class="wp-element-caption">Courtesy of DigiKey</figcaption></figure></div> <p>The client, called hopper-chat, controls everything. It continuously listens for human speech from a microphone and converts everything it hears using the <strong>Alpha Cephei Vosk</strong> speech-to-text (STT) library. Any phrases it hears are compared to a list of wake words/phrases, similar to how you might say “Alexa” or “Hey, Siri” to get your smart speaker to start listening. For Digit, the wake phrase is, unsurprisingly, “Hey, Digit.” Upon hearing that phrase, any new utterances are converted to text using the same Vosk system.</p> <p>The newly generated text is then sent to the LLM service. This service is a Docker container running <strong>Ollama</strong>, an open-source tool for running LLMs. In this case, the LLM is Meta’s <strong>Llama3:8b</strong> model with 8 billion parameters. While not as complex as OpenAI’s ChatGPT-4, it still has impressive conversational skills. The service sends the response back to the hopper-chat client, which immediately forwards it to the text-to-speech (TTS) service.</p> <p>TTS for hopper-chat is a service running <strong>Rhasspy Piper</strong> that encapsulates the <strong>en_US-lessac-low</strong> model, a neural network trained to produce sounds when given text. In this case, the model is specifically trained to produce English words and phrases in an American dialect. The “low” suffix indicates that the model is low quality — smaller size, more robotic sounds, but faster execution. The hopper-chat program plays any sounds it receives from the TTS service through a connected speaker.</p> <p>On Digit, the microphone is connected to a USB port on the Orin Nano and simply draped over a backpack strap. The speaker is connected via Bluetooth. Moss uses an Arduino to monitor activity in the Bluetooth speaker and move the mandibles during activity to give Digit the appearance of speaking.</p> <p>Moss added several fun features to give Digit a distinct personality. First, Digit tells a random joke, often a bad pun, every minute if the wake phrase is not heard. Second, Moss experimented with various default prompts to entice the LLM to respond in particular ways. This includes making random robot noises when generating a response and adopting different personalities, from helpful to sarcastic and pessimistic.</p> <div class="wp-block-image"> <figure class="aligncenter size-medium"><img data-recalc-dims="1" decoding="async" width="640" height="480" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20640%20480'%3E%3C/svg%3E" alt="" class="wp-image-568493" data-lazy-srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large.jpg?resize=750%2C563&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large.jpg?resize=1024%2C768&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large.jpg?resize=450%2C338&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large.jpg?resize=768%2C576&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large.jpg?resize=272%2C204&ssl=1 272w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large.jpg?w=1440&ssl=1 1440w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large.jpg?w=1280&ssl=1 1280w" data-lazy-sizes="(max-width: 640px) 100vw, 640px" data-lazy-src="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large-750x563.jpg?resize=640%2C480&ssl=1" /><noscript><img data-recalc-dims="1" loading="lazy" decoding="async" width="640" height="480" src="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large-750x563.jpg?resize=640%2C480&ssl=1" alt="" class="wp-image-568493" srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large.jpg?resize=750%2C563&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large.jpg?resize=1024%2C768&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large.jpg?resize=450%2C338&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large.jpg?resize=768%2C576&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large.jpg?resize=272%2C204&ssl=1 272w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large.jpg?w=1440&ssl=1 1440w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/jayy-digit-02-cropped-Large.jpg?w=1280&ssl=1 1280w" sizes="(max-width: 640px) 100vw, 640px" /></noscript><figcaption class="wp-element-caption">Courtesy of Jorvon Moss</figcaption></figure></div> <h2 class="wp-block-heading" id="h-agency-from-text-to-action">Agency: From Text to Action</h2> <p>The next steps for Digit involve giving it a form of self-powered locomotion, such as walking, and having the LLM perform actions based on commands. On their own, LLMs cannot perform actions. They simply generate text responses based on input. However, adjustments and add-ons can be made that allow such systems to take action. For example, ChatGPT already has several third-party plugins that can perform actions, such as fetching local weather information. The LLM recognizes the intent of the query, such as, “What’s the weather like in Denver, Colorado?” and makes the appropriate API call using the plugin. (We’ll look at some very recent developments in function calling, below.)</p> <p>At the moment, Digit can identify specific phrases using its STT library, but the recorded phrase must exactly match the expected phrase. For example, you couldn’t say “What’s the weather like?” when the expected phrase is “Tell me the local weather forecast.” A well-trained LLM, however, could infer that intention. Moss and I plan to experiment with Ollama and Llama3:8b to add such intention and command recognition.</p> <p>The code for hopper-chat is open source and <a href="http://github.com/ShawnHymel/hopper-chat">can be found on GitHub</a>. Follow along with us as we make Digit even more capable.</p> <h2 class="wp-block-heading" id="h-diy-robot-makers">DIY Robot Makers</h2> <p>Science fiction is overflowing with shiny store-bought robots and androids created by mega corporations and the military. We’re more inspired by the DIY undercurrent — portrayals of solo engineers cobbling together their own intelligent and helpful companions. We’ve always believed this day would come, in part because we’ve seen it so many times on screen. —<em>Keith Hammond</em></p> <ul class="wp-block-list"> <li>Dr. Tenma and Toby/Astro (<em>Astro Boy</em> manga, anime, and films, 1952–2014)</li> <li>J.F. Sebastian and his toys Kaiser and Bear (<em>Blade Runner</em>, 1982)</li> <li>Wallace and his Techno-Trousers (<em>Wallace & Gromit: The Wrong Trousers</em>, 1993)</li> <li>Anakin Skywalker and C-3PO (<em>Star Wars: The Phantom Menace</em>, 1999)</li> <li>Sheldon J. Plankton and Karen (<em>Spongebob Squarepants</em>, 1999–2024)</li> <li>Dr. Heinz Doofenshmirtz and Norm (<em>Phineas and Ferb</em>, 2008–2024)</li> <li>The Scientist and 9 (<em>9</em>, 2009)</li> <li>Charlie Kenton and Atom (<em>Real Steel</em>, 2011)</li> <li>Tadashi Hamada and Baymax (<em>Big Hero 6</em>, 2014)</li> <li>Simone Giertz and her Shitty Robots (<em>YouTube</em>, 2016–2018)</li> <li>Kuill and IG-11 (<em>The Mandalorian</em>, 2019)</li> <li>Finch and Jeff (<em>Finch</em>, 2021)</li> <li>Brian and Charles (<em>Brian and Charles</em>, 2022)</li> </ul> <h2 class="wp-block-heading" id="h-roll-your-own-local-llm-chatbot">Roll Your Own Local LLM Chatbot</h2> <p>I will walk you through the process of running an LLM on a Raspberry Pi. I specifically chose the Raspberry Pi 5 due to its increased computational power. LLMs are notoriously complex, so earlier versions of the Pi might need several minutes to produce an answer, even from relatively small LLMs. My Pi 5 had 8GB RAM; these LLMs may not run with less.</p> <div class="project-description"></div> <div class="alert-section"> <section id="text-23" class="widget widget_text"> <div class="textwidget"><p>What will the next generation of Make: look like? We’re inviting you to shape the future by investing in Make:. By becoming an investor, you help decide what’s next. The future of Make: is in your hands. <strong><a class="wefunder-cta" href="https://wefunder.com/make?utm_source=make&utm_medium=makezine&utm_campaign=wefunder&utm_content=cta_widget">Learn More.</a></strong></p> </div> </section> </div> <div class="project-steps-wrapper" id="the-steps"> <div class="project-steps-header"> <h2>Project Steps</h2> <select name="step-selector" onchange="gotoStep(this.value);"> <option value="#step-1">1. Set up the Pi 5 with Ollama</div><option value="#step-2">2. Try out TinyLlama</div><option value="#step-3">3. Set up the Ollama Python package</div><option value="#step-4">4. Chat with your LLM bot!</div><option value="#step-5">Local LLM Chatbot with Function Calling</div><option value="#step-6">A Closer Look at Ollama Tools</div> </select> </div> <div class="project-step" id="step-1"><h3 class="project-step-title">1. Set up the Pi 5 with Ollama</h3><div class="step-buttons"></div><div class="project-step-content"><p>Follow the official <a href="http://raspberrypi.com/documentation/computers/getting-started.html">Raspberry Pi Getting Started guide</a> to install the latest Raspberry Pi OS (64-bit) and configure your Raspberry Pi. You should use an SD card with at least 16 GB.<br /> Once you have booted into your Raspberry Pi, make sure you are connected to the internet and open a terminal window. Enter the following commands to updated the Pi and to install Ollama:</p> <pre>$ sudo apt update $ sudo apt upgrade $ curl -fsSL https://ollama.com/install.sh | sh</pre> <p>Next, start the Ollama service:</p> <pre>$ ollama serve</pre> <p>You might see a message that says “Error: listen tcp 127.0.0.1:11434: bind: address already in use.” Ignore this, as it just indicates that Ollama is already running as a service in the background.</p> </div></div><div class="project-step" id="step-2"><h3 class="project-step-title">2. Try out TinyLlama</h3><div class="step-buttons"></div><div class="project-step-content"><p>Meta’s LLaMa models are almost open source, with some caveats for commercial usage. AI researcher Zhang Peiyuan started the <strong>TinyLlama</strong> project in September 2023. TinyLlama is a truly open-source (Apache-2.0 license), highly-optimized LLM with only 1.1 billion parameters. It is based on the LLaMa 2 model and can generate responses quite quickly. It’s not as accurate as the newer generation of small LLMs, such as Llama3, but it will run on hobby-level hardware like our Pi 5.</p> <p>Download the latest version of TinyLlama with ollama:</p> <pre>$ ollama pull tinyllama</pre> <p>Run an interactive shell to chat with TinyLlama:</p> <pre>$ ollama run tinyllama</pre> <p>You should be presented with a prompt. Try asking the AI a question or have it tell you a joke.</p> <figure id="attachment_568489" aria-describedby="caption-attachment-568489" style="width: 750px" class="wp-caption aligncenter"><img decoding="async" class="size-medium wp-image-568489" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20750%20427'%3E%3C/svg%3E" alt="" width="750" height="427" data-lazy-srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large.png?resize=750%2C427&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large.png?resize=1024%2C583&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large.png?resize=450%2C256&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large.png?resize=768%2C437&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large.png?w=1522&ssl=1 1522w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large.png?w=1280&ssl=1 1280w" data-lazy-sizes="(max-width: 750px) 100vw, 750px" data-lazy-src="https://makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large-750x427.png" /><noscript><img loading="lazy" decoding="async" class="size-medium wp-image-568489" src="https://makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large-750x427.png" alt="" width="750" height="427" srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large.png?resize=750%2C427&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large.png?resize=1024%2C583&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large.png?resize=450%2C256&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large.png?resize=768%2C437&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large.png?w=1522&ssl=1 1522w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large.png?w=1280&ssl=1 1280w" sizes="(max-width: 750px) 100vw, 750px" /></noscript><figcaption id="caption-attachment-568489" class="wp-caption-text">Courtesy of Shawn Hymel</figcaption></figure> <p>Press Ctrl+D or enter <strong>/bye</strong> to exit the interactive shell.</p> </div></div><div class="project-step" id="step-3"><h3 class="project-step-title">3. Set up the Ollama Python package</h3><div class="step-buttons"></div><div class="project-step-content"><p>By default, Ollama runs as a background server and exposes port 11434. You can communicate with that service by making HTTP requests. To make life easier, Ollama maintains a Python library that communicates directly with that locally running service. Create a virtual environment and install the package:</p> <pre>$ python -m venv venv-ollama --system-site-packages $ source venv-ollama/bin/activate $ python -m pip install ollama==0.3.3</pre> <p>Open a new document:</p> <pre>$ nano tinyllama-client.py</pre> <p>Enter the following Python code:</p> <pre>import ollama # Settings prompt = "You are a helpful assistant. Tell me a joke. " \ "Limit your response to 2 sentences or fewer." model = "tinyllama" # Configure the client client = ollama.Client(host="http://0.0.0.0:11434") # The message history is an array of prompts and responses messages = [{ "role": "user", "content": prompt }] # Send prompt to Ollama server and save the response response = client.chat( model=model, messages=messages, stream=False ) # Print the response print(response["message"]["content"])</pre> <p>Close the file by pressing Ctrl+X, press Y when asked to save the document, and press Enter.</p> </div></div><div class="project-step" id="step-4"><h3 class="project-step-title">4. Chat with your LLM bot!</h3><div class="step-buttons"></div><div class="project-step-content"><p>Run the Python script by entering:</p> <pre>$ python tinyllama-client.py</pre> <p>TinyLlama can take some time to generate a response, especially on a small computer like the Raspberry Pi — 30 seconds or more — but here you are, chatting locally with an AI!</p> <figure id="attachment_568488" aria-describedby="caption-attachment-568488" style="width: 750px" class="wp-caption aligncenter"><img decoding="async" class="size-medium wp-image-568488" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20750%2072'%3E%3C/svg%3E" alt="" width="750" height="72" data-lazy-srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large.png?resize=750%2C72&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large.png?resize=1024%2C98&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large.png?resize=450%2C43&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large.png?resize=768%2C74&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large.png?w=1522&ssl=1 1522w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large.png?w=1280&ssl=1 1280w" data-lazy-sizes="(max-width: 750px) 100vw, 750px" data-lazy-src="https://makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large-750x72.png" /><noscript><img loading="lazy" decoding="async" class="size-medium wp-image-568488" src="https://makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large-750x72.png" alt="" width="750" height="72" srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large.png?resize=750%2C72&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large.png?resize=1024%2C98&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large.png?resize=450%2C43&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large.png?resize=768%2C74&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large.png?w=1522&ssl=1 1522w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large.png?w=1280&ssl=1 1280w" sizes="(max-width: 750px) 100vw, 750px" /></noscript><figcaption id="caption-attachment-568488" class="wp-caption-text">Courtesy of Shawn Hymel</figcaption></figure> <p>This should give you a sense of how to run local LLMs on a Raspberry Pi and interact with them using Python. Feel free to try different prompts, save the chat history using the <strong>append()</strong> method, and build your own voice-activated chatbot.</p> </div></div><div class="project-step" id="step-5"><h3 class="project-step-title">Local LLM Chatbot with Function Calling</h3><div class="step-buttons"></div><div class="project-step-content"><p>LLMs have traditionally been self-contained models that accept text input and respond with text. In the last couple of years, we’ve seen multimodal LLMs enter the scene, like GPT-4o, that can accept and respond with other forms of media, such as images and videos.</p> <p>But in just the past few months, some LLMs have been granted a powerful new ability — to call arbitrary functions — which opens a huge world of possible AI actions. ChatGPT and Ollama both call this ability <em><strong>tools</strong></em>. To enable such tools, you must define the functions in a Python dictionary and fully describe their use and available parameters. The LLM tries to figure out what you’re asking and maps that request to one of the available tools/functions. We then parse the response before calling the actual function.</p> <p>Let’s demonstrate this concept with a simple function that turns an LED on and off. Connect an LED with a limiting resistor to pin GPIO 17 on your Raspberry Pi 5.</p> <figure id="attachment_568490" aria-describedby="caption-attachment-568490" style="width: 750px" class="wp-caption aligncenter"><img decoding="async" class="size-medium wp-image-568490" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20750%20961'%3E%3C/svg%3E" alt="" width="750" height="961" data-lazy-srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large.png?resize=750%2C961&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large.png?resize=799%2C1024&ssl=1 799w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large.png?resize=351%2C450&ssl=1 351w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large.png?resize=768%2C984&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large.png?resize=345%2C441&ssl=1 345w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large.png?w=1080&ssl=1 1080w" data-lazy-sizes="(max-width: 750px) 100vw, 750px" data-lazy-src="https://makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large-750x961.png" /><noscript><img loading="lazy" decoding="async" class="size-medium wp-image-568490" src="https://makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large-750x961.png" alt="" width="750" height="961" srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large.png?resize=750%2C961&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large.png?resize=799%2C1024&ssl=1 799w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large.png?resize=351%2C450&ssl=1 351w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large.png?resize=768%2C984&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large.png?resize=345%2C441&ssl=1 345w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large.png?w=1080&ssl=1 1080w" sizes="(max-width: 750px) 100vw, 750px" /></noscript><figcaption id="caption-attachment-568490" class="wp-caption-text">Courtesy of Shawn Hymel / Fritzing</figcaption></figure> <p>Make sure you’re in the <strong>venv-ollama</strong> virtual environment we configured earlier and install some dependencies:</p> <pre>$ source venv-ollama/bin/activate $ sudo apt update $ sudo apt upgrade $ sudo apt install -y libportaudio2 $ python -m pip install ollama==0.3.3 vosk==0.3.45 sounddevice==0.5.0</pre> <p>You’ll need to download a new LLM model and the Vosk speech-to-text (STT) model:</p> <pre>$ ollama pull allenporter/xlam:1b $ python -c "from vosk import Model; Model(lang='en-us')"</pre> <p>As this example uses speech-to-text to convey information to the LLM, you will need a USB microphone, such as Adafruit 3367. With the microphone connected, run the following command to discover the USB microphone device number:</p> <pre>$ python -c "import sounddevice; print(sounddevice.query_devices())"</pre> <p>You should see an output such as:</p> <pre> 0 USB PnP Sound Device: Audio (hw:2,0), ALSA (1 in, 0 out) 1 pulse, ALSA (32 in, 32 out) * 2 default, ALSA (32 in, 32 out)</pre> <p>Note the device number of the USB microphone. In this case, my microphone is device number 0, as given by USB PnP Sound Device. Copy <a href="https://gist.github.com/ShawnHymel/16f1228c92ad0eb9d5fbebbfe296ee6a">this code</a> to a file named ollama-light-assistant.py on your Raspberry Pi.</p> <p>You can also download this file directly with the command:</p> <pre>$ wget https://gist.githubusercontent.com/ShawnHymel/16f1228c92ad0eb9d5fbebbfe296ee6a/raw/6161a9cb38d3f3c4388a82e5e6c6c58a150111cc/ollama-light-assistant.py</pre> <p>Open the code and change the <strong>AUDIO_INPUT_INDEX</strong> value to your USB microphone device number. For example, mine would be:</p> <pre>AUDIO_INPUT_INDEX = 0</pre> <p>Run the code with:</p> <pre>$ python ollama-light-assistant.py</pre> <p>You should see the Vosk STT system boot up and then the script will say “Listening…” At that point, try asking the LLM to “turn the light on.” Because the Pi is not optimized for LLMs, the response could take 30–60 seconds. With some luck, you should see that the <strong>led_write</strong> function was called, and the LED has turned on!</p> <figure id="attachment_568491" aria-describedby="caption-attachment-568491" style="width: 750px" class="wp-caption aligncenter"><img decoding="async" class="size-medium wp-image-568491" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20750%20462'%3E%3C/svg%3E" alt="" width="750" height="462" data-lazy-srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-03a-Large.png?resize=750%2C462&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-03a-Large.png?resize=1024%2C631&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-03a-Large.png?resize=450%2C277&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-03a-Large.png?resize=768%2C473&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-03a-Large.png?w=1522&ssl=1 1522w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-03a-Large.png?w=1280&ssl=1 1280w" data-lazy-sizes="(max-width: 750px) 100vw, 750px" data-lazy-src="https://makezine.com/wp-content/uploads/2024/10/ollama-pi-03a-Large-750x462.png" /><noscript><img loading="lazy" decoding="async" class="size-medium wp-image-568491" src="https://makezine.com/wp-content/uploads/2024/10/ollama-pi-03a-Large-750x462.png" alt="" width="750" height="462" srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-03a-Large.png?resize=750%2C462&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-03a-Large.png?resize=1024%2C631&ssl=1 1024w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-03a-Large.png?resize=450%2C277&ssl=1 450w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-03a-Large.png?resize=768%2C473&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-03a-Large.png?w=1522&ssl=1 1522w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/10/ollama-pi-03a-Large.png?w=1280&ssl=1 1280w" sizes="(max-width: 750px) 100vw, 750px" /></noscript><figcaption id="caption-attachment-568491" class="wp-caption-text">Courtesy of Shawn Hymel</figcaption></figure> <p>The <a href="http://github.com/SalesforceAIResearch/xLAM"><strong>xLAM</strong> model</a> is an open-source LLM developed by the SalesForce AI Research team. It is trained and optimized to <em>understand</em> requests rather than necessarily providing text-based answers to questions. The <a href="http://ollama.com/allenporter/xlam"><strong>allenporter</strong></a> version has been modified to work with Ollama tools. The 1-billion-parameter model can run on the Raspberry Pi, but as you probably noticed, it is quite slow and misinterprets requests easily.</p> <p>For an LLM that better understands requests, I recommend the <strong>Llama3.1:8b</strong> model. In the command console, download the model with:</p> <pre>$ ollama pull llama3.1:8b</pre> <p>Note that the Llama 3.1:8b model is almost 5 GB. If you’re running out of space on your flash storage, you can remove previous models. For example:</p> <pre>$ ollama rm tinyllama</pre> <p>In the code, change:</p> <pre>MODEL = "allenporter/xlam:1b"</pre> <p>to:</p> <pre>MODEL = "llama3.1:8b"</pre> <p>Run the script again. You’ll notice that the model is less picky about the exact phrasing of the request, but it takes much longer to respond — up to 3 minutes on a Raspberry Pi 5 (8GB RAM).<br /> When you are done, you can exit the virtual environment with the following command:</p> <pre>$ deactivate</pre> </div></div><div class="project-step" id="step-6"><h3 class="project-step-title">A Closer Look at Ollama Tools</h3><div class="step-buttons"></div><div class="project-step-content"><p>Let’s take a moment to discuss how tools work in Ollama. Feel free to open the <em>ollama-light-assistant.py</em> file to follow along.<br /> First, you need to define the function you want to call. In our example, we create a simple <strong>led_write()</strong> function that accepts an <strong>led</strong> object (as created by the Raspberry Pi <strong>gpiozero</strong> library) and an integer value: 0 for off, 1 for on.</p> <pre>def led_write(led, value): """ Turn the LED on or off. """ if int(value) > 0: led.on() print("The LED is now on") else: led.off() print("The LED is now off")</pre> <p>The trick is to get the LLM to understand that calling this function is a possibility! Since the LLM does not have direct access to your code, the <em>ollama</em> library acts as an intermediary. By defining a set of tools, the LLM can return one of those tools as a response instead of (or in addition to) its usual text-based answer. This response comes in the form of a JSON or Python dictionary that our code can parse and call the related function.</p> <p>You must define the tools in a list of dictionary objects. As these small LLMs struggle with the concept of an “LED,” we’ll call this a “light.” In our code, we provide the following description of the <strong>led_write()</strong> function to Ollama:</p> <pre>TOOLS = [ { 'type': 'function', 'function': { 'name': "led_write", 'description': "Turn the light off or on", 'parameters': { 'type': 'object', 'properties': { 'value': { 'type': 'number', 'description': "The value to write to the light pin " \ "to turn it off and on. 0 for off, 1 for on.", }, }, 'required': ['value'], }, } } ] </pre> <p>In the send() function, we send our query to the Ollama server running the LLM. This query is captured by the Vosk STT functions and converted to text before being added to the message history buffer msg_history.</p> <pre>response = client.chat( model=model, messages=msg_history.get(), tools=TOOLS, stream=False ) </pre> <p>When we receive the response from the LLM, we check to see if it contains an entry with the key <strong>tool_calls</strong>. If so, it means the LLM decided to use one of the defined tools! We then need to figure out which tool the LLM intended to use by cycling through all of the returned tool names. If the name <strong>led_write</strong> is given for one of the tools, which we defined in the original <strong>TOOLS</strong> dictionary, we call the <strong>led_write()</strong> function. We provide the function call with the pre-defined <strong>led</strong> object and argument <strong>value</strong> that the LLM decided to give.</p> <pre>if response['message'].get('tool_calls') is None: print("Tools not used.") return else: print("Tools used. Calling:") for tool in response['message']['tool_calls']: print(tool) if tool['function']['name'] == "led_write": led_write(led, tool['function']['arguments']['value'])</pre> <p>The properties defined in the <strong>TOOLS</strong> dictionary give the LLM context about the function, such as its use case and the necessary arguments it needs to provide. Think of it like giving an AI agent a form to fill out. The AI will first determine which form to use based on the request (e.g. “control a light”) and then figure out how to fill in the various fields. For example, the <strong>value</strong> parameter says that the field must be a number and it should be a 0 for “off” and 1 for “on.” The LLM uses these context clues to figure out how to craft an appropriate response.</p> </div></div> <div class="project-conclusion"> <h2 class="step-heading">Conclusion</h2> <h3>Robot Powers, Activate!</h3> <p>This example demonstrates the possibilities of using LLMs for understanding user intention and for processing requests to call arbitrary functions. Such technology is extremely powerful — we can connect AI agents to the internet to make requests, and control hardware! — but it’s still new and experimental. You will likely run into bugs, and you can expect the code interface to change. It also demonstrates the need for better-optimized models and more powerful hardware. A few boards such as the Jetson Orin Nano and accelerators like the new Hailo-10H enable low-cost local LLM execution today. I’m excited to see this tech get better!</p> <h3>More about Ollama:</h3> <ul> <li><a href="http://ollama.com">Ollama</a> is a lightweight framework for locally running LLMs</li> <li>The <a href="http://github.com/ollama/ollama/blob/main/docs/api.md">Ollama API</a> is compatible with most of the OpenAI API, which means you can use many of the same client function calls found in the<a href="http://platform.openai.com/docs/api-reference/introduction"> OpenAI documentation</a>.</li> <li>Ollama tools — <a href="http://ollama.com/blog/tool-support">support and examples</a></li> </ul> <p><em>This article appeared in Make: Vol. 91. <a href="https://subscribe.makezine.com/loading.do?omedasite=Make_subscribe" target="_blank" rel="noopener">Subscribe</a> for more maker projects and articles!</em></p> </div> </div> </section> <div class="related-makershed-wrapper amount-4"><h3>From the Shed: New Arrivals</h3><div class="related-makershed-items"><a href="https://www.makershed.com/products/make-arduino-electronics-starter-pack?utm_source=makezine&utm_medium=related&utm_campaign=makershed&utm_content=launch" class="related-makershed-item" target="_blank"><div class="image-square"><img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%200%200'%3E%3C/svg%3E" alt="Make: Arduino Electronics Starter Pack" data-lazy-src="https://cdn.shopify.com/s/files/1/0243/7593/files/PXL_20230627_164747231.PORTRAIT_2.jpg?v=1687885418" /><noscript><img src="https://cdn.shopify.com/s/files/1/0243/7593/files/PXL_20230627_164747231.PORTRAIT_2.jpg?v=1687885418" alt="Make: Arduino Electronics Starter Pack" /></noscript></div><h4>Make: Arduino Electronics Starter Pack</h4><div class="item-price">$64.95</div></a><a href="https://www.makershed.com/products/transistor-cat-kit?utm_source=makezine&utm_medium=related&utm_campaign=makershed&utm_content=launch" class="related-makershed-item" target="_blank"><div class="image-square"><img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%200%200'%3E%3C/svg%3E" alt="Transistor Cat Kit" data-lazy-src="https://cdn.shopify.com/s/files/1/0243/7593/files/IMG_0408.jpg?v=1700673662" /><noscript><img src="https://cdn.shopify.com/s/files/1/0243/7593/files/IMG_0408.jpg?v=1700673662" alt="Transistor Cat Kit" /></noscript></div><h4>Transistor Cat Kit</h4><div class="item-price">$12.95</div></a><a href="https://www.makershed.com/products/maker-faire-mare-island-hoodie?utm_source=makezine&utm_medium=related&utm_campaign=makershed&utm_content=launch" class="related-makershed-item" target="_blank"><div class="image-square"><img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%200%200'%3E%3C/svg%3E" alt="Maker Faire Mare Island Hoodie" data-lazy-src="https://cdn.shopify.com/s/files/1/0243/7593/files/SeaDragon.Hoodie.Full.png?v=1698946890" /><noscript><img src="https://cdn.shopify.com/s/files/1/0243/7593/files/SeaDragon.Hoodie.Full.png?v=1698946890" alt="Maker Faire Mare Island Hoodie" /></noscript></div><h4>Maker Faire Mare Island Hoodie</h4><div class="item-price">$35.00</div></a><a href="https://www.makershed.com/products/emf?utm_source=makezine&utm_medium=related&utm_campaign=makershed&utm_content=launch" class="related-makershed-item" target="_blank"><div class="image-square"><img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%200%200'%3E%3C/svg%3E" alt="The EMF Explorer Kit" data-lazy-src="https://cdn.shopify.com/s/files/1/0243/7593/files/emfbadgeinhand.jpg?v=1721855578" /><noscript><img src="https://cdn.shopify.com/s/files/1/0243/7593/files/emfbadgeinhand.jpg?v=1721855578" alt="The EMF Explorer Kit" /></noscript></div><h4>The EMF Explorer Kit</h4><div class="item-price">$29.99</div></a></div></div> </div> </div> <aside class="sidebar-wrapper"> <div class="theiaStickySidebar"> <div class="parts-and-tools-sidebar"> <div class="sidebar-content parts-wrapper" id="parts"><h3>Materials</h3><div class="parts-list"><ul> <li><strong>Raspberry Pi 5 single-board computer, 8GB RAM or more</strong></li> <li><strong>MicroSD card, 16GB or more</strong></li> <li><strong>USB microphone</strong> such as Adafruit 3367</li> <li><strong>Breadboard</strong></li> <li><strong>LED</strong></li> <li><strong>Resistor, 220Ω to 1kΩ</strong></li> <li><strong>Jumper wires</strong></li> </ul> </div></div><div class="sidebar-content tools-wrapper" id="tools"><h3>Tools</h3><div class="tools-list"><ul> <li><strong>Computer</strong> to flash Raspberry Pi OS; not needed afterward</li> <li><strong>Keyboard, mouse, and monitor</strong> connected to Raspberry Pi</li> <li><strong><a href="https://www.raspberrypi.com/software/">Raspberry Pi Imager</a> </strong></li> <li><strong><a href="https://gist.github.com/ShawnHymel/16f1228c92ad0eb9d5fbebbfe296ee6a">Light assistant code</a> </strong></li> </ul> </div></div> </div> </div> </aside> </div> </article> <span class="tags-links">Tagged <a href="https://makezine.com/tag/ai/" rel="tag">AI</a> <a href="https://makezine.com/tag/artificial-intelligence/" rel="tag">artificial intelligence</a> <a href="https://makezine.com/tag/companion/" rel="tag">companion</a> <a href="https://makezine.com/tag/cosplay/" rel="tag">cosplay</a> <a href="https://makezine.com/tag/expressive-robots/" rel="tag">expressive robots</a> <a href="https://makezine.com/tag/large-language-model/" rel="tag">Large Language Model</a> <a href="https://makezine.com/tag/llm/" rel="tag">LLM</a> <a href="https://makezine.com/tag/make91/" rel="tag">make91</a> <a href="https://makezine.com/tag/raspberry-pi-2/" rel="tag">raspberry pi</a></span><div class="row mz-author-row"><div class="col-xs-12 col-sm-3 col-lg-2 mz-author-img"><img src="https://i0.wp.com/makezine.com/wp-content/uploads/2022/05/headshot-1.png?fit=150%2C150&resize=300%2C300&quality=70&strip=all#038;ssl=1&resize=396%2C396&strip=all" alt="Shawn Hymel" class="avatar avatar-396" width="396" height="396"></div><div class="col-xs-12 col-sm-9 col-lg-10 -author-profile-bio"><h3 class="jumbo"><a href="https://makezine.com/author/shawn-hymel">Shawn Hymel</a></h3></h3><p><p>is an embedded engineer, maker, technical content creator, and instructor. He loves finding fun uses of technology at the intersection of code and electronics, as well as swing dancing in his free time (pandemic permitting).</p> <p></div></div> </div> <script> dataLayer.push({ 'event': 'taxonomyTracker', 'Category': 'Artificial Intelligence', }); </script> <script> dataLayer.push({ 'event': 'taxonomyTracker', 'Category': 'Costumes, Cosplay, and Props', }); </script> <script> dataLayer.push({ 'event': 'taxonomyTracker', 'Category': 'Raspberry Pi', }); </script> <script> dataLayer.push({ 'event': 'taxonomyTracker', 'Category': 'Robotics', }); </script> <script> dataLayer.push({ 'event': 'taxonomyTracker', 'Category': 'Technology', }); </script> </div><!-- .cv-container --> </div><!-- #content --> <div id="nv-scrollup" class="animated arrow-hide"><i class="fa fa-chevron-up"></i></div> <div class="affiliate-message hidden"> <div class="container"> <i class="fas fa-angle-double-right"></i> When you buy through links on our site, we may earn an affiliate commission. </div> </div> <script> jQuery(function () { jQuery("#accordion").accordion({ collapsible: true }); }); </script> <script> /* Set the date we're counting down to var countDownDate = new Date("Nov 15, 2024 09:00:00 GMT-05:00").getTime(); // Get today's date and time var now = new Date().getTime(); // Find the distance between now and the count down date var distance = countDownDate - now; // turn that into days, hours, minutes var days = Math.floor(distance / (1000 * 60 * 60 * 24)); var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); document.addEventListener('DOMContentLoaded', function(){ if(days > 1) { document.getElementById("weFunderTime").innerHTML = days + " Days to Go for Exclusive Benefits"; } else if(days > 0) { document.getElementById("weFunderTime").innerHTML = days + " Day to Go for Exclusive Benefits"; // If the count down is down to hours, show that } else if (hours > 1) { document.getElementById("weFunderTime").innerHTML = hours + " Hours to Go for Exclusive Benefits"; } else if (hours > 0) { document.getElementById("weFunderTime").innerHTML = hours + " Hour to Go for Exclusive Benefits"; // if there are mere minutes left, show that } else if (minutes > 1) { document.getElementById("weFunderTime").innerHTML = minutes + " Minutes to Go for Exclusive Benefits"; } else if (minutes > 1) { document.getElementById("weFunderTime").innerHTML = minutes + " Minute to Go for Exclusive Benefits"; } else { document.getElementById("wefunderWrapper").remove(); } });*/ </script> <style> .floating-footer { gap: 0px; } #wefunderWrapper { display:flex; justify-content:center; align-items:center; color:#333; min-height:100%; padding:10px; width:23vw; font-weight: 300; @media screen and (max-width: 835px) { width:25vw; padding: 5px; } @media screen and (max-width: 635px) { width:28vw; font-family: 'Roboto Light'; } @media screen and (max-width: 500px) { width: 32vw; } } #weFunderTime { font-size: 1.75vw; line-height: 1; @media screen and (max-width: 1136px) { font-size: 1.6vw; } @media screen and (max-width: 980px) { font-size: 2vw; } @media screen and (max-width: 600px) { font-size: 3vw; } } </style> <div class="floating-footer"> <!--<div id="wefunderWrapper"> <span id="weFunderTime">days<br />to go!</span> </div>--> <div > <a class="floatingfooter-cta" style="margin-top:5px" href="https://wefunder.com/make?utm_source=make&utm_medium=universal_footer&utm_campaign=wefunder&utm_content=floating_footer" target="_blank"> <picture class="wefund-picture"> <source media="(max-width: 600px)" data-lazy-srcset="https://make.co/wp-content/universal-assets/v2/images/invest_in_make_mobile.jpg"> <source media="(max-width: 980px)" data-lazy-srcset="https://make.co/wp-content/universal-assets/v2/images/invest_in_make_tablet.jpg"> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%200%200'%3E%3C/svg%3E" alt="Invest in Make today" onerror="this.onerror=null;this.src='https://make.co/wp-content/universal-assets/v2/images/invest_in_make_desktop.jpg';this.srcset=''" data-photo="https://make.co/wp-content/universal-assets/v2/images/invest_in_make_desktop.jpg" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/invest_in_make_desktop.jpg"><noscript><img src="https://make.co/wp-content/universal-assets/v2/images/invest_in_make_desktop.jpg" alt="Invest in Make today" onerror="this.onerror=null;this.src='https://make.co/wp-content/universal-assets/v2/images/invest_in_make_desktop.jpg';this.srcset=''" data-photo="https://make.co/wp-content/universal-assets/v2/images/invest_in_make_desktop.jpg"></noscript> </picture> </a> </div> <!-- <div><a style="margin-top:5px" href="https://wefunder.com/make" class="universal-btn-red" target="_blank">Learn More</a></div> <div id="accordion"> <h3>Invest in Make:</h3> <picture class="exhibit-picture project-image"> <source media="(max-width: 600px)" data-lazy-srcset="https://make.co/wp-content/universal-assets/v2/images/invest_in_make_mobile.jpg"> <source media="(max-width: 980px)" data-lazy-srcset="https://make.co/wp-content/universal-assets/v2/images/invest_in_make_tablet.jpg"> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%200%200'%3E%3C/svg%3E" alt="Invest in Make today" onerror="this.onerror=null;this.src='/wp-content/themes/makerfaire/images/default-featured-image.jpg';this.srcset=''" data-photo="https://make.co/wp-content/universal-assets/v2/images/invest_in_make_desktop.jpg" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/invest_in_make_desktop.jpg"><noscript><img src="https://make.co/wp-content/universal-assets/v2/images/invest_in_make_desktop.jpg" alt="Invest in Make today" onerror="this.onerror=null;this.src='/wp-content/themes/makerfaire/images/default-featured-image.jpg';this.srcset=''" data-photo="https://make.co/wp-content/universal-assets/v2/images/invest_in_make_desktop.jpg"></noscript> </picture> </div> </div> <p> <a href="https://wefunder.com/make" class="universal-btn-red" target="_blank">Learn More</a> </p>--> </div> <footer data-wpr-lazyrender="1" class="universal-footer"> <section class="newsletter-footer"> <div class="_form_4 wrapper"></div> <script src="https://make.activehosted.com/f/embed.php?id=4" type="text/javascript" charset="utf-8" data-rocket-defer defer></script> </section> <section class="magazine-footer"> <div class="wrapper"> <div class="magazine-image"> <img class="img-responsive float-left" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20418%20275'%3E%3C/svg%3E" alt="Subscribe to Make: Magazine" width="418" height="275" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/make-magazine-covers.webp?ver=909" /><noscript><img class="img-responsive float-left" src="https://make.co/wp-content/universal-assets/v2/images/make-magazine-covers.webp?ver=909" alt="Subscribe to Make: Magazine" width="418" height="275" /></noscript> </div> <div class="magazine-text"> <h4>Subscribe & Save</h4> <ul class="hidden-sm hidden-xs"> <li>Dozens of projects in every issue covering electronics, craft, fabrication, and more</li> <li>Learn tips and skill-building tutorials from experts in the maker community</li> <li>Save over 40% off the annual cover price for a full year (4 issues) of Make:</li> </ul> <a href="https://subscribe.makezine.com/Make_subscribe?utm_source=make&utm_medium=universal_footer&utm_campaign=fat_footer&utm_content=launch" class="universal-btn-red" target="_blank">SUBSCRIBE TO MAKE: MAGAZINE</a> </div> </div> </section> <section class="link-footer"> <div class="wrapper"> <div class="footer-branding hidden-sm hidden-xs"> <div class="footer-branding-item"> <a href="https://make.co"> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20100%2040'%3E%3C/svg%3E" height="40" width="100" class="img-responsive" alt="Make: Community brand logo" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/make_co_logo.webp" /><noscript><img src="https://make.co/wp-content/universal-assets/v2/images/make_co_logo.webp" height="40" width="100" class="img-responsive" alt="Make: Community brand logo" /></noscript> </a> </div> <div class="footer-branding-item"> <span>Publishers of</span> <a href="https://makezine.com"> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2064%2019'%3E%3C/svg%3E" width="64" height="19" class="img-responsive" alt="Make:" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/make_logo.svg" /><noscript><img src="https://make.co/wp-content/universal-assets/v2/images/make_logo.svg" width="64" height="19" class="img-responsive" alt="Make:" /></noscript><span>Magazine</span> </a> </div> <div class="footer-branding-item"> <span>Producers of</span> <a href="https://makerfaire.com"> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20124%2031'%3E%3C/svg%3E" height="31" width="124" class="img-responsive" alt="Maker Faire Logo" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/Maker_Faire_Logo.svg" /><noscript><img src="https://make.co/wp-content/universal-assets/v2/images/Maker_Faire_Logo.svg" height="31" width="124" class="img-responsive" alt="Maker Faire Logo" /></noscript> </a> </div> </div> <div class="footer-links"> <div class="make-links"> <ul> <li><a href="https://make.co/">About us</a></li> <li><a href="https://make.co/our-team">Our team</a></li> <li><a href="https://make.co/partner">Advertise with us</a></li> <li><a href="https://help.make.co/hc/en-us" target="_blank">Help Center</a></li> </ul> </div> <div class="faire-links"> <ul> <li><a href="https://make.co/contact">Contact us</a></li> <li><a href="https://make.co/join">Support Make:</a></li> <li><a href="https://makerfaire.com/globalmap/">Find a Maker Faire</a></li> <li><a href="https://subscribe.makezine.com/Make_account_status?utm_source=make&utm_medium=universal_footer&utm_campaign=manage&utm_content=launch" target="_blank">Manage Magazine Subscription</a></li> </ul> </div> <div class="footer-social"> <hr class="hidden-lg hidden-md hidden-sm" /> <div class="footer-social-section"> <span class="footer-label">Make:</span> <ul> <li><a href="https://twitter.com/make" aria-label="Make: Magazine Twitter" target="_blank"><img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2032%2032'%3E%3C/svg%3E" class="footer-x-logo" height="32" width="32" alt="Twitter X Logo" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/twitter-x-logo-round.svg" /><noscript><img src="https://make.co/wp-content/universal-assets/v2/images/twitter-x-logo-round.svg" class="footer-x-logo" height="32" width="32" alt="Twitter X Logo" /></noscript></a></li> <li><a href="https://facebook.com/makemagazine" aria-label="Make: Magazine Facebook" target="_blank"><i aria-hidden="true" class="fab fa-facebook-square"></i></a></li> <li><a href="https://youtube.com/user/makemagazine" aria-label="Make: Magazine Youtube" target="_blank"><i aria-hidden="true" class="fa fab fa-youtube"></i></a></li> <li><a href="https://instagram.com/makemagazine" aria-label="Make: Magazine Instagram" target="_blank"><i aria-hidden="true" class="fab fa-instagram"></i></a></li> <li><a href="https://discord.gg/mpBkj2hhJ4" class="discord-footer" aria-label="Make: Magazine Discord" target="_blank"><i aria-hidden="true" class="fab fa-discord"></i></a></li> <li><a href="https://mastodon.social/@makemagazine" aria-label="Make: Mastodon" target="_blank" rel="me"><i aria-hidden="true" class="fab fa-mastodon"></i></a></li> </ul> </div> <div class="footer-social-section"> <span class="footer-label">Maker Faire:</span> <ul> <li><a href="https://twitter.com/makerfaire" aria-label="Maker Faire Twitter" target="_blank"><img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2032%2032'%3E%3C/svg%3E" class="footer-x-logo" height="32" width="32" alt="Twitter X Logo" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/twitter-x-logo-round.svg" /><noscript><img src="https://make.co/wp-content/universal-assets/v2/images/twitter-x-logo-round.svg" class="footer-x-logo" height="32" width="32" alt="Twitter X Logo" /></noscript></a></li> <li><a href="https://facebook.com/makerfaire" aria-label="Maker Faire Facebook" target="_blank"><i aria-hidden="true" class="fab fa-facebook-square"></i></a></li> <li><a href="https://youtube.com/makerfaire" aria-label="Maker Faire Youtube" target="_blank"><i aria-hidden="true" class="fab fa-youtube"></i></a></li> <li><a href="https://instagram.com/makerfaire" aria-label="Maker Faire Instagram" target="_blank"><i aria-hidden="true" class="fab fa-instagram"></i></a></li> <li><a href="https://discord.gg/mpBkj2hhJ4" class="discord-footer" aria-label="Maker Faire Discord" target="_blank"><i aria-hidden="true" class="fab fa-discord"></i></a></li> <li><a href="https://mastodon.social/@makemagazine" aria-label="Make: Mastodon" target="_blank" rel="me"><i aria-hidden="true" class="fab fa-mastodon"></i></a></li> </ul> </div> </div> </div> </div> </section> <section class="bottom-footer"> <div class="wrapper"> <div class="footer-copyright"> <span>©<span class="current-year">2024</span> Make Community LLC. All rights reserved</span> </div> <div class="footer-legal"> <div class="privacy"> <a href="https://make.co/terms-and-privacy-policy/#privacy-policy">Privacy Policy</a> </div> <div class="terms"> <a href="https://make.co/terms-and-privacy-policy/#terms-of-use">Terms of Use</a> </div> </div> </div> </section> </footer> <div id="pinterest-offer" style=display:none;> <a href="https://subscribe.makezine.com/Make_subscribe?PC=MK&PK=M0MPT2&utm_source=make&utm_medium=pinterest_popup&utm_campaign=pinterest&utm_content=launch" target="_blank"> <b>Special Pinterest-only offer!<br />One year of Make: Magazine for just $19.99</b> <img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20300%20253'%3E%3C/svg%3E" alt="Special Pinterest Make: Magazine subscription offer" width="300px" height="253px" data-lazy-src="https://make.co/wp-content/universal-assets/v2/images/make-magazine-covers-4.webp?ver=90" /><noscript><img src="https://make.co/wp-content/universal-assets/v2/images/make-magazine-covers-4.webp?ver=90" alt="Special Pinterest Make: Magazine subscription offer" width="300px" height="253px" /></noscript> </a> </div> <div id="cookie-settings-btn">Cookie Settings</div> <div id="cookie-footer"> <div class="cookie-footer-innerwrap"> <div class="cookie-text"> We use cookies to continuously improve our websites for you and optimize its design and customization. <br /> We'll assume you're ok with this, but you can opt-out if you wish. </div> <button id="cookie-configure" class="universal-btn-reversed">Configure</button> <button id="cookie-accept" class="universal-btn">Accept</button> </div> </div> <div id="cookie-dialog"> <p>Our websites use cookies to improve your browsing experience. Some of these are essential for the basic functionalities of our websites. In addition, we use third-party cookies to help us analyze and understand usage. These will be stored in your browser only with your consent and you have the option to opt-out. Your choice here will be recorded for all <span title="make.co, makerfaire.com, makezine.com, makercamp.com and all associated subdomains">Make.co Websites.</span></p> <div class="cookie-toggle"> <span>Allow Non-Necessary Cookies</span> <input type="checkbox" id="nonNeccessaryCookies" class="cmn-toggle cmn-toggle-round" checked /> <label for="nonNeccessaryCookies">Allow Non-Necessary Cookies</label> </div> <button class="universal-btn" type="button" onclick="jQuery('.ui-dialog-titlebar-close').click()">Accept</button> </div></div><!-- #page --> <div data-elementor-type="popup" data-elementor-id="568005" class="elementor elementor-568005 elementor-location-popup" data-elementor-settings="{"entrance_animation":"fadeIn","exit_animation":"fadeIn","entrance_animation_duration":{"unit":"px","size":0.7,"sizes":[]},"prevent_scroll":"yes","avoid_multiple_popups":"yes","a11y_navigation":"yes","triggers":{"page_load":"yes","page_load_delay":0},"timing":{"times":"yes","schedule_end_date":"2024-09-04 23:59","schedule":"yes","times_times":3,"schedule_timezone":"site","schedule_server_datetime":"2024-11-23 17:08:39"}}" data-elementor-post-type="elementor_library"> <section class="elementor-section elementor-top-section elementor-element elementor-element-447fbccc elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="447fbccc" data-element_type="section"> <div class="elementor-container elementor-column-gap-default"> <div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-421c5f18" data-id="421c5f18" data-element_type="column"> <div class="elementor-widget-wrap elementor-element-populated"> <div class="elementor-element elementor-element-6488bc2 skip-lazy elementor-widget elementor-widget-image" data-id="6488bc2" data-element_type="widget" data-widget_type="image.default"> <div class="elementor-widget-container"> <a href="https://makerfaire.com/bay-area/"> <img width="640" height="360" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20640%20360'%3E%3C/svg%3E" class="attachment-medium_large size-medium_large wp-image-568004" alt="" data-lazy-srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/08/MF_Labor-Day-Sale-25.png?w=768&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/08/MF_Labor-Day-Sale-25.png?resize=750%2C422&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/08/MF_Labor-Day-Sale-25.png?resize=450%2C253&ssl=1 450w" data-lazy-sizes="(max-width: 640px) 100vw, 640px" data-lazy-src="https://i0.wp.com/makezine.com/wp-content/uploads/2024/08/MF_Labor-Day-Sale-25.png?fit=640%2C360&ssl=1" /><noscript><img width="640" height="360" src="https://i0.wp.com/makezine.com/wp-content/uploads/2024/08/MF_Labor-Day-Sale-25.png?fit=640%2C360&ssl=1" class="attachment-medium_large size-medium_large wp-image-568004" alt="" srcset="https://i0.wp.com/makezine.com/wp-content/uploads/2024/08/MF_Labor-Day-Sale-25.png?w=768&ssl=1 768w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/08/MF_Labor-Day-Sale-25.png?resize=750%2C422&ssl=1 750w, https://i0.wp.com/makezine.com/wp-content/uploads/2024/08/MF_Labor-Day-Sale-25.png?resize=450%2C253&ssl=1 450w" sizes="(max-width: 640px) 100vw, 640px" /></noscript> </a> </div> </div> <div class="elementor-element elementor-element-65e545b0 elementor-widget elementor-widget-heading" data-id="65e545b0" data-element_type="widget" data-widget_type="heading.default"> <div class="elementor-widget-container"> <h2 class="elementor-heading-title elementor-size-default">Escape to an island of imagination + innovation as Maker Faire Bay Area returns for its 16th iteration!</h2> </div> </div> <div class="elementor-element elementor-element-61297bbc elementor-widget elementor-widget-heading" data-id="61297bbc" data-element_type="widget" data-widget_type="heading.default"> <div class="elementor-widget-container"> <h2 class="elementor-heading-title elementor-size-default">Prices Increase in....</h2> </div> </div> <div class="elementor-element elementor-element-5130771 elementor-countdown--label-block elementor-widget elementor-widget-countdown" data-id="5130771" data-element_type="widget" data-widget_type="countdown.default"> <div class="elementor-widget-container"> <div class="elementor-countdown-wrapper" data-date="1725519540"> <div class="elementor-countdown-item"><span class="elementor-countdown-digits elementor-countdown-days"></span> <span class="elementor-countdown-label">Days</span></div><div class="elementor-countdown-item"><span class="elementor-countdown-digits elementor-countdown-hours"></span> <span class="elementor-countdown-label">Hours</span></div><div class="elementor-countdown-item"><span class="elementor-countdown-digits elementor-countdown-minutes"></span> <span class="elementor-countdown-label">Minutes</span></div><div class="elementor-countdown-item"><span class="elementor-countdown-digits elementor-countdown-seconds"></span> <span class="elementor-countdown-label">Seconds</span></div> </div> </div> </div> <div class="elementor-element elementor-element-2c745a8d elementor-align-center elementor-widget elementor-widget-button" data-id="2c745a8d" data-element_type="widget" data-widget_type="button.default"> <div class="elementor-widget-container"> <div class="elementor-button-wrapper"> <a class="elementor-button elementor-button-link elementor-size-xl" href="https://makerfaire.com/bay-area/buy-tickets" target="_blank"> <span class="elementor-button-content-wrapper"> <span class="elementor-button-text">Buy Tickets Now</span> </span> </a> </div> </div> </div> </div> </div> </div> </section> </div> <script type='text/javascript'> const lazyloadRunObserver = () => { const lazyloadBackgrounds = document.querySelectorAll( `.e-con.e-parent:not(.e-lazyloaded)` ); const lazyloadBackgroundObserver = new IntersectionObserver( ( entries ) => { entries.forEach( ( entry ) => { if ( entry.isIntersecting ) { let lazyloadBackground = entry.target; if( lazyloadBackground ) { lazyloadBackground.classList.add( 'e-lazyloaded' ); } lazyloadBackgroundObserver.unobserve( entry.target ); } }); }, { rootMargin: '200px 0px 200px 0px' } ); lazyloadBackgrounds.forEach( ( lazyloadBackground ) => { lazyloadBackgroundObserver.observe( lazyloadBackground ); } ); }; const events = [ 'DOMContentLoaded', 'elementor/lazyload/observe', ]; events.forEach( ( event ) => { document.addEventListener( event, lazyloadRunObserver ); } ); </script> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/c/6.6.1/wp-includes/js/jquery/ui/core.min.js?ver=1731557387" id="jquery-ui-core-js" data-rocket-defer defer></script> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/c/6.6.1/wp-includes/js/jquery/ui/tabs.min.js?ver=1731557387" id="jquery-ui-tabs-js" data-rocket-defer defer></script> <script type="text/javascript" id="make-omeda-script-js-extra"> /* <![CDATA[ */ var make_ajax_object = {"ajaxurl":"https:\/\/makezine.com\/wp-admin\/admin-ajax.php","ajaxnonce":"821f5fe876"}; /* ]]> */ </script> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/wp-content/plugins/make-elementor-widgets/includes/js/omeda.js?ver=1731557387" id="make-omeda-script-js" data-rocket-defer defer></script> <script type="text/javascript" id="rocket-browser-checker-js-after"> /* <![CDATA[ */ "use strict";var _createClass=function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||!1,descriptor.configurable=!0,"value"in descriptor&&(descriptor.writable=!0),Object.defineProperty(target,descriptor.key,descriptor)}}return function(Constructor,protoProps,staticProps){return protoProps&&defineProperties(Constructor.prototype,protoProps),staticProps&&defineProperties(Constructor,staticProps),Constructor}}();function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor))throw new TypeError("Cannot call a class as a function")}var RocketBrowserCompatibilityChecker=function(){function RocketBrowserCompatibilityChecker(options){_classCallCheck(this,RocketBrowserCompatibilityChecker),this.passiveSupported=!1,this._checkPassiveOption(this),this.options=!!this.passiveSupported&&options}return _createClass(RocketBrowserCompatibilityChecker,[{key:"_checkPassiveOption",value:function(self){try{var options={get passive(){return!(self.passiveSupported=!0)}};window.addEventListener("test",null,options),window.removeEventListener("test",null,options)}catch(err){self.passiveSupported=!1}}},{key:"initRequestIdleCallback",value:function(){!1 in window&&(window.requestIdleCallback=function(cb){var start=Date.now();return setTimeout(function(){cb({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-start))}})},1)}),!1 in window&&(window.cancelIdleCallback=function(id){return clearTimeout(id)})}},{key:"isDataSaverModeOn",value:function(){return"connection"in navigator&&!0===navigator.connection.saveData}},{key:"supportsLinkPrefetch",value:function(){var elem=document.createElement("link");return elem.relList&&elem.relList.supports&&elem.relList.supports("prefetch")&&window.IntersectionObserver&&"isIntersecting"in IntersectionObserverEntry.prototype}},{key:"isSlowConnection",value:function(){return"connection"in navigator&&"effectiveType"in navigator.connection&&("2g"===navigator.connection.effectiveType||"slow-2g"===navigator.connection.effectiveType)}}]),RocketBrowserCompatibilityChecker}(); /* ]]> */ </script> <script type="text/javascript" id="rocket-preload-links-js-extra"> /* <![CDATA[ */ var RocketPreloadLinksConfig = {"excludeUris":"\/wp-admin\/|\/2021\/11\/16\/when-should-makers-use-manufacturing-on-demand\/|\/blog\/|\/wp-json\/yoast\/|\/wp-json\/yoast\/|\/comparison\/boards\/|\/tag\/js\/gpt.js\/|\/jsma\/68qNg8e\/ma.js\/|\/|\/(?:.+\/)?feed(?:\/(?:.+\/?)?)?$|\/(?:.+\/)?embed\/|\/(index.php\/)?(.*)wp-json(\/.*|$)|\/refer\/|\/go\/|\/recommend\/|\/recommends\/","usesTrailingSlash":"1","imageExt":"jpg|jpeg|gif|png|tiff|bmp|webp|avif|pdf|doc|docx|xls|xlsx|php","fileExt":"jpg|jpeg|gif|png|tiff|bmp|webp|avif|pdf|doc|docx|xls|xlsx|php|html|htm","siteUrl":"https:\/\/makezine.com","onHoverDelay":"100","rateThrottle":"3"}; /* ]]> */ </script> <script type="text/javascript" id="rocket-preload-links-js-after"> /* <![CDATA[ */ (function() { "use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e=function(){function i(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(e,t,n){return t&&i(e.prototype,t),n&&i(e,n),e}}();function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var t=function(){function n(e,t){i(this,n),this.browser=e,this.config=t,this.options=this.browser.options,this.prefetched=new Set,this.eventTime=null,this.threshold=1111,this.numOnHover=0}return e(n,[{key:"init",value:function(){!this.browser.supportsLinkPrefetch()||this.browser.isDataSaverModeOn()||this.browser.isSlowConnection()||(this.regex={excludeUris:RegExp(this.config.excludeUris,"i"),images:RegExp(".("+this.config.imageExt+")$","i"),fileExt:RegExp(".("+this.config.fileExt+")$","i")},this._initListeners(this))}},{key:"_initListeners",value:function(e){-1<this.config.onHoverDelay&&document.addEventListener("mouseover",e.listener.bind(e),e.listenerOptions),document.addEventListener("mousedown",e.listener.bind(e),e.listenerOptions),document.addEventListener("touchstart",e.listener.bind(e),e.listenerOptions)}},{key:"listener",value:function(e){var t=e.target.closest("a"),n=this._prepareUrl(t);if(null!==n)switch(e.type){case"mousedown":case"touchstart":this._addPrefetchLink(n);break;case"mouseover":this._earlyPrefetch(t,n,"mouseout")}}},{key:"_earlyPrefetch",value:function(t,e,n){var i=this,r=setTimeout(function(){if(r=null,0===i.numOnHover)setTimeout(function(){return i.numOnHover=0},1e3);else if(i.numOnHover>i.config.rateThrottle)return;i.numOnHover++,i._addPrefetchLink(e)},this.config.onHoverDelay);t.addEventListener(n,function e(){t.removeEventListener(n,e,{passive:!0}),null!==r&&(clearTimeout(r),r=null)},{passive:!0})}},{key:"_addPrefetchLink",value:function(i){return this.prefetched.add(i.href),new Promise(function(e,t){var n=document.createElement("link");n.rel="prefetch",n.href=i.href,n.onload=e,n.onerror=t,document.head.appendChild(n)}).catch(function(){})}},{key:"_prepareUrl",value:function(e){if(null===e||"object"!==(void 0===e?"undefined":r(e))||!1 in e||-1===["http:","https:"].indexOf(e.protocol))return null;var t=e.href.substring(0,this.config.siteUrl.length),n=this._getPathname(e.href,t),i={original:e.href,protocol:e.protocol,origin:t,pathname:n,href:t+n};return this._isLinkOk(i)?i:null}},{key:"_getPathname",value:function(e,t){var n=t?e.substring(this.config.siteUrl.length):e;return n.startsWith("/")||(n="/"+n),this._shouldAddTrailingSlash(n)?n+"/":n}},{key:"_shouldAddTrailingSlash",value:function(e){return this.config.usesTrailingSlash&&!e.endsWith("/")&&!this.regex.fileExt.test(e)}},{key:"_isLinkOk",value:function(e){return null!==e&&"object"===(void 0===e?"undefined":r(e))&&(!this.prefetched.has(e.href)&&e.origin===this.config.siteUrl&&-1===e.href.indexOf("?")&&-1===e.href.indexOf("#")&&!this.regex.excludeUris.test(e.href)&&!this.regex.images.test(e.href))}}],[{key:"run",value:function(){"undefined"!=typeof RocketPreloadLinksConfig&&new n(new RocketBrowserCompatibilityChecker({capture:!0,passive:!0}),RocketPreloadLinksConfig).init()}}]),n}();t.run(); }()); /* ]]> */ </script> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/wp-content/themes/news-vibrant-pro/assets/js/navigation.js?ver=1731557387" id="news-vibrant-navigation-js" data-rocket-defer defer></script> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/wp-content/themes/news-vibrant-pro/assets/library/sticky/jquery.sticky.js?ver=1731557387" id="jquery-sticky-js"></script> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/wp-content/themes/news-vibrant-pro/assets/library/sticky/sticky-setting.js?ver=1731557387" id="nv-sticky-menu-setting-js" data-rocket-defer defer></script> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/wp-content/themes/news-vibrant-pro/assets/js/skip-link-focus-fix.js?ver=1731557387" id="news-vibrant-skip-link-focus-fix-js" data-rocket-defer defer></script> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/wp-content/themes/news-vibrant-pro/assets/library/stickysidebar/theia-sticky-sidebar.js?ver=1731557387" id="theia-sticky-sidebar-js" data-rocket-defer defer></script> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/wp-content/themes/news-vibrant-pro/assets/js/nv-combine-scripts.js?ver=1731557387" id="nv-combine-scripts-js" data-rocket-defer defer></script> <script type="text/javascript" src="https://kit.fontawesome.com/b9da6f1400.js?ver=6.6.1" id="fontawesome-js" data-rocket-defer defer></script> <script type="text/javascript" src="https://make.co/wp-content/universal-assets/v2/js/min/universal-auth0.min.js?ver=1.0.765" id="universal-auth0-js"></script> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/wp-content/universal-assets/v2/js/min/universal.min.js?ver=1731557387" id="universal-js" data-rocket-defer defer></script> <script type="text/javascript" src="https://makezine.com/wp-content/themes/makezine/js/min/built-libs.min.js?ver=1.0.765" id="built-scripts-js" data-rocket-defer defer></script> <script type="text/javascript" id="misc-scripts-js-extra"> /* <![CDATA[ */ var ajax_object = {"ajax_url":"https:\/\/makezine.com\/wp-admin\/admin-ajax.php","home_url":"https:\/\/makezine.com","logout_nonce":"bccea724c5"}; /* ]]> */ </script> <script type="text/javascript" src="https://makezine.com/wp-content/themes/makezine/js/min/scripts.min.js?ver=1.0.765" id="misc-scripts-js" data-rocket-defer defer></script> <script type="text/javascript" src="https://makezine.com/wp-content/plugins/search-filter-pro/public/assets/js/select2.min.js?ver=6.6.1" id="select2-js" data-rocket-defer defer></script> <script type="text/javascript" defer src="https://makezine.com/wp-content/plugins/youtube-embed-plus-pro/scripts/fitvids.min.js?ver=14.2.1.2" id="__ytprefsfitvids__-js"></script> <script type="text/javascript" src="https://stats.wp.com/e-202447.js" id="jetpack-stats-js" data-wp-strategy="defer" data-rocket-defer defer></script> <script type="text/javascript" id="jetpack-stats-js-after"> /* <![CDATA[ */ _stq = window._stq || []; _stq.push([ "view", JSON.parse("{\"v\":\"ext\",\"blog\":\"179013238\",\"post\":\"568464\",\"tz\":\"-8\",\"srv\":\"makezine.com\",\"j\":\"1:13.9.1\"}") ]); _stq.push([ "clickTrackerInit", "179013238", "568464" ]); /* ]]> */ </script> <script type="text/javascript" src="https://makezine.com/wp-content/plugins/elementor-pro/assets/js/webpack-pro.runtime.min.js?ver=3.25.2" id="elementor-pro-webpack-runtime-js" data-rocket-defer defer></script> <script type="text/javascript" src="https://makezine.com/wp-content/plugins/elementor/assets/js/webpack.runtime.min.js?ver=3.25.4" id="elementor-webpack-runtime-js" data-rocket-defer defer></script> <script type="text/javascript" src="https://makezine.com/wp-content/plugins/elementor/assets/js/frontend-modules.min.js?ver=3.25.4" id="elementor-frontend-modules-js" data-rocket-defer defer></script> <script data-minify="1" type="text/javascript" src="https://makezine.com/wp-content/cache/min/1/c/6.6.1/wp-includes/js/dist/hooks.min.js?ver=1731557387" id="wp-hooks-js"></script> <script type="text/javascript" src="https://c0.wp.com/c/6.6.1/wp-includes/js/dist/i18n.min.js" id="wp-i18n-js"></script> <script type="text/javascript" id="wp-i18n-js-after"> /* <![CDATA[ */ wp.i18n.setLocaleData( { 'text direction\u0004ltr': [ 'ltr' ] } ); /* ]]> */ </script> <script type="text/javascript" id="elementor-pro-frontend-js-before"> /* <![CDATA[ */ var ElementorProFrontendConfig = {"ajaxurl":"https:\/\/makezine.com\/wp-admin\/admin-ajax.php","nonce":"6c54b184d1","urls":{"assets":"https:\/\/makezine.com\/wp-content\/plugins\/elementor-pro\/assets\/","rest":"https:\/\/makezine.com\/wp-json\/"},"settings":{"lazy_load_background_images":true},"popup":{"hasPopUps":true},"shareButtonsNetworks":{"facebook":{"title":"Facebook","has_counter":true},"twitter":{"title":"Twitter"},"linkedin":{"title":"LinkedIn","has_counter":true},"pinterest":{"title":"Pinterest","has_counter":true},"reddit":{"title":"Reddit","has_counter":true},"vk":{"title":"VK","has_counter":true},"odnoklassniki":{"title":"OK","has_counter":true},"tumblr":{"title":"Tumblr"},"digg":{"title":"Digg"},"skype":{"title":"Skype"},"stumbleupon":{"title":"StumbleUpon","has_counter":true},"mix":{"title":"Mix"},"telegram":{"title":"Telegram"},"pocket":{"title":"Pocket","has_counter":true},"xing":{"title":"XING","has_counter":true},"whatsapp":{"title":"WhatsApp"},"email":{"title":"Email"},"print":{"title":"Print"},"x-twitter":{"title":"X"},"threads":{"title":"Threads"}},"facebook_sdk":{"lang":"en_US","app_id":"805939602930860"},"lottie":{"defaultAnimationUrl":"https:\/\/makezine.com\/wp-content\/plugins\/elementor-pro\/modules\/lottie\/assets\/animations\/default.json"}}; /* ]]> */ </script> <script type="text/javascript" src="https://makezine.com/wp-content/plugins/elementor-pro/assets/js/frontend.min.js?ver=3.25.2" id="elementor-pro-frontend-js" data-rocket-defer defer></script> <script type="text/javascript" id="elementor-frontend-js-before"> /* <![CDATA[ */ var elementorFrontendConfig = {"environmentMode":{"edit":false,"wpPreview":false,"isScriptDebug":false},"i18n":{"shareOnFacebook":"Share on Facebook","shareOnTwitter":"Share on Twitter","pinIt":"Pin it","download":"Download","downloadImage":"Download image","fullscreen":"Fullscreen","zoom":"Zoom","share":"Share","playVideo":"Play Video","previous":"Previous","next":"Next","close":"Close","a11yCarouselWrapperAriaLabel":"Carousel | Horizontal scrolling: Arrow Left & Right","a11yCarouselPrevSlideMessage":"Previous slide","a11yCarouselNextSlideMessage":"Next slide","a11yCarouselFirstSlideMessage":"This is the first slide","a11yCarouselLastSlideMessage":"This is the last slide","a11yCarouselPaginationBulletMessage":"Go to slide"},"is_rtl":false,"breakpoints":{"xs":0,"sm":480,"md":768,"lg":1025,"xl":1440,"xxl":1600},"responsive":{"breakpoints":{"mobile":{"label":"Mobile Portrait","value":767,"default_value":767,"direction":"max","is_enabled":true},"mobile_extra":{"label":"Mobile Landscape","value":880,"default_value":880,"direction":"max","is_enabled":false},"tablet":{"label":"Tablet Portrait","value":1024,"default_value":1024,"direction":"max","is_enabled":true},"tablet_extra":{"label":"Tablet Landscape","value":1200,"default_value":1200,"direction":"max","is_enabled":false},"laptop":{"label":"Laptop","value":1366,"default_value":1366,"direction":"max","is_enabled":false},"widescreen":{"label":"Widescreen","value":2400,"default_value":2400,"direction":"min","is_enabled":false}},"hasCustomBreakpoints":false},"version":"3.25.4","is_static":false,"experimentalFeatures":{"e_font_icon_svg":true,"additional_custom_breakpoints":true,"container":true,"e_swiper_latest":true,"e_nested_atomic_repeaters":true,"e_optimized_control_loading":true,"e_onboarding":true,"e_css_smooth_scroll":true,"theme_builder_v2":true,"home_screen":true,"landing-pages":true,"nested-elements":true,"editor_v2":true,"link-in-bio":true,"floating-buttons":true},"urls":{"assets":"https:\/\/makezine.com\/wp-content\/plugins\/elementor\/assets\/","ajaxurl":"https:\/\/makezine.com\/wp-admin\/admin-ajax.php","uploadUrl":"https:\/\/makezine.com\/wp-content\/uploads"},"nonces":{"floatingButtonsClickTracking":"7bd7d5858b"},"swiperClass":"swiper","settings":{"page":[],"editorPreferences":[]},"kit":{"active_breakpoints":["viewport_mobile","viewport_tablet"],"global_image_lightbox":"yes","lightbox_enable_counter":"yes","lightbox_enable_fullscreen":"yes","lightbox_enable_zoom":"yes","lightbox_enable_share":"yes","lightbox_title_src":"title","lightbox_description_src":"description"},"post":{"id":568464,"title":"Hey%20Robot%21%20Build%20Your%20Own%20AI%20Companion%20-%20Make%3A","excerpt":"Chat with and command your own embedded-AI companion bot using local LLMs.","featuredImage":"https:\/\/i0.wp.com\/makezine.com\/wp-content\/uploads\/2024\/10\/dk-digit-02-Large.jpg?fit=640%2C360&ssl=1"}}; /* ]]> */ </script> <script type="text/javascript" src="https://makezine.com/wp-content/plugins/elementor/assets/js/frontend.min.js?ver=3.25.4" id="elementor-frontend-js" data-rocket-defer defer></script> <script type="text/javascript" src="https://makezine.com/wp-content/plugins/elementor-pro/assets/js/elements-handlers.min.js?ver=3.25.2" id="pro-elements-handlers-js" data-rocket-defer defer></script> <script>window.lazyLoadOptions=[{elements_selector:"img[data-lazy-src],.rocket-lazyload,iframe[data-lazy-src]",data_src:"lazy-src",data_srcset:"lazy-srcset",data_sizes:"lazy-sizes",class_loading:"lazyloading",class_loaded:"lazyloaded",threshold:300,callback_loaded:function(element){if(element.tagName==="IFRAME"&&element.dataset.rocketLazyload=="fitvidscompatible"){if(element.classList.contains("lazyloaded")){if(typeof window.jQuery!="undefined"){if(jQuery.fn.fitVids){jQuery(element).parent().fitVids()}}}}}},{elements_selector:".rocket-lazyload",data_src:"lazy-src",data_srcset:"lazy-srcset",data_sizes:"lazy-sizes",class_loading:"lazyloading",class_loaded:"lazyloaded",threshold:300,}];window.addEventListener('LazyLoad::Initialized',function(e){var lazyLoadInstance=e.detail.instance;if(window.MutationObserver){var observer=new MutationObserver(function(mutations){var image_count=0;var iframe_count=0;var rocketlazy_count=0;mutations.forEach(function(mutation){for(var i=0;i<mutation.addedNodes.length;i++){if(typeof mutation.addedNodes[i].getElementsByTagName!=='function'){continue} if(typeof mutation.addedNodes[i].getElementsByClassName!=='function'){continue} images=mutation.addedNodes[i].getElementsByTagName('img');is_image=mutation.addedNodes[i].tagName=="IMG";iframes=mutation.addedNodes[i].getElementsByTagName('iframe');is_iframe=mutation.addedNodes[i].tagName=="IFRAME";rocket_lazy=mutation.addedNodes[i].getElementsByClassName('rocket-lazyload');image_count+=images.length;iframe_count+=iframes.length;rocketlazy_count+=rocket_lazy.length;if(is_image){image_count+=1} if(is_iframe){iframe_count+=1}}});if(image_count>0||iframe_count>0||rocketlazy_count>0){lazyLoadInstance.update()}});var b=document.getElementsByTagName("body")[0];var config={childList:!0,subtree:!0};observer.observe(b,config)}},!1)</script><script data-no-minify="1" async src="https://makezine.com/wp-content/plugins/wp-rocket/assets/js/lazyload/17.8.3/lazyload.min.js"></script><script>function lazyLoadThumb(e,alt,l){var t='<img data-lazy-src="https://i.ytimg.com/vi/ID/hqdefault.jpg" alt="" width="480" height="360"><noscript><img src="https://i.ytimg.com/vi/ID/hqdefault.jpg" alt="" width="480" height="360"></noscript>',a='<button class="play" aria-label="play Youtube video"></button>';if(l){t=t.replace('data-lazy-','');t=t.replace('loading="lazy"','');t=t.replace(/<noscript>.*?<\/noscript>/g,'');}t=t.replace('alt=""','alt="'+alt+'"');return t.replace("ID",e)+a}function lazyLoadYoutubeIframe(){var e=document.createElement("iframe"),t="ID?autoplay=1";t+=0===this.parentNode.dataset.query.length?"":"&"+this.parentNode.dataset.query;e.setAttribute("src",t.replace("ID",this.parentNode.dataset.src)),e.setAttribute("frameborder","0"),e.setAttribute("allowfullscreen","1"),e.setAttribute("allow","accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"),this.parentNode.parentNode.replaceChild(e,this.parentNode)}document.addEventListener("DOMContentLoaded",function(){var exclusions=["avatar","avatar-banner"];var e,t,p,u,l,a=document.getElementsByClassName("rll-youtube-player");for(t=0;t<a.length;t++)(e=document.createElement("div")),(u='https://i.ytimg.com/vi/ID/hqdefault.jpg'),(u=u.replace('ID',a[t].dataset.id)),(l=exclusions.some(exclusion=>u.includes(exclusion))),e.setAttribute("data-id",a[t].dataset.id),e.setAttribute("data-query",a[t].dataset.query),e.setAttribute("data-src",a[t].dataset.src),(e.innerHTML=lazyLoadThumb(a[t].dataset.id,a[t].dataset.alt,l)),a[t].appendChild(e),(p=e.querySelector(".play")),(p.onclick=lazyLoadYoutubeIframe)});</script> <!-- Start Active Campaign Pixel --> <script type="text/javascript"> (function(e,t,o,n,p,r,i){e.visitorGlobalObjectAlias=n;e[e.visitorGlobalObjectAlias]=e[e.visitorGlobalObjectAlias]||function(){(e[e.visitorGlobalObjectAlias].q=e[e.visitorGlobalObjectAlias].q||[]).push(arguments)};e[e.visitorGlobalObjectAlias].l=(new Date).getTime();r=t.createElement("script");r.src=o;r.async=true;i=t.getElementsByTagName("script")[0];i.parentNode.insertBefore(r,i)})(window,document,"https://diffuser-cdn.app-us1.com/diffuser/diffuser.js","vgo"); vgo('setAccount', '1000801328'); vgo('setTrackByDefault', true); vgo('process'); </script> <!-- Start Active Campaign Pixel --> <!-- Start Survey Gizmo Beacon --> <script type="text/javascript"> (function(d,e,j,h,f,c,b){d.SurveyGizmoBeacon=f;d[f]=d[f]||function() {(d[f].q=d[f].q||[]).push(arguments)} ;c=e.createElement(j),b=e.getElementsByTagName(j)[0];c.async=1;c.src=h;b.parentNode.insertBefore(c,b)})(window,document,'script','//d2bnxibecyz4h5.cloudfront.net/runtimejs/intercept/intercept.js','sg_beacon'); sg_beacon('init','Mjg4MjQzLTJiMjdlNGU0NmM3ZDM3YWQ2YWJiOTEwNWRhNDM0ZGQ1NTFlZTdhN2Q3Y2E4Y2M0ZTlh'); </script> <!-- End Survey Gizmo Beacon --> <a href="mailto:feedback@make.co?subject=Makezine.com Feedback" class="btn feedback-btn">FEEDBACK</a> <!-- Next weeks winning lottery ticket number might be 03-14-28-34-45... no promises though. --> <script>"use strict";function wprRemoveCPCSS(){var preload_stylesheets=document.querySelectorAll('link[data-rocket-async="style"][rel="preload"]');if(preload_stylesheets&&0<preload_stylesheets.length)for(var stylesheet_index=0;stylesheet_index<preload_stylesheets.length;stylesheet_index++){var media=preload_stylesheets[stylesheet_index].getAttribute("media")||"all";if(window.matchMedia(media).matches)return void setTimeout(wprRemoveCPCSS,200)}var elem=document.getElementById("rocket-critical-css");elem&&"remove"in elem&&elem.remove()}window.addEventListener?window.addEventListener("load",wprRemoveCPCSS):window.attachEvent&&window.attachEvent("onload",wprRemoveCPCSS);</script><script>class RocketElementorAnimation{constructor(){this.deviceMode=document.createElement("span"),this.deviceMode.id="elementor-device-mode-wpr",this.deviceMode.setAttribute("class","elementor-screen-only"),document.body.appendChild(this.deviceMode)}_detectAnimations(){let t=getComputedStyle(this.deviceMode,":after").content.replace(/"/g,"");this.animationSettingKeys=this._listAnimationSettingsKeys(t),document.querySelectorAll(".elementor-invisible[data-settings]").forEach(t=>{const e=t.getBoundingClientRect();if(e.bottom>=0&&e.top<=window.innerHeight)try{this._animateElement(t)}catch(t){}})}_animateElement(t){const e=JSON.parse(t.dataset.settings),i=e._animation_delay||e.animation_delay||0,n=e[this.animationSettingKeys.find(t=>e[t])];if("none"===n)return void t.classList.remove("elementor-invisible");t.classList.remove(n),this.currentAnimation&&t.classList.remove(this.currentAnimation),this.currentAnimation=n;let s=setTimeout(()=>{t.classList.remove("elementor-invisible"),t.classList.add("animated",n),this._removeAnimationSettings(t,e)},i);window.addEventListener("rocket-startLoading",function(){clearTimeout(s)})}_listAnimationSettingsKeys(t="mobile"){const e=[""];switch(t){case"mobile":e.unshift("_mobile");case"tablet":e.unshift("_tablet");case"desktop":e.unshift("_desktop")}const i=[];return["animation","_animation"].forEach(t=>{e.forEach(e=>{i.push(t+e)})}),i}_removeAnimationSettings(t,e){this._listAnimationSettingsKeys().forEach(t=>delete e[t]),t.dataset.settings=JSON.stringify(e)}static run(){const t=new RocketElementorAnimation;requestAnimationFrame(t._detectAnimations.bind(t))}}document.addEventListener("DOMContentLoaded",RocketElementorAnimation.run);</script><noscript><link data-minify="1" rel='stylesheet' id='jetpack_related-posts-css' href='https://makezine.com/wp-content/cache/min/1/p/jetpack/13.9.1/modules/related-posts/related-posts.css?ver=1731557386' type='text/css' media='all' /><link data-minify="1" rel='stylesheet' id='wp-block-library-css' href='https://makezine.com/wp-content/cache/min/1/c/6.6.1/wp-includes/css/dist/block-library/style.min.css?ver=1731557386' type='text/css' media='all' /><link data-minify="1" rel='stylesheet' id='mediaelement-css' href='https://makezine.com/wp-content/cache/min/1/c/6.6.1/wp-includes/js/mediaelement/mediaelementplayer-legacy.min.css?ver=1731557386' type='text/css' media='all' /><link data-minify="1" rel='stylesheet' id='wp-mediaelement-css' href='https://makezine.com/wp-content/cache/min/1/c/6.6.1/wp-includes/js/mediaelement/wp-mediaelement.min.css?ver=1731557386' type='text/css' media='all' /><link data-minify="1" rel='stylesheet' id='auth0-widget-css' href='https://makezine.com/wp-content/cache/min/1/wp-content/plugins/auth0/assets/css/main.css?ver=1731557386' type='text/css' media='all' /><link rel='stylesheet' id='search-filter-plugin-styles-css' href='https://makezine.com/wp-content/plugins/search-filter-pro/public/assets/css/search-filter.min.css?ver=2.5.19' type='text/css' media='all' /><link data-minify="1" rel='stylesheet' id='nv-style-css' href='https://makezine.com/wp-content/cache/min/1/wp-content/themes/news-vibrant-pro/style.css?ver=1731557386' type='text/css' media='all' /><link data-minify="1" rel='stylesheet' id='news-vibrant-responsive-style-css' href='https://makezine.com/wp-content/cache/min/1/wp-content/themes/news-vibrant-pro/assets/css/nv-responsive.css?ver=1731557386' type='text/css' media='all' /><link rel='stylesheet' id='elementor-frontend-css' href='https://makezine.com/wp-content/plugins/elementor/assets/css/frontend.min.css?ver=3.25.4' type='text/css' media='all' /><link rel='stylesheet' id='widget-image-css' href='https://makezine.com/wp-content/plugins/elementor/assets/css/widget-image.min.css?ver=3.25.4' type='text/css' media='all' /><link rel='stylesheet' id='widget-heading-css' href='https://makezine.com/wp-content/plugins/elementor/assets/css/widget-heading.min.css?ver=3.25.4' type='text/css' media='all' /><link rel='stylesheet' id='widget-countdown-css' href='https://makezine.com/wp-content/plugins/elementor-pro/assets/css/widget-countdown.min.css?ver=3.25.2' type='text/css' media='all' /><link rel='stylesheet' id='e-animation-fadeIn-css' href='https://makezine.com/wp-content/plugins/elementor/assets/lib/animations/styles/fadeIn.min.css?ver=3.25.4' type='text/css' media='all' /><link data-minify="1" rel='stylesheet' id='swiper-css' href='https://makezine.com/wp-content/cache/min/1/wp-content/plugins/elementor/assets/lib/swiper/v8/css/swiper.min.css?ver=1731557386' type='text/css' media='all' /><link rel='stylesheet' id='e-swiper-css' href='https://makezine.com/wp-content/plugins/elementor/assets/css/conditionals/e-swiper.min.css?ver=3.25.4' type='text/css' media='all' /><link rel='stylesheet' id='elementor-post-553223-css' href='https://makezine.com/wp-content/uploads/elementor/css/post-553223.css?ver=1730849814' type='text/css' media='all' /><link rel='stylesheet' id='e-popup-style-css' href='https://makezine.com/wp-content/plugins/elementor-pro/assets/css/conditionals/popup.min.css?ver=3.25.2' type='text/css' media='all' /><link data-minify="1" rel='stylesheet' id='make-elementor-style-css' href='https://makezine.com/wp-content/cache/min/1/wp-content/plugins/make-elementor-widgets/includes/css/style.css?ver=1731557386' type='text/css' media='all' /><link data-minify="1" rel='stylesheet' id='jquery-ui-tabs-css' href='https://makezine.com/wp-content/cache/min/1/ui/1.13.2/themes/base/jquery-ui.css?ver=1731557386' type='text/css' media='all' /><link rel='stylesheet' id='elementor-post-568005-css' href='https://makezine.com/wp-content/uploads/elementor/css/post-568005.css?ver=1730849814' type='text/css' media='all' /><link data-minify="1" rel='stylesheet' id='tablepress-default-css' href='https://makezine.com/wp-content/cache/min/1/wp-content/plugins/tablepress/css/build/default.css?ver=1731557386' type='text/css' media='all' /><link rel='stylesheet' id='bootstrap-css' href='https://makezine.com/wp-content/themes/makezine/css/bootstrap-noglyphicons.min.css?ver=6.6.1' type='text/css' media='all' /><link data-minify="1" rel='stylesheet' id='make-css-css' href='https://makezine.com/wp-content/cache/min/1/wp-content/themes/makezine/css/style.min.css?ver=1731557386' type='text/css' media='all' /><link data-minify="1" rel='stylesheet' id='universal-firstload.css-css' href='https://makezine.com/wp-content/cache/min/1/wp-content/universal-assets/v2/css/universal-firstload.min.css?ver=1731557386' type='text/css' media='all' /><link data-minify="1" rel='stylesheet' id='universal.css-css' href='https://makezine.com/wp-content/cache/min/1/wp-content/universal-assets/v2/css/universal.min.css?ver=1731557386' type='text/css' media='all' /><link rel='stylesheet' id='make-projects-css' href='https://makezine.com/wp-content/themes/makezine/css/style-projects.min.css?ver=1.0.765' type='text/css' media='all' /><link rel='stylesheet' id='__EPYT__style-css' href='https://makezine.com/wp-content/plugins/youtube-embed-plus-pro/styles/ytprefs.min.css?ver=14.2.1.2' type='text/css' media='all' /><link rel='stylesheet' id='__disptype__-css' href='https://makezine.com/wp-content/plugins/youtube-embed-plus-pro/scripts/lity.min.css?ver=14.2.1.2' type='text/css' media='all' /><link rel='stylesheet' id='__dyntype__-css' href='https://makezine.com/wp-content/plugins/youtube-embed-plus-pro/scripts/embdyn.min.css?ver=14.2.1.2' type='text/css' media='all' /><link rel='stylesheet' id='google-fonts-1-css' href='https://fonts.googleapis.com/css?family=Roboto%3A100%2C100italic%2C200%2C200italic%2C300%2C300italic%2C400%2C400italic%2C500%2C500italic%2C600%2C600italic%2C700%2C700italic%2C800%2C800italic%2C900%2C900italic%7CRoboto+Slab%3A100%2C100italic%2C200%2C200italic%2C300%2C300italic%2C400%2C400italic%2C500%2C500italic%2C600%2C600italic%2C700%2C700italic%2C800%2C800italic%2C900%2C900italic&display=auto&ver=6.6.1' type='text/css' media='all' /></noscript></body> </html> <script type="application/ld+json"> { "@context": "https://schema.org", "@type": "HowTo", "name": "Hey Robot! Build Your Own AI Companion", "description": "Chat with and command your own embedded-AI companion bot using local LLMs.","totalTime": "1–3 Hours","step": [{"@type": "HowToStep", "name": "1. Set up the Pi 5 with Ollama", "url": "https://makezine.com/projects/hey-robot-build-your-own-ai-companion/#step1", "itemListElement": [{ "@type": "HowToDirection", "text": "Follow the official Raspberry Pi Getting Started guide to install the latest Raspberry Pi OS (64-bit) and configure your Raspberry Pi. You should use an SD card with at least 16 GB.Once you have booted into your Raspberry Pi, make sure you are connected to the internet and open a terminal window. Enter the following commands to updated the Pi and to install Ollama:$ sudo apt update$ sudo apt upgrade$ curl -fsSL https://ollama.com/install.sh | shNext, start the Ollama service:$ ollama serveYou might see a message that says “Error: listen tcp 127.0.0.1:11434: bind: address already in use.” Ignore this, as it just indicates that Ollama is already running as a service in the background." }]},{"@type": "HowToStep", "name": "2. Try out TinyLlama", "url": "https://makezine.com/projects/hey-robot-build-your-own-ai-companion/#step2", "itemListElement": [{ "@type": "HowToDirection", "text": "Meta’s LLaMa models are almost open source, with some caveats for commercial usage. AI researcher Zhang Peiyuan started the TinyLlama project in September 2023. TinyLlama is a truly open-source (Apache-2.0 license), highly-optimized LLM with only 1.1 billion parameters. It is based on the LLaMa 2 model and can generate responses quite quickly. It’s not as accurate as the newer generation of small LLMs, such as Llama3, but it will run on hobby-level hardware like our Pi 5.Download the latest version of TinyLlama with ollama:$ ollama pull tinyllamaRun an interactive shell to chat with TinyLlama:$ ollama run tinyllamaYou should be presented with a prompt. Try asking the AI a question or have it tell you a joke.Courtesy of Shawn HymelPress Ctrl+D or enter /bye to exit the interactive shell." }],"image": {"@type": "ImageObject","url": "https://makezine.com/wp-content/uploads/2024/10/ollama-pi-01a-Large-750x427.png"}},{"@type": "HowToStep", "name": "3. Set up the Ollama Python package", "url": "https://makezine.com/projects/hey-robot-build-your-own-ai-companion/#step3", "itemListElement": [{ "@type": "HowToDirection", "text": "By default, Ollama runs as a background server and exposes port 11434. You can communicate with that service by making HTTP requests. To make life easier, Ollama maintains a Python library that communicates directly with that locally running service. Create a virtual environment and install the package:$ python -m venv venv-ollama --system-site-packages$ source venv-ollama/bin/activate$ python -m pip install ollama==0.3.3Open a new document:$ nano tinyllama-client.pyEnter the following Python code:import ollama# Settingsprompt = \"You are a helpful assistant. Tell me a joke. \" \ \"Limit your response to 2 sentences or fewer.\"model = \"tinyllama\"# Configure the clientclient = ollama.Client(host=\"http://0.0.0.0:11434\")# The message history is an array of prompts and responsesmessages = [{ \"role\": \"user\", \"content\": prompt}]# Send prompt to Ollama server and save the responseresponse = client.chat( model=model, messages=messages, stream=False)# Print the responseprint(response[\"message\"][\"content\"])Close the file by pressing Ctrl+X, press Y when asked to save the document, and press Enter." }]},{"@type": "HowToStep", "name": "4. Chat with your LLM bot!", "url": "https://makezine.com/projects/hey-robot-build-your-own-ai-companion/#step4", "itemListElement": [{ "@type": "HowToDirection", "text": "Run the Python script by entering:$ python tinyllama-client.pyTinyLlama can take some time to generate a response, especially on a small computer like the Raspberry Pi — 30 seconds or more — but here you are, chatting locally with an AI!Courtesy of Shawn HymelThis should give you a sense of how to run local LLMs on a Raspberry Pi and interact with them using Python. Feel free to try different prompts, save the chat history using the append() method, and build your own voice-activated chatbot." }],"image": {"@type": "ImageObject","url": "https://makezine.com/wp-content/uploads/2024/10/ollama-pi-02a-Large-750x72.png"}},{"@type": "HowToStep", "name": "Local LLM Chatbot with Function Calling", "url": "https://makezine.com/projects/hey-robot-build-your-own-ai-companion/#step5", "itemListElement": [{ "@type": "HowToDirection", "text": "LLMs have traditionally been self-contained models that accept text input and respond with text. In the last couple of years, we’ve seen multimodal LLMs enter the scene, like GPT-4o, that can accept and respond with other forms of media, such as images and videos.But in just the past few months, some LLMs have been granted a powerful new ability — to call arbitrary functions — which opens a huge world of possible AI actions. ChatGPT and Ollama both call this ability tools. To enable such tools, you must define the functions in a Python dictionary and fully describe their use and available parameters. The LLM tries to figure out what you’re asking and maps that request to one of the available tools/functions. We then parse the response before calling the actual function.Let’s demonstrate this concept with a simple function that turns an LED on and off. Connect an LED with a limiting resistor to pin GPIO 17 on your Raspberry Pi 5.Courtesy of Shawn Hymel / FritzingMake sure you’re in the venv-ollama virtual environment we configured earlier and install some dependencies:$ source venv-ollama/bin/activate$ sudo apt update$ sudo apt upgrade$ sudo apt install -y libportaudio2$ python -m pip install ollama==0.3.3 vosk==0.3.45 sounddevice==0.5.0You’ll need to download a new LLM model and the Vosk speech-to-text (STT) model:$ ollama pull allenporter/xlam:1b$ python -c \"from vosk import Model; Model(lang='en-us')\"As this example uses speech-to-text to convey information to the LLM, you will need a USB microphone, such as Adafruit 3367. With the microphone connected, run the following command to discover the USB microphone device number:$ python -c \"import sounddevice; print(sounddevice.query_devices())\"You should see an output such as: 0 USB PnP Sound Device: Audio (hw:2,0), ALSA (1 in, 0 out) 1 pulse, ALSA (32 in, 32 out)* 2 default, ALSA (32 in, 32 out)Note the device number of the USB microphone. In this case, my microphone is device number 0, as given by USB PnP Sound Device. Copy this code to a file named ollama-light-assistant.py on your Raspberry Pi.You can also download this file directly with the command:$ wget https://gist.githubusercontent.com/ShawnHymel/16f1228c92ad0eb9d5fbebbfe296ee6a/raw/6161a9cb38d3f3c4388a82e5e6c6c58a150111cc/ollama-light-assistant.pyOpen the code and change the AUDIO_INPUT_INDEX value to your USB microphone device number. For example, mine would be:AUDIO_INPUT_INDEX = 0Run the code with:$ python ollama-light-assistant.pyYou should see the Vosk STT system boot up and then the script will say “Listening…” At that point, try asking the LLM to “turn the light on.” Because the Pi is not optimized for LLMs, the response could take 30–60 seconds. With some luck, you should see that the led_write function was called, and the LED has turned on!Courtesy of Shawn HymelThe xLAM model is an open-source LLM developed by the SalesForce AI Research team. It is trained and optimized to understand requests rather than necessarily providing text-based answers to questions. The allenporter version has been modified to work with Ollama tools. The 1-billion-parameter model can run on the Raspberry Pi, but as you probably noticed, it is quite slow and misinterprets requests easily.For an LLM that better understands requests, I recommend the Llama3.1:8b model. In the command console, download the model with:$ ollama pull llama3.1:8bNote that the Llama 3.1:8b model is almost 5 GB. If you’re running out of space on your flash storage, you can remove previous models. For example:$ ollama rm tinyllamaIn the code, change:MODEL = \"allenporter/xlam:1b\"to:MODEL = \"llama3.1:8b\"Run the script again. You’ll notice that the model is less picky about the exact phrasing of the request, but it takes much longer to respond — up to 3 minutes on a Raspberry Pi 5 (8GB RAM).When you are done, you can exit the virtual environment with the following command:$ deactivate" }],"image": {"@type": "ImageObject","url": "https://makezine.com/wp-content/uploads/2024/10/raspberry-pi-led-01-Large-750x961.png"}},{"@type": "HowToStep", "name": "A Closer Look at Ollama Tools", "url": "https://makezine.com/projects/hey-robot-build-your-own-ai-companion/#step6", "itemListElement": [{ "@type": "HowToDirection", "text": "Let’s take a moment to discuss how tools work in Ollama. Feel free to open the ollama-light-assistant.py file to follow along.First, you need to define the function you want to call. In our example, we create a simple led_write() function that accepts an led object (as created by the Raspberry Pi gpiozero library) and an integer value: 0 for off, 1 for on.def led_write(led, value): \"\"\" Turn the LED on or off. \"\"\" if int(value) > 0: led.on() print(\"The LED is now on\") else: led.off() print(\"The LED is now off\")The trick is to get the LLM to understand that calling this function is a possibility! Since the LLM does not have direct access to your code, the ollama library acts as an intermediary. By defining a set of tools, the LLM can return one of those tools as a response instead of (or in addition to) its usual text-based answer. This response comes in the form of a JSON or Python dictionary that our code can parse and call the related function.You must define the tools in a list of dictionary objects. As these small LLMs struggle with the concept of an “LED,” we’ll call this a “light.” In our code, we provide the following description of the led_write() function to Ollama:TOOLS = [ { 'type': 'function', 'function': { 'name': \"led_write\", 'description': \"Turn the light off or on\", 'parameters': { 'type': 'object', 'properties': { 'value': { 'type': 'number', 'description': \"The value to write to the light pin \" \ \"to turn it off and on. 0 for off, 1 for on.\", }, }, 'required': ['value'], }, } }]In the send() function, we send our query to the Ollama server running the LLM. This query is captured by the Vosk STT functions and converted to text before being added to the message history buffer msg_history.response = client.chat( model=model, messages=msg_history.get(), tools=TOOLS, stream=False)When we receive the response from the LLM, we check to see if it contains an entry with the key tool_calls. If so, it means the LLM decided to use one of the defined tools! We then need to figure out which tool the LLM intended to use by cycling through all of the returned tool names. If the name led_write is given for one of the tools, which we defined in the original TOOLS dictionary, we call the led_write() function. We provide the function call with the pre-defined led object and argument value that the LLM decided to give.if response['message'].get('tool_calls') is None: print(\"Tools not used.\") returnelse: print(\"Tools used. Calling:\") for tool in response['message']['tool_calls']: print(tool) if tool['function']['name'] == \"led_write\": led_write(led, tool['function']['arguments']['value'])The properties defined in the TOOLS dictionary give the LLM context about the function, such as its use case and the necessary arguments it needs to provide. Think of it like giving an AI agent a form to fill out. The AI will first determine which form to use based on the request (e.g. “control a light”) and then figure out how to fill in the various fields. For example, the value parameter says that the field must be a number and it should be a 0 for “off” and 1 for “on.” The LLM uses these context clues to figure out how to craft an appropriate response." }]}],"supply": [{ "@type": "HowToSupply", "name": "" },{ "@type": "HowToSupply", "name": "Raspberry Pi 5 single-board computer, 8GB RAM or more" },{ "@type": "HowToSupply", "name": "MicroSD card, 16GB or more" },{ "@type": "HowToSupply", "name": "USB microphone such as Adafruit 3367" },{ "@type": "HowToSupply", "name": "Breadboard" },{ "@type": "HowToSupply", "name": "LED" },{ "@type": "HowToSupply", "name": "Resistor, 220Ω to 1kΩ" },{ "@type": "HowToSupply", "name": "Jumper wires" },{ "@type": "HowToSupply", "name": "" }],"tool": [{ "@type": "HowToTool", "name": "" },{ "@type": "HowToTool", "name": "Computer to flash Raspberry Pi OS; not needed afterward" },{ "@type": "HowToTool", "name": "Keyboard, mouse, and monitor connected to Raspberry Pi" },{ "@type": "HowToTool", "name": "Raspberry Pi Imager " },{ "@type": "HowToTool", "name": "Light assistant code " },{ "@type": "HowToTool", "name": "" }]} </script> <!-- This website is like a Rocket, isn't it? Performance optimized by WP Rocket. Learn more: https://wp-rocket.me -->