Introduction: Walabot FX - Guitar Effect Control

About: I'm a 3D designer and Maker with over 10 years 3D design experience. I've been 3D printing / Making since 2013. Love Star Wars.. enough said really

Control your favourite guitar effect using nothing but awesome guitar poses!

Step 1: Things You Will Need!

Hardware Components

Walabot - Walabot https://walabot.com/store/us/products/walabot-pro...

Raspberry Pi - Raspberry Pi 3 Model B http://www.mcmelectronics.com/product/83-17300

Sunfounder LCD1602 https://www.amazon.co.uk/SunFounder-LCD1602-Displ...

SunFounder PCA9685 16 Channel 12 Bit PWM Servo Driver for Arduino and Raspberry Pi https://www.amazon.co.uk/d/5ia/SunFounder-PCA9685...

Servo (generic) No link

9V Battery Clip http://octopart.com/233-keystone-20415

4xAA battery holder https://www.adafruit.com/products/830

AA Batteries http://www.amazon.com/dp/B00451SSBI/?tag=octopart...

Jumper wires (generic) https://www.sparkfun.com/products/11026

DPDT Latching Action Foot Switch https://www.rapidonline.com/Catalogue/Product/78-...

Korg SDD3000-PDL https://www.rapidonline.com/Catalogue/Product/78-...


Software OSs, Apps and Online Services

Autodesk Fusion360 - https://www.autodesk.com/products/fusion-360/overv...

Blynk - http://www.blynk.cc/getting-started

Tools etc

3D Printer

Soldering Iron

Step 2: Abstract

What would it be like to control musical expression using nothing but the position of your guitar in 3D space? Well, let's protoype something and find out!

Step 3: The Basic Idea

I wanted to be able to control 3 effect parameter in real time, I wanted to do this using how I positioned my guitar. So one thing was clear, I was going to need a few things.

  • A sensor that is able to see 3D space
  • Servos to turn the knobs
  • An LCD display
  • An I2C Servo driver
  • A Raspberry Pi
  • To learn Python

Step 4: Walabot

Want to see through walls? Sense objects in 3D space? Sense if you are breathing from across the room?
Well, you're in luck!

The Walabot is whole new way for sensing the space around you using low power radar.


This was going to be key to this project, i would be able to take the carteasan (X-Y-Z) coodinates of objects in 3D space, and map those to servo positions changing how a guitar effect sounds, in real time, without touching the pedal.

Win.

More information about the Walabot can be found here

Step 5: Getting Started

First things first, you will need a computer to drive the Walabot, for this project i'm using a Raspberry Pi 3 (here in refered to at RPi) due to the built in WiFi and general extra oomph

I bought a 16GB SD card with NOOBS preinstalled to keep things nice and simple, and opted to install Raspian as my Linux OS of choice

(if you are unfamiliar with how to install Raspian, please take a moment to have a little read of this)

OK, once you have got Raspian running on your RPi, there are a few configuration steps to take to get things ready for our project

Step 6: Setting Up the Raspberry Pi - 1

Firstly make sure you are running the latest Kernel version and check for updates by opening a command shell and typing

sudo apt-get update
sudo apt-get dist-upgrade

