Categories

Meta

I wanted to design a 3D printable file that would allow me to clamp my acrylic fairings to the cLeg. Luckily Kay and Gabe created a pretty solid model of the cLeg itself so I could use its contours in my design. Again, I had to cut the model down manually in Blender because netfabb does an awful job of exporting STL (hadn’t yet investigated if this is an actual or a free-demo-imposed limitation of the software).

I also used Blender to multiply the scale by 1,000 before importing into Tinkercad.

I like Tinkercad because it makes it super easy to perform boolean functions on complex stuff like our leg here. If you’re a tinkercadder, try ungrouping the model so you can see how I made a cross section of the leg: Tinker This

And I went on to improvise a way to screw two parts together — this is very much a test fit, to see if the idea makes any sense, to see if screwing two plastic pieces on with pressure is enough to keep it from falling off.

I went back and forth about 3D printing holes for nuts and bolts, but decided I would drill it out of the finished plastic — “machining” is way more accurate than printing for this kind of thing.

OK, the original Kinect scan was not very dimensionally accurate…I guess I could have compared measurements of the model with measurements of the object, that’s what I get for trusting technology -.- I can still use the blocks of plastic for practice fitting, though. They don’t clamp around the c-Leg, but I tested screwing the pieces together and drilling into the plastic to insert a brass threaded insert, and with a few taps of a hammer that turned our really nice.

Of course, the chunky tinkercad design isn’t so fashionable, but it served its purpose to confirm that I need to press the shape of the leg more accurately (the front fairing doesn’t sit flush with the printed model at all) and that countersunk M5 screws will do a nice job of securing the fairing to the bracket, though I’ll have to play with melting a countersink so the head of the screw doesn’t stick out the back.

Visiting FabLab Taipei and OpenLab Taipei

Though I griped about Chinese internet censorship, FabLab Taipei was the real reason I hopped on a plane for a detour the last few days of my trip. Their facebook group is always sharing amazing projects and a video I saw at Fab11 of their Maker Faire showed a big, active, and creative community. I messaged the group the day before I arrived but didn’t hear back, so I got in touch the old fashioned way and showed up at their door.

I was greeted by a man named Sega Liu, who was working on his iteration of a fold-up 3D printer. He gave me a tour of the multi-room facility, which was punctuated by a number of surprising projects: incredible corrugated cardboard & resin surfboard (Ah cardboard, always reminds me of home), intricate laser cut wood paneling and an impressive cardboard-folded giant frog mask. The lab was stocked with capable machines, including an assortment of 3D printers, the familiar Roland circuitboard milling machine, and a very heavy duty CNC machine that doesn’t get much use (it runs the unfortunate Roland software, though it accepts plain text serial data not so different from GCode, so perhaps the more modern & open source ChiliPeppr could be modified to control it.) There’s a sizable laser cutter, lots of electronics equipment, and in the basement: a comprehensive wood-shop.

