A homebuilt wooden sensor box i made, mainly for controlling PureData.
To make the experience fit your profile, pick a username and tell us what interests you.
We found and based on your interests.
This is how one IR sensor and one op-amp are connected to the Teensy. I use some variable resistors for finetuning the thresholds. Keep in mind that operating a LM358 op-amp with only 3.3V will not give you the full output range. The output range will be missing 2V, so it will be only 1.3V (HIGH ~2.2V, LOW ~0.9V).
Two IR sensors are needed to sense direction and speed of one hard disk platter. When using only one, there is no chance for calculating the direction. When using two sensors with a 90° angle offset, you can make use of the Quadrature Encoding technique.
To connect the ribbon and pressure sensors is easy. See, for example:
Connect a pressure (FSR) sensor
SoftPot ribbon sensor product page
On the SoftPot product page, it's said not to connect Ground and Power directly. So make sure to put a 10kOhm resistor in series to connect the ground and the power pin. The center pin can be read directly.
The faders and potentiometers are connected to the Teensy like this.
For the switches, i used the <Bounce.h> library. On this page, you can find detailled information on using the switches. It's nice that you only need one digital pin and a ground connection for each switch.
The LEDs are connected with a resistor in series to make sure that there is not too much current flowing. The longer leg is connected to a digital pin, the shorter with a resistor to ground. As i used really bright white LEDs, i chose a bigger resistor than you would normally do to limit the light intensity.
The touch buttons are connected to the Teensy's touch pins directly.
For reading the touch sensors, i simply use the "touchRead()" operator that you get with Teensyduino (Teensy 3.0 and higher). To be honest, i don't know precisely what the Teensy is doing here. It's some advanced capacitive sensing technology that is implemented with the new Teensy boards. I read something about a reference capacitor equalling out changing conditions. It's said to be faster and giving more reproducible results than when using the old technique with 2 pins, a resistor and the CapSense library (Arduino CapSense article).
Now i may have made a mistake in the design as i was just reading some articles about capacitive touch sensing and it seems that you have improved readings using a grounding plate surrounding the sensor. It seems that the better touch sensing is with an electrical field between two capacitor plates that you change while bringing your finger closer to this system. This would mean there is a metal sensor object that is connected to the touch pins of the Teensy and a grounding plate (connected to ground), surrounding this object. In my design, i just soldered cables to the nails and connect the cables to Teensy's touch pins, making use of touchRead().
This is working quite good, but I have to tell you, that the pin readings change drastically when i touch, for example, the housing of my laptop computer. I will try to make some changes and improve my design.
See The art of capacitive touch sensing for more information on the topic, though this may not be the same technology as the one that touchRead() is working with in the new Teensy boards. Also have a look at the PRJC (Teensy) forum. There are some posts on this topic.
This is the Processing code i used in the second demo video demonstrating the rotary disks.
It is receiving the Teensy data from the serial port (for communication syntax, see Arduino code in the other project log entry).
The wheel resolution (see LEDMode in Arduino code) is being controlled here.
All the values are being scaled.
// ***** wheelController Software *****
// ******** Jan Godde, 2015 ********
// PROCESSING RECEIVE SKETCH FOR arduinoSendWheelsMore SKETCH
// USING PHASE VOCODER IN PD IN soundWheel.pd SKETCH
import processing.serial.*;
import org.puredata.processing.PureData;
PureData pd; // don't forget: expr operator seems not to be working with pdp5!
final int REVOL = 308; // resolution optimized: 4 x (77 black bars)
Serial myPort;
String thisString = "0";
int[] splitString = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
int LEDMode;
int wheel2Mode;
float pos1, pos2;
float ribbon1, ribbon2, fader1, fader2, fsr1, fsr2;
float knob1, knob2, knob3, knob4;
float lefttouch, righttouch, mono, wheeltouch1, wheeltouch2;
float[] inputValue = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //fader, pressure, knobs, 2 wheels
float[] touch = {0, 0, 0, 0, 0}; //2 touch ducking - 1 touch mono (middle) - 2 wheel touch
float[] ribbon = {0, 0};
void setup()
{
pd = new PureData(this, 44100, 0, 2);
pd.openPatch("wheelSound.pd");
pd.start();
size(1200,700);
background(0);
noStroke();
smooth();
LEDMode = 0;
wheel2Mode = 0;
String portName = Serial.list()[4]; // N° 4
myPort = new Serial(this, portName, 57600);
//myPort.bufferUntil('\n');
myPort.clear();
}
void draw()
{
myPort.clear();
lefttouch = constrain( map(touch[0], 1000, 5700, 0, 1000), 0, 1000 );
righttouch = constrain( map(touch[1], 1050, 5700, 0, 1000), 0, 1000 );
mono = constrain( map(touch[2], 1000, 5700, 0, 1000), 0, 1000 );
wheeltouch1 = constrain( map(touch[3], 1500, 6500, 0, 1000), 0, 1000 );
wheeltouch2 = constrain( map(touch[4], 1500, 6500, 0, 1000), 0, 1000 );
fader1 = constrain( map(inputValue[0], 0, 1023, 0, 1000), 0, 1000 ); //fader1
fader2= constrain( map(inputValue[1], 0, 1023, 0, 1000), 0, 1000 ); //fader2
fsr1 = constrain( map(inputValue[2], 0, 700, 0, 1000), 0, 1000 ); //fsr1
fsr2 = constrain( map(inputValue[3], 200, 700, 0, 1000), 0, 1000 );//fsr2
knob1 = constrain( map(inputValue[4], 0, 1023, 0, 1000), 0, 1000 ); //knob1
knob2 = constrain( map(inputValue[5], 0, 1023, 0, 1000), 0, 1000 ); //knob2
knob3 = constrain( map(inputValue[6], 0, 1023, 0, 1000), 0, 1000 ); //knob3
knob4 = constrain( map(inputValue[7], 0, 1023, 0, 1000), 0, 1000 ); //knob4
ribbon1 = constrain( map(ribbon[0], 450, 750, 0, 1000), 0, 1000 );
ribbon2 = constrain( map(ribbon[1], 450, 750, 0, 1000), 0, 1000 );
drawWheels(inputValue[8], inputValue[9], wheeltouch1, wheeltouch2);
pos1 = constrain( map(inputValue[8], 0, ((LEDMode+1)*REVOL), 0, 1000), 0, 1000 );
pos2 = constrain( map(inputValue[9], 0, ((LEDMode+1)*REVOL), 0, 1000), 0, 1000 );
// send all values from 0...1000
pd.sendFloat("vol1", (float)fader1); //fader1
pd.sendFloat("vol2", (float)fader2); //fader2
pd.sendFloat("pvrev1", (float)knob2); //knob2
pd.sendFloat("pvrev2", (float)knob3); //knob3
pd.sendFloat("drywet1", (float)knob1); //knob1
pd.sendFloat("drywet2", (float)knob4); //knob4
pd.sendFloat("pos1", (float)pos1); // wheel 1 position
pd.sendFloat("pos2", (float)pos2); // wheel 2 position
pd.sendFloat("transpose1", (float)fsr1); //fsr1
pd.sendFloat("transpose2", (float)fsr2); //fsr2
pd.sendFloat("touch7", (float)lefttouch);
pd.sendFloat("touch9", (float)righttouch);
pd.sendFloat("touch8", (float)mono); // "mono" channel cross-talk
pd.sendFloat("wheeltouch1", (float)wheeltouch1); // wheel touch 1 & 2
pd.sendFloat("wheeltouch2", (float)wheeltouch2);
pd.sendFloat("wheel2mode", (float)wheel2Mode); // scratch mode on/off on wheel 2
pd.sendFloat("ribbon1", (float)ribbon1);
pd.sendFloat("ribbon2", (float)ribbon2);
}
void drawWheels(float pos1, float pos2, float touch1, float touch2)...
Read more »
This is the code that i am using in the second demo video, demonstrating the rotary disks. This code may be still a mess, and there may be some stupid solutions, but so far it works.
I am not reading in all the touch sensors as for this example i only need a few.
For reading the touch sensors, i simply use the "touchRead()" operator that is working with Teensyduino (Teensy 3.0 and higher). This is working quite good, but I have to tell you, that the pin readings change drastically when i touch, for example, the housing of my laptop computer. I will try to make some changes and improve my design. I posted another project log entry on this topic.
The two switches change a mode that is represented by the first 4 LEDs. The higher the mode (LEDMode: 0, 1, 2, 3, 4), the slower the values change when disks are spun. So it decreases the sensitivity of the wheels, making the wheel movements more precise.
When both switches are pressed, a second mode (LED5Mode) is changed (0, 1), displayed by LED number 5.
If you wonder about all the Serial.print() operators at the end of the sketch, this is how the data is being sent to Processing (see Processing code).
// ***** wheelController Software *****
// ******** Jan Godde, 2015 ********
// ARDUINO SETTINGS FOR processingReceiveWheels SKETCH
// USING PHASE VOCODER IN PD IN soundWheel.pd SKETCH
#include <Encoder.h>
#include <Bounce.h>
#define ENCODER_OPTIMIZE_INTERRUPTS
#define REVOL 308 // resolution optimized: 4 x (77 black bars)
int LEDMode = 0;
int LED5Mode = 0;
int switch1last, switch2last;
int LEDState[5][5] = { {LOW, LOW, LOW, LOW, LOW}, {HIGH, LOW, LOW, LOW, LOW},
{LOW, HIGH, LOW, LOW, LOW},
{LOW, LOW, HIGH, LOW, LOW}, {LOW, LOW, LOW, HIGH, LOW} };
Encoder knobLeft(9, 10);
Encoder knobRight(11, 12);
Bounce switch1 = Bounce(2, 5); // (pin number, 5 ms debounce time)
Bounce switch2 = Bounce(3, 5); // switch 1: D2, switch2: D3
// int sensorPin[20] = { A7, A6, A14, A20, A10, A11, A15, A16, //fader - fsr - knobs
// 0, 1, 15, 16, 17, 18, 19, 22, 23, 25, 32, 33 }; //touchPins
int sensorPin[13] = { A7, A6, A14, A20, A10, A11, A15, A16, //fader - fsr - knobs
0, 33, 32, 1, 25}; // 3 touchPins & 2 wheelTouch
int ribbonPin[2] = {A0, A19};
int ribbonValue[2] = {0, 0};
int ribbonTouched[2] = {0, 0};
int LEDPin[5] = {4, 5, 6, 7, 8};
int outputValue[15]; //with wheel encoder at last two positions
int positionLeft = 0;
int positionRight = 0;
//int newLeft, newRight;
void setup() {
Serial.begin(57600);
pinMode(A14, INPUT_PULLUP);//fsr1
pinMode(A20, INPUT_PULLUP);//fsr2
pinMode(A0, INPUT_PULLUP);//ribbon1
pinMode(A19, INPUT_PULLUP);//ribbon2
pinMode(2, INPUT_PULLUP); //switch1
pinMode(3, INPUT_PULLUP); //switch2
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
}
void loop() {
LEDStateChange();
if (switch1.update()){
if(switch1.fallingEdge()) {
switch1last = 1;
LEDMode = mod((LEDMode-1),5);
if (switch2last == 1){
wheel2StateChange();
}
}
if(switch1.risingEdge()) {
switch1last = 0;
}
}
if (switch2.update()){
if(switch2.fallingEdge()) {
switch2last = 1;
LEDMode = mod((LEDMode+1),5);
if (switch1last == 1){
wheel2StateChange();
}
}
if(switch2.risingEdge()) {
switch2last = 0;
}
}
//Serial.print(switch1last);
//Serial.print(" ");
//Serial.println(switch2last);
// COLLECT SENSOR DATA:
for(int i = 0; i < 8; i++){
outputValue[i] = analogRead(sensorPin[i]);
}
for(int i = 8; i < 13; i++){
outputValue[i] = touchRead(sensorPin[i]);
}
ribbonRead();
int newLeft, newRight;
newLeft = knobLeft.read();
newRight = knobRight.read();
//newLeft = newLeft + 1;
//newRight = newRight + 2;
if (newLeft != positionLeft || newRight != positionRight) {
newLeft = mod(newLeft, (LEDMode+1)*REVOL);
newRight = mod(newRight, (LEDMode+1)*REVOL);
//knobLeft.write(0);
//knobRight.write(0);
positionLeft = newLeft;
positionRight = newRight;
}
//**************************//
for(int i = 0; i < 13; i++){
Serial.print(outputValue[i]);...
Read more »
I was designing this box with SketchUp. I knew the dimensions, and what sensors I'd like to use, but hardly more. Here is how i ended up with the 3D model:
For sensing the movement of the rotary disks (which i hacked out of two old hard drives i had lying around) i was thinking about different approaches. If you look around in the web, there are a couple of DIY maker projects hacking hard disk drives. I could have hacked any optical mice and have the camera look at the disk movement. I could have measured the voltage on the hard disk connectors that appears while spinning the hard drive (amplifying necessary, resolution questionable). I think by measuring the voltages on the hard disk contact pins you can still achieve pretty good results.There's a number of other hard disk jog wheel projects out there. I decided to use reflective optoelectronics. Using Quadrature Encoding, i could go with a good resolution (with 77 black bars, i get 4x77 = 308 ticks per revolution). This is the disk with the pattern for the IR sensor:
The IR sensors i used are named "ITR9904". You can use other sensors as well. There are many IR sensors like this, in one housing, with both one IR LED and one phototransistor. With this design, they have to make use of IR reflection, not transmission.
With the IR sensors, i can measure a high voltage if IR light is reflected, and a low voltage if not. Very important was the exact position of the two sensors. They have to be in an angle of 90 degrees in order to make the Quadrature Encoding possible with this approach. This works if we have an odd number of black (absorbing) stripes on the disk. Here you can see how i placed the sensors below the disk (90°) in the 3D model:
The top panel was built out of two laser cut wood layers that i glued together. The red bars indicate the positions at which i added extra wood blocks that i could put screws into for connceting the top panel to the rest of the box. The screws are hidden by case feet.
Create an account to leave a comment. Already have an account? Log In.
Looks very good!
One comment to the 90° positioning of the sensors. They do not to be 90° mechanically, only electrically, and this is independent of the number of strips (even or odd). They can be side by side and have just a distance (midpoints) of (2n+1)*w/2, where w is the width of a strip or gap. So they can be on the same small PCB and easier to mount.
How did you make the black strips on the backside of the disks? Toner transfer or PCB- photo resist could be possible.
Wow! Thanks for adding in all the detail! That's fantastic.
I'm going to read up on the Teensy cap sensing this weekend. :)
Become a member to follow this project and never miss any updates
I'm looking to add some extra expressiveness to my electronic drum set. I'd like to add semi-circular shaped ribbon controllers underneath the cymbals or maybe an XY pad. And some sort of IR sensor underneath the mesh drum heads, so that pushing down on them sends a MIDI CC #. Could all of these extra controllers be wired into standard cable type connectors to all go to a central "brain" type module that would house the Teensy board?