(sudo is added to ensure you've got administrative privilages eg. stuff will work)

This may take a while to complete, so go and have a nice cup of tea.

Step 7: Setting Up the Raspberry Pi - 2

You need to install the Walabot SDK for RPi. From your RPi web browser go to
https://www.walabot.com/gettingstarted and download the Raspberry Pi Installer Package.

From a command shell:

cd downloads
sudo dpkg -I walabotSDK_RasbPi.deb

Step 8: Setting Up the Raspberry Pi - 3

We need to start configuring the RPi to use the i2c bus.
From a command shell:

sudo apt-get install python-smbus
sudo apt-get install i2c-tools

once this is done, you have to add the following to the modules file

From a command shell:

sudo nano /etc/modules

add these 2 strings on seperate lines:

i2c-dev 
i2c-bcm2708

Step 9: Setting Up the Raspberry Pi - 4

The Walabot draws a fair bit of current, and we'll also use GPIO's to control stuff so we need to set these up

From a command shell:

sudo nano /boot/config.txt

add the following lines at the end of the file:

safe_mode_gpio=4
max_usb_current=1

The RPi is an excellent tool for makers, but it is limited in the current it can send to the Walabot. Hence why we're adding a 1Amp max current rather than the more standard 500mA

Step 10: Python

Why Python? well, as it's super easy to code, fast to get running and there's loads of good python examples available! i'd never used it before and was soon up and running in no time.
Now the RPi is configured for what we want, the next step is to configure Python to have access to the Walabot API, LCD Servo interfaces

Step 11: For the Walabot

From a command shell

Sudo pip install “/usr/share/walabot/python/WalabotAPI-1.0.21.zip”

Step 12: For the Servo Interface

From a command shell

sudo apt-get install git build-essential python-dev
cd ~
git clone  https://github.com/adafruit/Adafruit_Python_PCA96...
cd Adafruit_Python_PCA9685
sudo python setup.py install

Why do we need to used a servo driver? Well, for an RPi a couple of reasons.


1. The current drawn by a servo can be very high, and that number gets larger the more servos you have (of course). If you're driving the servo directky from an RPi you run the risk of blowing it's power supply

2. Timings of the PWM (Pulse Width Modulation) that control the servos position are very important. As the RPi doesn't use a realtime OS (there may be interrupts and such) the timings a not accurate and can make the servos twitch nervously. A dedicated driver allows accurate control, but also allows for up to 16 servos to be added, so this is great for expansion.

Step 13: For the LCD

open your RPi web browser


https://www.sunfounder.com/learn/category/sensor-k...

download

https://github.com/daveyclk/SunFounder_SensorKit_...

From a command shell:

sudo mkdir /usr/share/sunfounder

Using the graphical explorer, copy the python folder out of the zip file into you new sunfounder folder

The LCD is used to prompt the user as to what exactly is going on. Showing the process of configuration through to the x, y and z values being mapped onto each servo

Step 14: Blynk

Blynk is a brilliant IoT service that allows you to create a custom app to control your stuff. It seemed like the perfect solution to give me remote control of the walabot to really dial in the settings...


One problem. Blynk is not currently supported on the Python platform, bugger. But fear not! i was able to find a nice little work around that allows remote control and remote parameter input! it is a little hacky

first step is to download the Blynk app from your favourite app store

Second, sign up for an account

Once that is done, open the app and start a new project, choosing Raspberry Pi 3 as the hardware.

The app will allocate you an access token (you will need this to put in your code)

Once you have done that. you will need to set up the app as shown in the images. This is how it will interface with the walabot.

Step 15: Configuring the Blynk App

Step 16: You Can Use This QR Code With the Blynk App to Clone My Project to Save You Time

OK Now that the app is all set up, we can configure Python and the RPi to talk to it over the internets. Magic

Step 17: Running Blynk With the Raspberry Pi and Using the Blynk HTTPS for Python

Firstly, you need to install the Blynk HTTPS wrapper for Python


From a command shell:

sudo git clone  http://github.com/daveyclk/blynkapi.git
sudo pip install blynkapi

Secondly, you need to install the Blynk Service on the RPi

From a command shell:

git clone  http://github.com/daveyclk/blynkapi.git
cd blynk-library/linux
make clean all target=raspberry

to run the blynk service

sudo ./blynk --token=YourAuthToken

To ensure the Blynk Service runs on start up you need to modify the /etc/rc.local

by doing

sudo nano /etc/rc.local

add this at the end

./blynk-library/linux/blynk --token=my token &

(i have included a cope of my /etc/rc.local file in the code section for reference)

To test it's working simply type

sudo /etc/rc.local start

The Blynk Service should now be running

Step 18: Autorunning the Script

Now that this is all set up and configured, and we have the python code ready. we can set things to auto run so we can ditch the keyboard and monitors


There are a few things to do

Create a new script file to run out Python Program

sudo nano guitareffect.sh

add these lines

#!/bin/sh
python /home/pi/GuitarEffectCLI.py

make sure to save it

Next we need to give the script permission to run by typing

Sudo chmod +x /home/pi/guitareffect.sh

And finally, we need to add this script to the /etc/rc.local file that we tinkered with earlier.

Sudo nano /etc/rc.local

Add

/home/pi/guitareffect.sh & 

be sure to include the "&" this allows the Python Script to run in the background

Right! That's all the configuration and software sorted, next it's time to wire up the hardware

Step 19: The Hardware

First Breadboard prototype

Step 20: Enclosure Design

The enclosure was designed and rendered in the awesome Fusion360

Step 21: Guts Shots

Step 22: Final Assembly Shots

Step 23: To Fix the Walabot to the Stand

Use the self adhesive metal disk that comes with the walabot to fix it in place

Step 24: Hardware STL Files for 3D Printing

Step 25: Schematics for Wiring the Thing Up

Step 26: Code

Use the attached Python script for your project

from __future__ import print_function
from sys import platform from os import system from blynkapi import Blynk import WalabotAPI import time import RPi.GPIO as GPIO

#set up GPIO using Board Numbering GPIO.setmode(GPIO.BOARD) GPIO.setup(18, GPIO.IN, pull_up_down = GPIO.PUD_UP)

#blynk auth token auth_token = "your_auth_token_here"

# Import the PCA9685 module for servo control. import Adafruit_PCA9685

#import LCD module from location from imp import load_source LCD1602 = load_source('LCD1602', '/usr/share/sunfounder/Python/LCD1602.py')

# Initialise the PCA9685 using the default address (0x40). pwm = Adafruit_PCA9685.PCA9685()

# blynk objects defaults = Blynk(auth_token, pin = "V9") start_button = Blynk(auth_token, pin = "V3") Rmax = Blynk(auth_token, pin = "V0") Rmin = Blynk(auth_token, pin = "V1") Rres = Blynk(auth_token, pin = "V2")

ThetaMax = Blynk(auth_token, pin = "V4") ThetaRes = Blynk(auth_token, pin = "V5")

PhiMax = Blynk(auth_token, pin = "V6") PhiRes = Blynk(auth_token, pin = "V7")

Threshold = Blynk(auth_token, pin = "V8")

ServoMin = Blynk(auth_token, pin = "V10") ServoMax = Blynk(auth_token, pin = "V11")

def LCDsetup(): LCD1602.init(0x27, 1) # init(slave address, background light)

def numMap(x, in_min, in_max, out_min, out_max): """ used for mapping the walabot readings to servo position """ return int((x- in_min) * (out_max - out_min) / (in_max - in_min) + out_min)

# use this for rounding up the raw data to the assigned value def myRound(x, base=2): return int(base * round(float(x)/base))

#extracts the number form the returned blynk string def numberExtract(val): val = str(val) return int(filter(str.isdigit, val))

# Set frequency to 60hz, good for servos. pwm.set_pwm_freq(60)

# Configure min and max servo pulse lengths defaults SERVO_MIN = 175 # Min pulse length out of 4096 SERVO_MAX = 575 # Max pulse length out of 4096

# walabot default values R_MAX = 60 R_MIN = 20 R_RES = 5

THETA_MAX = 20 THETA_RES = 5

PHI_MAX = 20 PHI_RES = 5

THRESHOLD = 1

# variables for blynk switching on = "[u'1']"

class Walabot:

def __init__(self): self.wlbt = WalabotAPI self.wlbt.Init() self.wlbt.SetSettingsFolder() self.isConnected = False self.isTargets = False

def blynkConfig(self): load_defaults = defaults.get_val() if str(load_defaults) == on: SERVO_MAX = ServoMax.get_val() SERVO_MAX = numberExtract(SERVO_MAX) print("Servo Max =", SERVO_MAX)

SERVO_MIN = ServoMin.get_val() SERVO_MIN = numberExtract(SERVO_MIN) print("Servo MIN =", SERVO_MIN) R_MAX = Rmax.get_val() R_MAX = numberExtract(R_MAX) print("R max =", R_MAX)

R_MIN = Rmin.get_val() R_MIN = numberExtract(R_MIN) print("R Min =", R_MIN)

R_RES = Rres.get_val() R_RES = numberExtract(R_RES) print("R Res =", R_RES)

THETA_MAX = ThetaMax.get_val() THETA_MAX = numberExtract(THETA_MAX) print("Theta Max =", THETA_MAX) THETA_RES = ThetaRes.get_val() THETA_RES = numberExtract(THETA_RES) print("Theta Res =", THETA_RES)

PHI_MAX = PhiMax.get_val() PHI_MAX = numberExtract(PHI_MAX) print("Phi Max =", PHI_MAX) PHI_RES = PhiRes.get_val() PHI_RES = numberExtract(PHI_RES) print("Phi Res =", PHI_RES)

THRESHOLD = Threshold.get_val() THRESHOLD = numberExtract(THRESHOLD) print("Threshold =", THRESHOLD)

else: # if nothing from blynk app, load defaults SERVO_MIN = 175 # Min pulse length out of 4096 SERVO_MAX = 575 # Max pulse length out of 4096

# walabot default values R_MAX = 60 R_MIN = 20 R_RES = 5

THETA_MAX = 20 THETA_RES = 5

PHI_MAX = 20 PHI_RES = 5

THRESHOLD = 1 def connect(self): try: self.wlbt.ConnectAny() self.isConnected = True self.wlbt.SetProfile(self.wlbt.PROF_SENSOR) #self.wlbt.SetDynamicImageFilter(self.wlbt.FILTER_TYPE_MTI) self.wlbt.SetDynamicImageFilter(self.wlbt.FILTER_TYPE_NONE) #self.wlbt.SetDynamicImageFilter(self.wlbt.FILTER_TYPE_DERIVATIVE) self.wlbt.SetArenaTheta(-THETA_MAX, THETA_MAX, THETA_RES) self.wlbt.SetArenaPhi(-PHI_MAX, PHI_MAX, PHI_RES) self.wlbt.SetArenaR(R_MIN, R_MAX, R_RES) self.wlbt.SetThreshold(THRESHOLD) except self.wlbt.WalabotError as err: if err.code != 19: # 'WALABOT_INSTRUMENT_NOT_FOUND' raise err

def start(self): self.wlbt.Start()

def calibrate(self): self.wlbt.StartCalibration()

def get_targets(self): self.wlbt.Trigger() return self.wlbt.GetSensorTargets()

def stop(self): self.wlbt.Stop()

def disconnect(self): self.wlbt.Disconnect()

def main(): flag = True check = "" LCDsetup() while flag: LCD1602.write(0, 0, 'Guitar ') LCD1602.write(0, 1, 'Effect Control') time.sleep(2) LCD1602.write(0, 0, 'Press Start to ') LCD1602.write(0, 1, 'begin ') time.sleep(2) if (str(check) == on): flag = False else: check = start_button.get_val() #check for blynk start button press if (GPIO.input(18) == 0): #check footswitch flag = False

LCD1602.write(0, 0, "OK! let's Do it ") LCD1602.write(0, 1, ' ') wlbt = Walabot() wlbt.blynkConfig() wlbt.connect() LCD1602.clear() if not wlbt.isConnected: LCD1602.write(0, 0, 'Not Connected ') else: LCD1602.write(0, 0, 'Connected ') time.sleep(2) wlbt.start() wlbt.calibrate() LCD1602.write(0, 0, 'Calibrating.....') time.sleep(3) LCD1602.write(0, 0, 'Starting Walabot')

appcheck = start_button.app_status() flag = True # reset flag for main prog

while flag: # used to put effect in standby (effectively) if (appcheck == True): if (str(check) != on): if (GPIO.input(18) != 0): #check footswitch flag = False else: check = start_button.get_val() #check for start button press appcheck = start_button.app_status()

else: if (GPIO.input(18) != 0): #check footswitch flag = False

xval = 0 yval = 0 zval = 0 average = 2 delayTime = 0

targets = wlbt.get_targets()

if len(targets) > 0: for j in range(average):

targets = wlbt.get_targets() if len(targets) > 0: print(len(targets)) targets = targets[0]

print(str(targets.xPosCm)) xval += int(targets.xPosCm) yval += int(targets.yPosCm) zval += int(targets.zPosCm) time.sleep(delayTime) else: print("no targets") xval = xval/average

xval = numMap(xval, -60, 60, SERVO_MIN, SERVO_MAX) xval = myRound(xval) if xval < SERVO_MIN: # protect the servo xval = SERVO_MIN if xval > SERVO_MAX: xval = SERVO_MAX LCD1602.write(0, 0, 'x=' + str(xval) + ' ') pwm.set_pwm(0, 0, xval)

yval = yval/average

yval = numMap(yval, -60, 60, SERVO_MIN, SERVO_MAX) yval = myRound(yval) if yval < SERVO_MIN: # protect the servo yval = SERVO_MIN if yval > SERVO_MAX: yval = SERVO_MAX LCD1602.write(0, 1, 'y=' + str(yval)) pwm.set_pwm(1, 0, yval)

zval = zval/average

zval = numMap(zval, R_MIN, R_MAX, SERVO_MIN, SERVO_MAX) zval = myRound(zval) if zval < SERVO_MIN: # protect the servo zval = SERVO_MIN if zval > SERVO_MAX: zval = SERVO_MAX LCD1602.write(8, 1, 'z=' + str(zval)) pwm.set_pwm(2, 0, zval)

else: print("no targets") LCD1602.write(0, 0, "Shutting Down ") LCD1602.write(0, 1, 'The Walabot ') time.sleep(3) wlbt.stop() wlbt.disconnect()

if __name__ == '__main__': while True: main()

for the guitareffect.sh

#!/bin/sh
cd /home/pi

sudo python GuitarEffectCLI.py


A copy of the RC local file for reference

#!/bin/sh -e
# # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing.

# Print the IP address _IP=$(hostname -I) || true if [ "$_IP" ]; then printf "My IP address is %s\n" "$_IP" fi

./blynk-library/linux/blynk --token="you token goes here" & sleep 10 sudo /home/pi/guitareffect.sh & exit 0


Step 27: Github Repositories to Use

Use this for the Sunfounder LCD

https://github.com/daveyclk/SunFounder_SensorKit_f...

Use this for the servo driver

https://github.com/daveyclk/Adafruit_Python_PCA968...

Use this for the Blynk Python HTTPS Wrapper

https://github.com/daveyclk/blynkapi


Step 28: Conclusion

Well this has been a steep learning curve, but has been so worth it.


My take aways are

  • I had to learn Python..turns out it's ace
  • Interfaced the Python on the Raspberry Pi with the Blynk IoT service. This is not officially supported so there is some limits to it's functions. Still works great though!
  • It turns out the Walabot is great for musical expression. I used it on a Korg SDD3000, but you can use any effect you like

Have a go yourself. This isn't limited to guitar effects, i can be used with any instrument with any effect.