EvilRuxpin – The Chippy Ruxpin Alternative – Hacking a Teddy Ruxpin with Next Thing Co. C.H.I.P $9 Linux Computer to Play Heavy Metal
So, I modified a Chippy Ruxpin into a more ‘evil’ form as a gift for a coworker.
1. Build a Chippy Ruxpin out of a C.H.I.P. and an old Teddy Ruxpin
2. Make it evil. Make it say random evil scary things every few minutes, and make the eyes glow red with an LED
3. Make it wifi. It is now ad-hoc so no keyboard is needed. Smartphone controllable!
4. Add DHCP server, so your smartphone can connect and pull an IP, so you can load the web gui over wifi
5. Add an 3W stereo audio amplifier. Stock ruxpin speaker + CHIP audio is kinda wimpy. DC 5V PAM8403 Audio Stereo Amplifier Board Volume Control Class D Kit Module
6. Add a big battery, maybe a 5w solar panel to charge the battery.
7. put a heavy metal t shirt on Teddy.
8. option to play stored heavy metal .mp3’s using mplayer in linux, controllable on the webgui page from a smartphone.
I chose Blackened by Metallica as the first Heavy Metal song played thru a Teddy Ruxpin ever in the history of the Earth. Yes my Teddy Ruxpin plays Metallica in stereo on command via wifi from my smartphone.
Dont’ forget to put an .mp3 file in /home/chip/Desktop/m.mp3. Obviously we are going to change this to play many many metal .mp3’s. ‘Cause that’s rad. Teddy Ruxpin Metal Beats Pill. If only I could figure out how to make the mouth/eyes move while mplayer plays an .mp3…………hmmmmmmmmmmmmmm
9. do it all as a boot script so no user input is needed after power on.
I’ve done it! (except the LED/GPIO part)
More to come! to do:
to do: integrate amazon echo hack, so that replys move the mouth and eyes of Ruxpin.
So, here are the basic steps (updates to come):
–flash CHIP with 4.3 headless. 4.4 wifi? doesn’t seem to work even if you modify the GPIO variables in the .py script.
–enable a wifi connection, apt-get update and apt-get upgrade
–install all the chippy crap from the link below
sudo apt-get install python-setuptools python-dev build-essential espeak alsa-utils sudo apt-get install python-alsaaudio python-numpy python-twitter python-bottle mplayer
-get chippy working
–apt-get install isc-dhcp-server, again see link below
–apt-get install bc , this lets ./battery.sh work, so you can monitory your LiPo 3.7v battery from linux
–apt install wireless-tools (this step may break your normal wifi managed mode connection setup. its ad-hoc w no internet from here out, so if you want to install more software from the internet, do it before this step)
edit /etc/NetworkManager/NetworkManager.conf:
wired device not managed
Most probably your interface appears in /etc/network/interfaces. By default, NetworkManager does not manage interfaces that appear in /etc/network/interfaces. You can change this behaviour.
To do this – in a terminal:
sudo nano /etc/NetworkManager/NetworkManager.conf
change the line managed=false to managed=true
Save, stop and start network manager:
sudo service network-manager restart
-configure that bitch /etc/dhcp/dhcp.conf
-configure /etc/network something/ interfaces to use 192.168.1.66 ip and dns, see links below
-configure wlan0 to always use 192.168.1.66 because we are evil
-config wlan0 as ad-hoc wifi on channel 6 see just below this
-config /etc/rc.local to do all this crap at boot, no login needed to turn on wifi and dhcp, and python script
edit /etc/network/interfaces make the ip 192.168.1.66 cause we are evil:
source-directory /etc/network/interfaces.d
auto wlan0
iface wlan0 inet static
address 192.168.1.66
netmask 255.255.255.0
gateway 192.168.1.1
edit /etc/rc.local code:
iwconfig wlan0 mode ad-hoc channel 6 essid “EvilRuxpin”
ifconfig wlan0 up 192.168.1.66
sudo service isc-dhcp-server start
cd ChippyRuxpin cause i installed under root
python /root/ChippyRuxpin/chippyRuxpin.py
sample /etc/dhcp/dhcp.conf code for ez ip’s baby:
option domain-name “Evil.Ruxpin”
default-lease-time 600;
max-lease-time 7200;
authoritative;
subnet 192.168.1.0 netmask 255.255.255.0 {
range 192.168.1.10 192.168.1.20;
option subnet-mask 255.255.255.0;
option routers 192.168.1.66;
option domain-name-servers 192.168.1.66;
}
after a editing /etc/rc.local, /etc/network/interfaces and /etc/dhcp/dhcp.conf, reboot.
once booted up, you should be able to connect to ad-hoc wifi “EvilRuxpin”
it should serve up a DHCP address between 192.168.1.10-20.
goto http://192.168.1.66:8080 or 80
page should load
note: my stupid dell laptop would not connect to the ad-hoc wifi, but my iphone 5s would.
Resources:
Chippy Ruxpin:
https://github.com/NextThingCo/ChippyRuxpin/blob/experimental/chippyRuxpin.py
http://makezine.com/projects/chippy-ruxpin/
http://www.dreeyoreshospital.net/Teddy_Ruxpin-fix-1.html
Pinouts H Bridge
http://espeak.sourceforge.net/voices.html
https://www.hackster.io/LagunaComputer/evil-ruxpin-a7afc6
C.H.I.P wifi adhoc/dhcp server:
https://bbs.nextthing.co/t/does-c-h-i-ps-wireless-radio-supports-adhoc-mode/3425/10
https://wiki.debian.org/NetworkConfiguration
http://www.binarytides.com/disable-ipv6-ubuntu/
http://askubuntu.com/questions/71159/network-manager-says-device-not-managed
https://wiki.debian.org/DHCP_Server
Amazon Echo Hack for CHIP(to do!):
http://sammachin.com/the-10-echo/
Next Thing Co CHIP GPIO:
https://github.com/xtacocorex/CHIP_IO
http://docs.getchip.com/chip.html#physical-connectors
https://bbs.nextthing.co/t/programming-with-gpio/2110/7
https://github.com/connornishijima/chipGPIO
http://docs.getchip.com/chip.html#gpio
https://bbs.nextthing.co/t/adafruit-gpio-library-for-chip/2696/5
CHIP Linux misc:
http://serverfault.com/questions/727943/auto-root-login-in-linux-servers
http://stackoverflow.com/questions/11421399/how-to-fix-bad-interpreter-error-when-using-yum
https://bbs.nextthing.co/t/configure-vnc-without-display/1334/5
3.7v lipo battery
battery.sh python-run-external-command-and-get-output/
chippyRuxpin.py:
#!/usr/bin/python
# Chippy Ruxpin by Next Thing Co
# Powered by C.H.I.P., the world's first $9 computer!
# apt-get install python-setuptools python-dev build-essential espeak alsa-utils
# apt-get install python-alsaaudio python-numpy python-twitter python-bottle mplayer
# IMPORTANT NOTE ABOUT TWITTER STUFF!
# In order to retrieve tweets, you need to authorize this code to use your twitter account.
# This involves obtaining some special tokens that are specific to you.
# Please visit Twitter’s website to obtain this information and put the values in the variables below.
# For more information, visit this URL:
# https://dev.twitter.com/oauth/overview/application-owner-access-tokens
consumerKey=’INSERT YOUR CONSUMER KEY HERE FROM TWITTER’
consumerSecret=’INSERT YOUR CONSUMER SECRET HERE FROM TWITTER’
accessTokenKey=’INSERT YOUR ACCESS TOKEN KEY HERE FROM TWITTER’
accessTokenSecret=’INSERT YOUR ACCESS TOKEN SECRET HERE FROM TWITTER’
import sys
import time
import subprocess
import os
from random import randint
from threading import Thread
from chippyRuxpin_audioPlayer import AudioPlayer
from chippyRuxpin_gpio import GPIO
from chippyRuxpin_twitter import ChippyTwitter
from chippyRuxpin_webFramework import WebFramework
fullMsg = “”
MOUTH_OPEN = 408 # GPIO pin assigned to open the mouth. XIO-P0
MOUTH_CLOSE = 412 # GPIO pin assigned to close the mouth. XIO-P2
EYES_OPEN = 410 # GPIO pin assigned to open the eyes. XIO-P4
EYES_CLOSE = 414 # GPIO pin assigned to close the eyes. XIO-P6
io = GPIO() #Establish connection to our GPIO pins.
io.setup( MOUTH_OPEN )
io.setup( EYES_OPEN )
io.setup( MOUTH_CLOSE )
io.setup( EYES_CLOSE )
print(“start”)
audio = None
wasRunning = False
isRunning = True
print(“isRunning t”)
rcount = 0
def updateMouth():
print(“def updateMouth”)
lastMouthEvent = 0
lastMouthEventTime = 0
while( audio == None ):
time.sleep( 0.1 )
print(“while audio none”)
while isRunning:
if( audio.mouthValue != lastMouthEvent ):
lastMouthEvent = audio.mouthValue
lastMouthEventTime = time.time()
if( audio.mouthValue == 1 ):
io.set( MOUTH_OPEN, 1 )
io.set( MOUTH_CLOSE, 0 )
else:
io.set( MOUTH_OPEN, 0 )
io.set( MOUTH_CLOSE, 1 )
else:
if( time.time() – lastMouthEventTime > 0.4 ):
io.set( MOUTH_OPEN, 0 )
io.set( MOUTH_CLOSE, 0 )
# A routine for blinking the eyes in a semi-random fashion.
def updateEyes():
print(“def updateEyes”)
while isRunning:
print(“before updateEyes”)
io.set( EYES_CLOSE, 1 )
io.set( EYES_OPEN, 0 )
time.sleep(0.6)
print(“io updateEyes”)
io.set( EYES_CLOSE, 0 )
io.set( EYES_OPEN, 1 )
time.sleep(0.6)
#io.set( EYES_CLOSE, 1 )
#io.set( EYES_OPEN, 0 )
#time.sleep(0.2)
io.set( EYES_CLOSE, 0 )
io.set( EYES_OPEN, 0 )
time.sleep( randint( 0,1) )
print(“while updateEyes”)
#rtalk()
#wasRunning=True
def rtalk():
while isRunning:
#cmd = “sudo sh -c ‘echo 1 > /sys/class/gpio/gpio412/value'”
#subprocess.Popen(cmd,shell=True, stdout=subprocess.PIPE)
time.sleep(1)
global rcount
myTextIndex = 1
rcount = rcount + 1
myTextIndex = ( randint( 0,2) )
print(myTextIndex)
print(rcount)
if rcount >= 60:
#myTextIndex == 0
if myTextIndex == 0:
myText = “hello fucker!”
elif myTextIndex == 1:
myText = “I can hear you Adam. I know you are talking about me. You don’t want to make me angry ”
elif myTextIndex == 2:
myText = “Hey! give me the pipe back”
else:
myText = ‘single quotes this is option 4’
#return MyText
rcount = 0
talk(myText)
def talk(myText):
print(“talk”)
global rcount
rcount = 0
if( myText.find( “playmetal” ) >= 0 ):
myText += “0”
myText = myText[7:-1]
cmd = “mplayer /home/chip/Desktop/m.mp3”
subprocess.Popen(cmd,shell=True, stdout=subprocess.PIPE)
#try:
# myText = twitter.getTweet( myText )
#except:
# print( “!!!ERROR: INVALID TWITTER CREDENTIALS. Please read README.md for instructions.”)
return
os.system( “espeak \”,…\” 2>/dev/null” ) # Sometimes the beginning of audio can get cut off. Insert silence.
time.sleep( 0.5 )
subprocess.call([“espeak”, “-w”, “speech.wav”, myText, “-s”, “130”])
audio.play(“speech.wav”)
#audio.play(“m.mp3”)
# cmd = “mplayer /home/chip/Desktop/m.mp3”
# subprocess.call(cmd,shell=True, stdout=subprocess.PIPE)
#cmd = “mplayer /home/chip/Desktop/m.mp3”
#subprocess.Popen(cmd,shell=True, stdout=subprocess.PIPE)
#cmd = “sudo echo 0 > /sys/class/gpio/gpio408/value”
#subprocess.call(cmd,shell=True, stdout=subprocess.PIPE)
print(“done talking”)
return myText
rtalk
#os.system( “sudo axp209 –no_limit” )
mouthThread = Thread(target=updateMouth)
mouthThread.start()
eyesThread = Thread(target=updateEyes)
eyesThread.start()
rtalkThread = Thread(target=rtalk)
rtalkThread.start()
print(“started aand played”)
audio = AudioPlayer()
if( consumerKey.find( ‘TWITTER’ ) >= 0 ):
print( “WARNING: INVALID TWITTER CREDENTIALS. Please read README.md for instructions.” )
else:
twitter = ChippyTwitter(consumerKey,consumerSecret,accessTokenKey,accessTokenSecret)
print(“def userinput”)
def userInput():
print(“start userinput”)
time.sleep(6)
while isRunning:
user_input = raw_input(“some input:”)
talk(user_input)
print(“while userinput”)
print(“userinput thread”)
inputThread = Thread(target=userInput)
inputThread.start()
print(“webframe”)
web = WebFramework(talk)
print(“webframe done”)
isRunning = False
print(“isrunning false”)
io.cleanup()
print(“io cleanup”)
sys.exit(1)
chippyRuxpin-webFramework.py:
#!/usr/bin/env python
#
# Chippy Ruxpin by Next Thing Co 2015
# Powered by C.H.I.P., the world's first $9 computer!
from bottle import run, get, post, request, route, redirect
import socket
preset1=”Hello Adam, would you like to hear some Heavy Metal?”
preset2=”Hello Adam, would you like to hear some Heavy Metal?”
print(“web start”)
class WebFramework:
def __init__(self,func):
self.ip = [(s.connect((‘192.168.1.66’, 80)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]
print( “———“)
print( “CHIPPY RUXPIN IS ONLINE!”)
print( “In your browser, go to ” + str(self.ip) + “:8080”)
print( “———“)
self.talkFunc = func
@route(‘/’)
def index():
return ”’
”’
@post(‘/’)
def speak():
speech = request.forms.get(‘speech’)
self.talkFunc( speech )
redirect(‘/’)
print(“def speak”)
run(host=self.ip, port=8080, debug=True)
this part of the code does not format well in wordpress . it is:
LESS THAN SYMBOL form action=”/” method=”post” GREATER THAN SYMBOL
preset11: LESS THAN SYMBOL input name=”speech” type=”text” size=”96″ value=”one of these days, _ _ _ _ I am going to kill that fucking cat'” / GREATER THAN SYMBOL
LESS THAN SYMBOL input value=”Go!” type=”submit” / GREATER THAN SYMBOL
chippyRuxpin_audioPlayer.py:
#!/usr/bin/env python
#
# Chippy Ruxpin by Next Thing Co 2015
# Powered by C.H.I.P., the world's first $9 computer!
#!/usr/bin/env python
#
import alsaaudio as aa
import audioop
from time import sleep
import struct
import math
import array
import numpy as np
import wave
import os
import subprocess
class AudioPlayer:
def __init__(self):
subprocess.Popen(‘amixer cset numid=1 100%’ ,shell=True, stdout=subprocess.PIPE ) # Set PA mixer volume to 100%
subprocess.Popen(‘amixer cset numid=2 2’ ,shell=True, stdout=subprocess.PIPE ) # Set right mixer to be “right” (2)
subprocess.Popen(‘amixer cset numid=3 1’ ,shell=True, stdout=subprocess.PIPE ) # Set left mixer to be “left” (1)
subprocess.Popen(‘amixer cset numid=4 1′ ,shell=True, stdout=subprocess.PIPE ) # Set DAC self.output to be “Direct” (2… or 1 for “Mixed” if you prefer)
self.prevAudiovalue = 0
self.mouthValue = 0
def play(self,fileName):
# Initialise matrix
matrix=[0,0,0,0,0,0,0,0]
# Set up audio
wavfile = wave.open(fileName,’r’)
chunk = 1024
output = aa.PCM(aa.PCM_PLAYBACK, aa.PCM_NORMAL)
output.setchannels(1)
output.setrate(22050)
output.setformat(aa.PCM_FORMAT_S16_LE)
output.setperiodsize(chunk)
data = wavfile.readframes(chunk)
try:
while data!=”:
output.write(data)
# Split channel data and find maximum volume
channel_l=audioop.tomono(data, 2, 1.0, 0.0)
channel_r=audioop.tomono(data, 2, 0.0, 1.0)
max_vol_factor =5000
max_l = audioop.max(channel_l,2)/max_vol_factor
max_r = audioop.max(channel_r,2)/max_vol_factor
for i in range (1,8):
self.generateMouthSignal((1<<max_r)-1)
data = wavfile.readframes(chunk)
except:
data = None
os.system( ‘/etc/init.d/alsa-utils restart’ )
sleep( .25 )
def generateMouthSignal(self,val):
delta = val – self.prevAudiovalue
if( delta < -2 or val == 0 ): self.mouthValue = 0 elif( delta > 0 ):
self.mouthValue = 1
self.prevAudiovalue = val