|Hand tools and fabrication machines:|
Our chosen community for this assignment was the competitive AFX dance team community at UC Berkeley. We interviewed two dancers from this community about their involvement in AFX, their typical practice sessions, their likes and dislikes, and especially their freestyle circles. We learned that freestyle circles don't happy that often, maybe once or twice in the beginning of the semester. And when they do freestyle, the dancers are reluctant and shy to show their skills. But freestyle circles were recognized as an important practice arena and dancers were inspired by watching other people dance. Another dislike about the AFX community was how big it was and how hard it was to meet people due to this. So, our focus was on freestyle circles and how to encourage shy people to participate and foster a closer community in AFX.
Our initial ideas were to make an object that could be passed to the next freestyler's during freestyle circles. But there was the issue of holding something during dancing was awkward. So we decided on maybe a wearable mask, this way shy dancers might be more inclined to participate. The question then was how to make this mask different from any store bought mask. We played around with the idea that maybe it could vibrate when that dancer's turn was over or shine brighter the louder people cheered.
Then we thought of another idea: maybe a device that could record someone dancing to a song for a set amount of seconds, then passing this device to someone else who dances to the next part of the song and so on until the song is over, after which the device creates a music video of all these dancing clips and uploads them to the Internet. Because this seemed like such a daunting feat, we decided to keep the mask as a back up plan.
Originally we used a usb webcam connected to the raspberry pi. To control the usb webcam we used the OpenCV library to capture footage. However, as we added more processes to run concurrently, the raspberry pi struggled to process the commands. In order to reduce strain on the cpu we changed cameras to a raspberry pi camera module. The camera module is not supported by OpenCV, so we rewrote the recording script to execute a subprocess call using the command line raspivid.
Once the videos are collected they are concatenated using FFMPEG. FFMPEG is a command line software which joins a list of videos with a song and outputs a new video file. Using subprocess we execute it through the python script.
After creating a music video the raspberry pi uploads a video to youtube with the python script youtube-upload, provided by github.com/tokland. The video is then processed on a youtube channel to be viewed.
For the visual design, we chose a simple interface with one button -- the most straightforward and simple option. Our priorities in designing the casing was to (1) protect the hardware, (2) show users only what they need to see, and (3) create a sleek look that fits the aesthetics of dance groups like AFX. We lasercut black acrylic for the casing with openings in the front panel custom tailored for the speaker, camera, and LED indicator, and we included a temporary back door panel for us to access the hardware during demos. (In the final version, the back panel would also be sealed.)
We also made a logo to add a little playfulness to Groovecube's sleek look and cut vinyl stickers with it.
Because Groovecube needs protection from scratches when being passed from dancer to dancer, and because we wanted a place to include simple instructions and a QR code to access the completed music video, we made packaging that echoes our logo design. Although the one-button interface seems like it wouldn't require instructions, we realize that not everyone is familiar with the blinking light countdown that most camera self-timers use. So we didn't want any confusion about what the LED was indicating. This packaging prototype uses lasercut poster paper and vinyl sticker, but future iterations would be made of sturdier cardboard with more economical print instead of labor-intensive sticker. (It took 8 hours, most of which was weeding the letters and QR code.)
In conclusion, if we had more time, we would have iterated on making the box expand to a wider target user group. Initially, we only thought this box can be tailored towards serious dancers like the ones on AFX Competition team we interviewed. However, through our user testing and observations, we realized, anyone, not only dancers, can enjoy the Groovecube. In addition, instead of having it an always moving object to be passed from person to person, another option would be to set it in a popular location (perhaps Lower Sproul where dance groups often practice) to use as a photobooth-like object. In the future, we would like users to be able to use whatever song they like and maybe use a screen to display information such as counting down, song choice, how many minutes left in song, how many seconds in your song segment, and so on. We would also like a website where everyone could upload their videos to their own accounts. Dance groups or co-owners could also customize their Groovecubes with different colors or stickers. Finally, another future iteration idea was that multiple cubes from different locations can join together to make a music video, maybe even an international music video with a blend of different dance styles and cultures!
import numpy as test_video import cv2 import time import os import subprocess import RPi.GPIO as GPIO ## Import GPIO Library import pygame import threading from picamera.array import PiRGBArray from picamera import PiCamera ###CODE TO BLINK LIGHT BEFORE RECORD ## Define function named Blink() def Blink(): print "blink start" GPIO.setmode(GPIO.BOARD) ## Use BOARD pin numbering GPIO.setup(7, GPIO.OUT) ## Setup GPIO pin 7 to OUT #might have to debug this because haven't tested GPIO.output(7, True) time.sleep(1) GPIO.output(7, False) time.sleep(1) #0 second for i in range(0, 2): GPIO.output(7, True) time.sleep(0.5) GPIO.output(7, False) time.sleep(0.5) #4 second for i in range(0, 8): GPIO.output(7, True) time.sleep(0.125) GPIO.output(7, False) time.sleep(0.125) GPIO.output(7, True) #5 second print "blink end" #PLAY AUDIO CLIP def play_audio(clip_to_play): print 'play audio start' pygame.mixer.init() pygame.mixer.music.load(clip_to_play) pygame.mixer.music.play() while pygame.mixer.music.get_busy() == True: continue #put the one we just played in a folder old_dest = directory + '/' + clip_to_play new_dest = directory + '/played/' + clip_to_play os.rename(old_dest, new_dest) #do i need this to be the correct directory? print 'play audio end' ###CODE FROM ORIGINAL START.PY TO RECORD SET LENGTH OF VIDEO def record_video(): time.sleep(5) timestamp = time.time() stop_time = timestamp + 20 record = "raspivid -o test" + str(timestamp) + ".avi -t 20000" subprocess.call(record, shell=True) print "recording started" while True: GPIO.output(7, True) ## Turn on GPIO pin 7 if time.time() >= stop_time: GPIO.output(7, False) ## Turn on GPIO pin 7 GPIO.cleanup() print "stopped recording" break #BEGIN CONCAT CODE def concat_middle(videofiles): i = 0 x = '' while i < len(videofiles): x += videofiles[i] + '|' i += 1 return x[0:-1] # output,error = subprocess.Popen( # command, universal_newlines=True, shell=True, # stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() def create_video(): print "begin concat" directory = '/home/pi/Desktop/cp1' videofiles = [n for n in os.listdir(directory) if n=='t' and n[-4:]=='.avi'] command_start = 'ffmpeg -i "concat:' #command_end = '" -i hotline.m4a -c copy out' + str(timestamp) + '.avi' command_end = '" -i hotline_short.m4a -c copy out' + '.avi' command = command_start + concat_middle(videofiles) + command_end print command # subprocess.call(command, shell=True) output,error = subprocess.Popen( command, universal_newlines=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() print "end concat" ###UPLOADING TO YOUTUBE FUNCTION def upload_vid(): #print 'sleeping' #time.sleep(100) print "begin upload" youtube_up = "youtube-upload --title='Groove Cube' /home/pi/Desktop/cp1/out.avi" subprocess.call(youtube_up, shell=True) print "end upload" ###CODE TO RESPOND TO BUTTON PRESS GPIO.setmode(GPIO.BOARD) GPIO.setup(11, GPIO.IN, pull_up_down=GPIO.PUD_UP) while True: input_state = GPIO.input(11) if input_state == False: #do some sort of subprocess.call(something) print('Button Pressed') GPIO.cleanup() break ###END BUTTON PRESS CODE threads =  directory = '/home/pi/Desktop/cp1' audiofiles = [int(n) for n in os.listdir(directory) if n=='h' and n[-4:]=='.mp3'] audiofiles.sort() #play lowest numbered first if len(audiofiles) > 0: clip_to_play = 'hb' + str(audiofiles) + '.mp3' threads.append(threading.Thread(target=Blink)) threads.append(threading.Thread(target=play_audio, args=(clip_to_play,))) threads.append(threading.Thread(target=record_video)) map(lambda x: x.start(), threads) audiofiles.remove(audiofiles) print audiofiles #below should run after everything if len(audiofiles) == 0: time.sleep(26) create_video() upload_vid() for vid in videofiles: os.remove(directory + '/' + vid) print 'vids moved back' os.remove(directory + '/' + 'out.avi') played_directory = directory + '/played/' move_back = [n for n in os.listdir(played_directory) if n=='h' and n[-4:]=='.mp3'] for m in move_back: os.rename(played_directory + m, directory + '/' + m) print move_back
Did you replicate this project? Share it!I made one
Love this project? Think it could be improved? Tell us what you think!