I felt immediately at home in the space, which had a lot in common with CUCFabLab: it is open to the community relatively late at night (every day 6–10PM), has every machine you could possibly need to make awesome stuff, and a lot of the furniture, well, has a hand-me-down feel (which I like better than the try-not-to-scratch-the-table newness of some places. Gives it character 😉

I chatted with Sega about my work back at CUCFabLab. It always surprises people to think FabLabbing could be a full time job. FabLab Taipei, like many hackerspaces, is all volunteer. I told Sega about how CUCFabLab has grown from an all volunteer staff to employing a dozen people at times (though I’ll write another time about the trade-offs in establishing a paid staff among volunteers). At some point in all this he decided that Ted, the main benefactor of the lab, would want to meet me and called him back to the lab (I guess I had just missed him).

Ted told me about the history of the lab, and how they use to have membership fees but eventually switched to free membership after establishing that it was a hard sell and wasn’t helping much with rent anyway. Apparently, Taipei is awash with low-cost designers and prototypers to the point where even university students don’t design things for themselves, they can hire someone to work for them for the price of a typical hackerspace membership. It is an interesting problem in Taiwan as in China, when building things is seen as something of a lower-class occupation: how do you catch people’s interest with the prospect of “Do It Yourself!”

Of course, the premise of a FabLab is to create something new, and in my experience learning to use a machine gives you a lot of ideas about what can be created with it — so if you want to design something (even to have someone else build it), if you want to be innovative, you could start by learning the various styles of fabrication. I think as people’s interest is piqued by the surprising inventions exhibited at Maker Faires and workshops, they will be enticed to try it themselves.

After telling Ted that I was interested in learning about as many maker communities as possible, he said “We better get over to OpenLab then, you can come to FabLab any night but OpenLab is Wednesdays, lets go.”

Exterior of FabLab Taipei, Interior of cab across town.

Ted hailed a cab to take us across town to OpenLab Taipei, past a temple and through narrow corridors. I had just read about this neighborhood earlier that day: an illegal settlement of improvised architecture that the city chose to preserve and transform into a collective of artist studios called Treasure Hill. I was surprised to find out that a hackerspace was nestled among the concrete cubes stacked up here, but it certainly fit in among the artist studios.

The most striking project sitting on the shelf was a 3D printed Immorton Joe mask complete with ribbon cable hairdo. A very DIY shortwave radio built with point-to-point soldering on a copper board was being tuned into Chinese music. Scattered on the table were other projects in progress including a recycled CD drive pen plotter. A pile of vintage diagnostics gear completed the hackerspace aesthetic, and an impressive laser-etched stamp stood ready to print more banners for promoting the space.

We were just here for an hour before people were packing up. Ted and I took the metro one stop to the Shida night market to keep chatting about maker communities. There was some fantastic barbeque chicken (was that cinnamon? Five spice?) and instead of bars in this area there are convenience stores with barstools in a sitting area — kind of neat, you pay convenience store prices for a bar experience. We talked about 3Nod underwriting Fab12 and how Fab Academy would work for a Chinese student body (the material will be translated on a rolling basis and Chinese fab labs will work a few weeks behind English language labs).

The next day I visited the Treasure Hill artist village again, this time in the daylight. It has fantastic art scattered around the open areas and on top of roofs. I peaked into a small cafe called Tadpole Point and saw they had burgers with fried egg on the menu so I put in an order and browsed the art books lining the wall. The room had a great view out the screen door overlooking the interstate and the valley. According to wiki this location was originally fortified for anti-aircraft defense, but it’s a good place to enjoy the scenery, too. With a great burger served on a solid wood butcher block and a breeze through a window of the poured concrete room, I reflected on how cheap materials can be arranged so elegantly, in the case of architecture and for food.

Unfortunately I didn’t get to find out more about the Conductive Ink Experiment nor the More Than Useful Detective Lab.

One Friday night, googling (or, baidu-ing?) for “things to do in Shanghai,” I found out about a hackathon being held the next day: 24 hours using MeteorJS to build a web app. Perfect! I’d built a dirt simple sign-in sheet with NodeJS and Javascript, but my code was already getting messy so I shelved it until I was ready to rewrite it from scratch. The hackathon was just the excuse I needed to try a modern framework (i.e. someone else’s code that does most of the work for you) to rewrite my sign-in sheet for the FabLab’s many machines. And hey, if it’s polished enough, maybe other FabLabs would want to use it, too.

I was finally getting used to Shanghai’s metro system and found the Agora Co-working space without any trouble. It’s a beautiful office with a garden out back and the wifi was the fastest I’d gotten anywhere in China. I liked the place right away.

This was my second hackathon (after the People’s Music School Hack Music) so I was a little more proactive about introducing myself and what I wanted to do. Pretty quickly, a small team assembled around my laser-sign-in sheet project, but it was a bit every-man-for-himself as far as learning MeteorJS goes. We were all there for the same reason, to try out the new framework, but without any kind of guided introduction / classroom situation, we were left to read the docs and getting starter guides, which isn’t really a group project.

But after a couple hours, I felt like I was learning a lot and my teammembers felt they had worked through enough of the tutorials that were ready to work on something together, but then we were all new at collaborative coding, too! Especially for a one-page app, it’s difficult to divvy up the work. We didn’t figure that out until after an hour of learning to use github (another good learning experience, though, cloning and committing and all that, that’s definitely a good thing to work through with other people in the same room instead of just reading a getting started guide.) Once we could finally push and clone each other’s code we arrived at the question of how to split up the work. We all took a stab at creating a good foundation to work up from, but were all using our own preferred approaches and stepped on each others feet when we tried to merge our ideas together, so when were getting settled in after dinner and my team members asked what we should work on, I said:

“I want to suggest that we all do whatever we want to”

And that worked out pretty well. A sign in sheet is a simple enough app that we could all write it from scratch, and this way we could experiment with the approach that interested us instead of trying to come to agreement on what tools to use together. So from then on out we worked on our own thing, snacked in the kitchen on occasion, and put on our headphones to focus whenever we wanted, and I think we all had a good time. I stayed up late and slept on that giant beanbag in the first picture.

In the morning I showed my progress to a few guys (it works, but it doesn’t have a way of saving the data or reseting each day, yet), but had to bid them farewell before the end of the Hackathon to get across town for the Shanghai Maker Carnival. It was great to find some friends in such a big city and feel like I was on a programming team (however dysfunctional) for a day.

NodeJS, Client Side Javascript, and Google Speech API

This section of the tutorial introduces “client side javascript” — running code alongside HTML in a web browser. We won’t be building a beautiful site. Instead, I’m going to introduce as little as possible to get results so you can move onto controlling lamps and motors and other internet-connected-things. Hopefully you can combine this with your own knowledge or other tutorials to build the application you want.

At this point you should have two files, a server.js and an index.html sitting in the same directory.

For this part, we’ll just be working with index.html, so you could simply point your web browser to C:/your/file/path/index.html and it will work fine, but why not get in the habit of starting your node server? You’ll see changes to index.html reflected when you refresh the page either way.

The history of HTML is a jumbled one with many actors. Lots of people were taking stabs at building websites and lots of people were writing web browsers that did their best to render a useable website from everyone else’s code. The modern day result of this is that the web browser is a very forgiving platform that lets you leave all kinds of stuff out, and lets mistakes go without complaining too much. That’s actually one reason why I’ve heard some people discourage javascript as a first programming language: you can make a lot of mistakes and there’s not a compiler to tell you what you did wrong, the web browser will try to run anything it can and ignore whatever doesn’t work.

Use the “Inspect element” to find out how Chrome interpreted our 4 lines of HTML:

Our file only contained <h1> tags and the <script> tags. <html>,<head>, <body>, and this mysterious “#shadow-root” were all added by the web browser before rendering. On top of that, in the bottom-center there’s styling added on to the <h1> element: all of this display: block; font-size: 2em; -webkit-margin-before etc. is added by Chrome to make our barebones HTML code look presentable. So like I said, you can leave a lot out and modern web browsers will figure out how to render your page anyway.

OK, I promised an interactive web page, so let’s change that header <h1> into a button <button>. If you don’t know: in lots of text editors Ctrl+H will bring up a “find and replace” menu. We’ll also add an “id” attribute inside the opening button tag: this is a name you give individual elements so you can write javascript that acts (or listens to) those elements.

Here, ‘onclick’ listens to that ‘myButton’ element, ready to react to a click at any moment. This is different than, for instance, programming an Arduino, where we’d have to check whether a button is pressed continuously in an infinite loop. Instead, we can write a function that executes only in response to the web browser noticing that the user clicked their mouse while hovering over the button element. This is “Event driven programming.” (You actually can do event driven programming with Arduino, if you know about hardware interrupts.)

While chaining those identifiers and functions all together on one line works OK, programming like that quickly gets hard to read. It’s much better practice to break it into pieces.

Create a function called speak, which calls on the alert function to say hi.

Attach the ‘onclick’ event listener to the button variable and assign the function named ‘speak’ as its action.

I included two ways you could create the speak function here that would work equivelantlly in this case. There are specific cases where you should choose one or the other that involve global vs local scope (great info on the subject here), but for now it’s just important to know that there’s more than one way to do it. Hopefully keeping that in mind will make reading other people’s javascript examples less confusing.

Buttons default to ‘block-inline’ style, and appear on the same line

Let’s move on to a button that changes the background — this will set us up for turning a lamp on and off. The buttons have separate IDs, and each button is assigned to a new javascript variable.

By the way, you don’t have to have a button element to be able to click on it. I like the look of h1 better, so I’ll just click on those. I’ll change the color style of the h1 elements with each click as well. (side effect: button elements default to a block-inline style whereas header elements default to block style)

Recommended Reading:

Note: “Handling Events” recommends using ‘addEventListener’ instead of ‘onclick’, which is a better way to do it. Onclick events are limited to one-per-element, whereas you can ‘addEventListeners’ as much as you want. But for a simple example I like the syntax of .onclick better.

NodeJS, Client Side Javascript, and Google Speech API

This series will introduce newcomers to web programming using a few of the latest tools available. I’ve dabbled in building web sites since Microsoft Frontpage 2003 came out, but always ran into frustrating inconsistiences (casualties of the browser wars) and intimidating combinations of programming languages to start a server and handle user interactions (PHP, AJAX, HTTP POST and GET, yuck).

Recently I’d been hearing a lot about Node.js, software for building web servers with javascript. When it was introduced at JSConf in 2009, it received a standing ovation. When was the last time you heard of a new technology receiving a standing ovation? With all of the hype surrounding NodeJS, I decided to dabble again and was swept off my feet by the fact that I only have to know one language. Javascript is used to create the web server, and javascript is used to make the web page interactive. With added libraries, we can use javascript to control lights, relays, and motors with the use of Arduino, Raspberry Pi, Galileo, and others, and we can use the relatively new HTML5 web speech components to control all that hardware with voice commands!

Part 1 of this tutorial will walk you through installing the bare minimum on a Windows system (linux and MacOS instructions will come later) and serve up a ‘hello world’ HTML page.

Part 2 will introduce client side javascript — that is, programs that run in a user’s web browser to make the page interactive. We’ll start with a button that changes the background color.

Parts 1 and 2 could be switched, you could start with html and then learn how to start the server, as long as you do both before part 3.

Part 3 will use the excellent Johnny-Five library (meant for programming robots with javascript) to allow our webserver to control an Arduino. It could just as easily control the GPIO of a Rapsberry Pi, BeagleBone, or Galileo. Socket.IO will be uesd to send messages from the client to the server.

Part 4 adds voice control to the mix, explaining how to use the Annyang library to execute javascript functions (and therefore control attached hardware) within the web browser. I’ll also cover creating an SSL certificate here so the browser listens continuously without timing out.

Part 5 moves all of this functionality to the Galileo platform, which can run our web server and interface directly with other hardware, via digital I/O and serial communication.

Without further ado:

Install the Basics

Visit the official NodeJS website and download the latest. I’ll be using 4.2.2, hopefully they won’t change too much by the time you read this.

Pick out a good text editor: I’ll use Komodo Edit because it’s open source and lets me use Vi keybindings, but Notepad++ and Sublime Text are popular. Any of these will give you helpful features like syntax highlighting and auto-completion which make programming a million times more pleasant than trying to use notepad.

Go through the Next →Accept →Next →Next →OK →OK →Finish rigamarole of Windows installations to get NodeJS installed.

Next we’re going to do a javascript hello world. NodeJS is simply a program that executes javascript files. We’ll write a command in a javascript file, and tell NodeJS to run that file for us. This first program is just one line of code:

console.log("Hello World");

Type that into your text editor, and save it as something like ‘firsttry.js’ or anything you want as long as it has that .js file extension.

Next, open Powershell (you can hit start and just type ‘powershell’ and hit enter). This is a program you might never have touched, but it comes with Windows and has a lot of powerful features — it’s how we’ll control the webserver. But first, try a few commands, see what ls, cd, and pwd do. They stand for List, Change Directory, and Print Working Directory.

Once you’ve navigated to the folder where you saved your first js file, you can type node followed by the filename. This uses NodeJS to execute firsttry.js, which simply prints “Hello World” to the console — another word for the command line. We’ll use console.log() a lot, it can give status messages from the server running in the command line, and it can also give status messages in the web browser, which has its own console we’ll see later.

So that’s a pretty boring program, but it’s important to make sure that ‘hello world’ works if we expect to run a web server on our machine.

Of course, there are whole books written on and whole careers based off writing and running web servers. For our purposes, I want to provide this working model: a web server is a program that listens for requests, and fulfills certain requests however you tell it to. The ‘listening for requests’ is mostly handled for us, we just have to write code to respond to them.

The NodeJS documentation provides dozens of functions for this purpose, but doesn’t give a simple example. I’ll use a stripped-down example from this awesome instructable to get us started. You could copy paste this example code into your editor, but I recommend typing it in yourself to spend some quality time with each component.

If you haven’t coded much, this is a little crazy, but thankfully we don’t have to come up with this ourselves. This chunk of code actually handles quite a lot: it uses require() to import or include the ‘http’ and ‘fs’ (short for filesystem) features of nodejs. It creates a server object and starts listening on port 80. It answers any request by sending index.html back, and delivers a nice error message if it has any trouble.

To get your first website up and running, save this javascript file, and create another file that contains nothing but the phrase “hello world.” Or, if you want to work ahead:

<h1> Hello World! </h1>

console.log("Hello Console!")

Save that file as index.html in the same directory as simpleserver.js and go back to Powershell. Remember how to use node to execute a file? Try it on the javascript file containing the web server code.

The very first time you run javascript code that creates a server, you’ll get the following message (unless you have Windows Firewall disabled):

Make sure “Private networks” is checkmarked before clicking Allow!

I checked Private and Public, since I want to try serving webpages on networks besides my own. Windows will only ask you once! If you don’t allow both networks now, it’s a bit of a pain to change the settings later.

Once you allow NodeJS to communicate, you can open a web browser and try it: just type in ‘localhost’ in the address bar.

If you added that console.log(“Hello Console”), you get to check out the web browser’s console. That line of code executes inside Chrome and writes its message to Chrome’s console, found in the Inspect element menu. We’ll use this a lot later on, so now’s a good time to find it.

That’s all for part one. Next up is writing our own javascript (don’t worry, it won’t be as complicated as the server function, at least at first 😉

Windows 7/8/10

Download and Install

Adding ffmpeg to your ‘PATH’

Add ffmpeg to your path so it can be executed anywhere. There will be only cosmetic differences between Windows 7 and Windows 10.

I found that one one version of Windows I was unable to edit the path if I simply hit Start and searched for “system environment variables” — instead I had to open the dialog via System (control panel) and then click “Advanced System Settings” and then “Environment Variables”. I guess by clicking on the ‘Advanced system settings’ with the little security icon it gives me the admin privilege I need to change the settings.

After clicking “Environment Variables…” You’ll get a list of user variables and a list of system variables. Scroll through the System variables until you find “Path” and click Edit, you’ll get the “Edit System Variable” dialog. Here each folder containing executables is listed in the format C:foobar;C:foobar; — that is, full file path, ending in a backslash, seperated by semicolons. So we’ll add our ffmpeg folder extracted from the 7z file, specifically, its bin folder. I dropped the whole thing in to my C drive, renamed the long folder name to just ‘ffmpeg’ and added the following to my ‘Variable Value’ (highlighted in the screenshot). The backslash at the end is important.

;C:ffmpegbin

After OK OK OKing out of there, you should be able to start powershell and start ffmpeg from anywhere. if you get the following when typing ffmpeg into powershell, then everything worked!

This stackoverflow discussion was helpful in figuring out how to do screen capture on Windows. I ran the following command to grab my Powershell window at 10 frames per second and saving to the file out2.mov. Here is the official documentation which details a few options.

From Kinect scan to laser cutting

Opened the original scan in Blender, selected the portion of the scan we’re concerned with. Separated it from the rest of the mesh and exported as stl.

Used Netfabb to repair the mesh and cut into a top and bottom portion.

Found out netfabb decimates the mesh upon export, from 27000 triangles to 24000 triangles, and manages to make it pretty rough, so it looks like this in 123D Make.

Inspected the files before and after repairing in Netfabb…

Used MeshLab’s Filters → Remeshing → Surface Reconstruction to “Shrinkwrap” the model and fill in gaps and holes without losing the smoothness of the scan.

Used this guide to split the part in two using Blender’s newish “Bisect” function.

Played around with different options in 123D Make…

Drew a circle in Blender against the scanned cLeg and stool, confirmed that the units of the scan are in meters. (The circle is .355 units wide and in real life the stools are too.) But, since many programs interpret these STL units as mm, our objects are 1000 times too small. Let’s scale them up.

Settled on a slicing pattern in 123D Make. Used the Modify Form feature to hollow out the leg and picked out the Radial Slices construction technique. The arrangement has some collisions at the bottom, but I don’t want a closed model anyway, so will do some hand-tuning in Inkscape. Exported the model to Blender to check that the cLeg would sit inside it okay.

Using Inkscape to layout the the pieces onto less than 4 sheets of plywood… (nesting is apparantly a difficult problem for computers, and not one that many softwares implement, certainly not free ones. just have to eyeball it)

123D Make is sadistic and exports the objects as groups of thousands of lines instead of a single vector, so editing the exported PDF is really really slow. (It takes 20 seconds to select a text object and type in a new number. I counted.) Learned things:

On the left: the highlighted list of numbers 4,000 characters long describes a single path. On the right side, two coordinates of a single line segment are surrounded by markup. The file containing 2 objects takes 73 lines of text. The file exported by 123D Make takes up 6151 lines of text for the same object. Inkscape modifies this information in memory every time you move something.

Inkscape operates with SVG, which is plain text, ASCII, one character equals one byte. When a path is exported as 677 individual paths, each one of those line segments has 8 lines of markup surrounding it in the SVG file (between the g tags, with information for position and stroke and fill attributes). So what could be saved (and manipulated in memory) as 20 bytes if it was appended to the list of nodes in a single path instead takes 389 bytes to be kept in memory as a standalone object.

I found this forum post describing how to select all the separate objects, Path → Combine them into a single object, and in node edit mode you can select all nodes and click Join Selected Nodes and it simply merges overlapping nodes. Hallelujah!

So to downsize the files enough that they’re not a pain to work with:

Open the PDF. I learned that if you check the “import via Poppler” option Inkscape can detect the colors of the stroke (otherwise imported PDFs have “undefined” color unless you adjust it yourself). So check that box. CtrlA, CtrlU to ungroup everything. Click a blue line segment. Edit →Select Same →Stroke Color. Path →Combine. F2 (Edit Paths by Node). CtrlA. Wait for a minute. Join Selected Nodes (one of the buttons in the node edit toolbar, 3rd from the left, just after the delete node button. It might take a few minutes for Inkscape to chew on this one. It will probably become unresponsive. Let it do its thing. In my case this trimmed the file size by 97% and I could then translate and rotate and rearrange the objects without any lag.

Two hours later…have my minified cut file, fitting on 1.5 sheets instead of 4. I’ve trimmed the tops and bottoms off the vertical slices so the end result will be open.

20 minutes of lasering + 10 minutes of assembling: Hey I made a thing!

Met up with Shawna and learned the design constraints: how the leg has to move, what areas can’t be covered, etc. We picked out a pattern she wouldn’t mind having wrapped around her leg:

I took a few measurements of the wooden positives and drew the outer shape of the fairing in inkscape by hand (using auto-smooth of course!). A few booleans later I had my cut file, which took about 20 minutes apiece. To get the part ready to shape against the mold, I stuck it in our convection oven to bake at 300F for about 5 minutes (don’t worry, we keep one oven for circuit boards and plastics and a different oven for foods 🙂

So the process was: semi-soften the plastic in the oven, then roughly fold it over the wooden form, then stick the whole wooden form in the oven. If you let it soften all the way when it’s sitting on the metal it’ll stick to the metal. Better to have it roughly on the wood form when it reaches maximum droopiness. When it’s as soft as rubber, we take it out and push the plastic against the form, holding it in place as it cools.

I’m pretty happy with the second prototype. I think the next step is 3D printing some bracket system, and maybe taking more time to plan out how the plastic will fold against the form — this was pretty heavily eyeballed.

Camping in Anji (安吉县) at the regional Burning Man

So that happened. A surprise opportunity to see what the Chinese interpretation of Burning Man would look like, for less than 100USD, tent & bus ticket included. Duh.

My friend had basically been camping at Xin Che Jian anyway, and he jumped at the opportunity to take the early bus out to volunteer and set up, which I’m a little jealous of, cause he got to build stuff. I woke up early the next day to make my way downtown to catch a bus. Unfortunately, I was feeling groggy when I descended to the subway platform during morning rush hour, and saw people stuffing themselves like sardines onto the southbound train and I thought to myself “Whoa. Good thing I don’t have to get on that train.” and took the path of least resistance onto the nearly empty northbound train. I took me 2 stops to realize I was going away from downtown when I had the opportunity to transfer to another equally stuffed train. I didn’t see how I would squeeze my full pack of luggage on and calculated that I probably wouldn’t make it in time anyway. The end of the line was called “Meilan Lake” and I thought that sounded nice so I just stayed on the roomy, quiet, wrong train.

Luckily I looked at a map (for once) to see that there wasn’t actually a lake anywhere near the Meilan Lake stop and got off at one of the University stops instead. I wandered around campus, trying to enjoy the streams and the sun and hoping I would run into something interesting, but ended up just heading back to Xin Che Jian after a half hour. The whole time I had a backup plan, of course: there would be a 7pm bus, and I had the feeling they would honor my bus ticket regardless.

Woman in native American headdress in Shanghai, telling people “Get the fuck on the bus” at once playfully and sternly. Chinese twenty-something in what I called “that hat people wear in rice fields” and she called “yeah, an asian hat.” carrying 40L of water. Sycamore trees in the French Concession.

Later in the afternoon, after killing time installing a different linux on my laptop (hooray! everything works on debian right away! ❤ debian) I decided to walk the mile and a half to the bus pickup spot, strangely enough an Australian sports bar. I later eavesdropped “there’s just not that many places in Shanghai to park a bus.”

So I meet my fellow burners. I shouldn’t have been too surprised but it was about 80% expats. People working in Shanghai from Copenhagen, Ireland, Canada, U.K. and so on. We shared some food, stood around while the luggage was loaded onto the buses. The ticket-taker couldn’t find my name on the list (since I bought a ticket for a different time) so she made me pinky-swear that I didn’t counterfeit my ticket and let me on the bus.

I picked a seat to myself, only now remembering that I have a hard time starting a conversation with someone without already having a reason.

I hadn’t slept much, and having just walked 2 miles with 30 pounds of stuff, I submitted to my exhaustion and closed my eyes for the first half hour of being on the bus. I tried to nap, ignoring the noise and the music of a bus on its way to a party in the forest, but eventually I opened my eyes to see the Chinese billboards and illuminated LED skyscrapers and was struck by the improbability and novelty of my rolling through Shanghai to the soundtrack of 1970s American Funk being played on a portable loudspeaker.

I decided that maybe it was a good thing I wasn’t talking to anyone, I could focus on the strange scenery out the window — the sprawling city and far off, inexplicable bright lights. At one point there was what looked like a half of a donut sticking out of the ground on the horizon, lit up like a televsion. I still have no idea what it was. Maybe it was just a giant, donut-shaped televison, maybe they have those here.

Eventually, though, the Canadian girl sitting by herself behind me tapped my shoulder, asking if I was travelling alone, and I traded in my excess legroom for a conversation partner. I told her about my work at FabLab and she told me about how she got a teaching job in Tripoli right out of college, owing to her double degree in History and Psychology. She says the job market wasn’t looking good for people who could only teach one thing, so she buckled down and double majored. She taught in Libya during a relatively peaceful period a year ago, but was evacuated soon after she started hearing gunshots at night aimed at her apartment bloc. Luckily, her contract was up soon anyway and she lined up a teaching job at one of the international (a.k.a. private) schools in Shanghai. I asked her about the curriculum difference between public schools and private schools, how China’s role in WWII was represented differently and the kids in private school were taught from U.K. textbooks. I wondered what conversations about history looked like between kids who had different educations, but she wasn’t around for that.

So of course I knew this bus was full of interesting people to talk to, you don’t get on a bus from Shanghai to a Burning Man by sitting at home all day, but still I couldn’t help but keep to myself. I tell myself that I have enough ideas I haven’t done anything about, and meeting people will just fill my head with new ideas before I’m done with any old ones. I know that’s dumb, I’m just rationalizing my introversion.

Anyway, this happened:

Pulled over in the middle of nowhere.

“Why did we stop? Did we lose the other bus?”

A few minutes go by.

“Does anyone know how to get to the campground?”

“Oh nooo, we’re the lost bus.”

“While we’re at it, does anyone on board know how to fly a plane? And also know how to get to the campground?”

My ‘VIP’ tent on the left, the more communal tent city on the right. There was food getting cooked in the tent city. You live, you learn.

But we made it, rolling up to a forest glowing bright green at half past midnight. People lined up to check in, renting tents and accepting the garbage bags being handed to each person. I opted to pay the extra ten bucks to rent a tent that was already set up on a platform so I could get right to dancing. That ended up being just a so-so decision, tho, since these ‘VIP’ tents were on a different part of the campground than everyone else. Not only was it removed from the easy community that comes with having a dozen people living a couple meters away from you, it was a lot closer to the main stage and the loudspeakers, which is pretty VIP until you want to sleep. In the morning when I was looking for a water kettle to cook my cup of noodles, I saw campers gathered in the walkways with propane hot plates and lots of finger food and again kicked myself for paying extra to stay at the top of the hill. I suppose I could have joined them, but I didn’t think I had much to offer and in general feel like I’m being rude if I insert myself into someone else’s situation.

Before I found out that I was going to be an introvert for the whole weekend, though, I did dance my butt off til 4am. I started recording the music just after that before crawling into my tent, too bad the recorder died after 7 minutes, the music played until noon. That was the most surreal part of the whole thing, waking up to gray light and looking out my tent to see a foggy forest at what I guessed was about 7am with like 8 people still dancing. Actually being able to lounge in my tent and watch the dance field was pretty cool, though.

I went back to bed, no longer phased by nonstop bass arpeggios. Actually I think it had an airplane-jet-engine-drone effect on me, where just the constant loudness lulls me to sleep. I’m pretty sure I woke up the second time when the music stopped, out of a confused “something’s different, what’s going on” kind of reaction to the quiet.

With the sun back in the sky, a few people stretching turned into an impromptu yoga class as people woke up and copied what the especially-stretchy guy was doing. We would follow him from one stretch to another, everyone laughing at themselves for not getting half as far into the stretch as our accidental class-leader.

More buses of people showed up, bringing the campground total to somewhere between 100–150 burners. People made art, offered their juggling clubs to people who wanted to try, and talked to each other during the quiet afternoon before the next DJ was scheduled. There was an awful lot of smoke circles that I didn’t want to participate in, so I felt put off from making friends, though in retrospect there were enough people sitting out that it wasn’t a good reason to keep to myself. I think what’s really happening with me is that I feel bad about not maintaining my existing relationships better, I know I leave people hanging a lot, maybe say ‘see you soon’ and never make plans. I imagine I’m doing a disservice to someone to introduce myself and make new friends knowing I won’t answer their messages either. It takes energy to reach out to people, and maybe I’m greedy with whatever energy I have, taking it for myself. I’m still trying to figure out how much I want to change that.

When I did want to socialize, though, there was a really great sunlit cabin beside the tent city and the dance field. The elongated honeycomb framing the windows overlooking the lake was really beautiful. The table was a giant slab of a single tree, 20 feet long and 4 feet wide, mounted on sawed off tree trunks. Really nice place to sit and boil water and chat. The regional’s organizer told stories of Burning Man back in the 90s, before they had rules about firearms, for instance. His old photos from the playa were strewn about the table, along with his choice comic books and various revolutionary propaganda. I borrowed a copy of Debord’s Society of the Spectacle and fell asleep in a hammock.

The next morning I noticed a ‘Moka Pot Coffee Workshop (free coffee)’ on the schedule and made sure to be back at the cabin at 10am sharp. Had a really pleasant time sitting with people from all over the world exchanging coffee rituals. The Italian running the ‘workshop’ showed us how his grandmother whipped sugar and a drop of coffee into a foam. We struggled to find cups and found out PET has a pretty low melting point. I figured out I have a much better time with people who are waking up on stimulants than people passing around narcotics.

That’s about all I have to report. It was loud, I slept a lot, the mountains are really pretty, I actually don’t have a lot of fun at parties. Had a great conversation concerning how you learn a lot about yourself when travelling just because you’re always putting yourself in new situations, and you get to see how you react to it. I react to lots of things by sleeping.

After getting FFMPEG installed, let’s try it out on a MOV downloaded from my google photos account:

ffmpeg -i MVI_6654.MOV firsttry.gif

We’re calling the ffmpeg program and telling it that MVI_6654.MOV is our input file with the -i flag. the filename at the end defines the conversion and creates the new file, resulting in:

Pretty cool. But I bet I can make it loop nicely by just using the first few seconds, so we use the duration flag, -t and specify the duration in seconds.

ffmpeg -t 2 -i MVI_6654.MOV secondtry.gif

So it loops! kinda slow tho, maybe we can drop every other frame? A-ha. Thanks to the -r flag, we can choose a frame rate for the output (note that these options do different things based on their order. -t is used before the -i input, -r is used after the input, so it affects the output.)

ffmpeg -t 2 -i MVI_6654.MOV -r “15” thirdtry.gif

That’s more like it. As an added benefit, the file is now 2 megabytes instead of 8 megabytes. I’ve got another one to convert that has kind of a long input video, so I’m going to specify a time to start the gif as well as the duration. The -ss flag defines the starting point. Oh yeah, and your seconds can be decimals. If you have a longer video and want to define the starting position in hours, minutes, seconds, you can use “hh:mm:ss” format, like “00:00:03” instead of “3”

ffmpeg -t 3 -ss 0.5 -i MVI_6663.MOV -r “15” fourthtry.gif

This has been pretty simple, but I know I’ve seen better looking gifs. Let’s find out how to make it look more like a video…

You should recognize what -ss, -t, and -i do here, -vf is a way to invoke filters on our video. so we can describe fps and scale here. Hm. I’ll admit I don’t know what -1 does. But the flags describe what algorithm to use, more info in that blog. So that generates palette.png which we can use in our 2nd line in terminal (by the way, the backslash at the end of the line is if you run out of space and need to keep typing, hit backslash and return and you can keep going on a new line before hitting return to complete the command.)

This uses our .MOV as an input but has a second -i flag to use palette.png as a 2nd input. Then, ok, I copy pasted the rest of it, but I’m happy enough with what this produces that I’ll stop asking questions 😀

Let me know if there’s anything I can explain in more detail, but don’t ask me for help installing things, just google it!

Side by side comparison of easy, default color palettes and head-scratching custom color palettes

I’d like to revisit this with more general advice and showing off other aspects of ffmpeg, but in the meantime here’s articles that others’ found helpful.

This tutorial will allow you to play short samples (less than four seconds) from an Arduino with no extra hardware. It is based off the work of MIT group “high-low tech” and uses all free software. It will futher explain how to trigger the sound using sensors. It is generously translated into Chinese by Chris Zhang at Shanghai hackerspace Xin Che Jian:

You can either open an existing file with Audacity, or record a new one, which is what Chris did to create our ghost sound. Freesound.org is a great website to download other people’s recordings. Try it out! Use the record, stop, and play icons at the top left of the program.

When deciding what sound to use, we have to consider the very small memory of Arduino — 32kB for our program + our audio. Audacity has a “resample” ability so our sound takes up less memory. In the bottom left corner, change the project rate from 44000 to 8000. Then in the Tracks menu, select Resample, and hit OK.

When powering a speaker directly from the Arduino, it won’t be very loud. In Audacity, if your sound waves aren’t very tall (low volume, low amplitude), it’s useful to use the Normalize effect. This boosts your levels as high as possible without clipping (overpowering the speaker resulting in distorted sound). Select Effect →Normalize and set the amplitude to zero before hitting OK.

In the Export menu, you’ll have the option to change the file format. This is typically the difference between mp3, wav, and flac, etc. but we’re using a more uncommon file type, so in that menu choose “Other uncompressed files” and click options. Choose WAV (microsoft) as your header , and Unsigned 8 bit PCM as the Encoding.

This results in a very small .wav file that we can finally convert to store on the Arduino. The conversion program is written in Processing so for now it requires Java. Run “EncodeAudio”, which simply asks you to select that wav file you just exported. The results are stored on your clipboard, waiting to be pasted. We’re ready to open Arduino and save the file to memory.

Open the Arduino IDE and add the PCM library downloaded above. Open File →Examples →PCM →playback. It should look like this:

That long list of integers is the example sound, we can replace it with the list of integers that resulted from Encode Audio. Triple-click on any of the numbers to highlight the entire line (thousands of numbers long) and use ctrl-v or cmd-v to paste our own sound.

Upload this code and the sound will play on a speaker connected to pin 11 and GND. You can either use a tiny speaker like in the doorbell tutorial, or if you have speakers with a headphone jack, wire it up like so:

GND gets attached to the tip, pin 11 can be attached to either (or both!) of the remaining silver bands. Be sure to start with the volume on your speakers turned way down, this will play full blast! Also probably don’t do this to your nice stereo cause I’m not sure if it’s safe, I just know it works.

With the current code, the sound will play once when the Arduino turns on: you can hit the ‘reset’ button on the circuitboard to play it again.

The simplest trigger possible is touching two wires together to connect GND to a sensor pin. In our loop we constantly check if our sensor pin is ‘LOW’ and if it is, we start the sound. So cut the ‘startplayback’ function from inside the setup and paste it inside a conditional statement in the loop, using digitalRead() to check if it’s connected to ground. To make sure it doesn’t go off when no one is at the door, we use the internal pull up resistor using pinMode(). This is our final code for using a simple switch to trigger a single sound.

Notice that I changed the name of the array from ‘sample’ to ‘ghost’ — be sure to change the name in the startPlayback function as well — it’s used twice.

You’re not limited to this, of course! You can have as many different sounds as will fit on memory (so 4 seconds total) but trigger them at different times. Copy-paste that ‘constant unsigned char sample[] PROGMEM’ code and give different names to different lists of numbers. You can also use an external pullup resistor of 1 megaohm (the built-in one is only 10k) to make it touch sensitive instead of having to touch two wires together. Connect the megaohm resistor between the sensor pin (A0) and 5V. Delete the pinMode function from the setup.

The following code uses booleans to play a different sound each time the sensor is touched. This one includes our ghost sounds, so you can upload this and try it yourself. Megaohm resistor between A0 and 5V, speaker on pin 11 and GND.