#3DInterface
Explore tagged Tumblr posts
Text

Experience the future of tech with immersive VR and AR interfaces designed for real-world impact. From smart design to interactive control, explore innovation at www.auckam.com.
#VirtualReality#AugmentedReality#MixedReality#FutureTech#ImmersiveTechnology#HumanMachineInteraction#VRInterface#TechInnovation#HolographicDisplay#ARVR#DigitalTransformation#SmartTech#WearableTech#3DInterface#TechTrends#UserExperienceDesign#NextGenTechnology#MetaverseTech
0 notes
Video
tumblr
Project 3
For project three, we decided to work together to create a 3D tracking interface using everyday materials. By making a half cube with cardboard and tape, and attaching aluminum foil to each wall of the cube, we are able to track the motions of a users hand with the use of a visual aid displayed in processing. The aluminum foil is a capacitive sensor that acts as an antenna. It measures how far the electricity has to jump to complete the circuit with the users hand and displays it in a virtual model. The sensors are made of aluminum foil; a 1/4” shielded audio cable and resistors (220K and 10K). The audio cable is cut into 3 and the shield is stripped from one end of each piece. Alligator clips connect to the stripped side. On the other side one 10K and one 220K resistor connect to the same wire as the alligator clip. The shielded still on one side is all connected and powered via 5V on the Genuino as to not act as an antenna itself. The 10K resistors are connecting directly into the Genuino and the 220K resistors are also connected to 5V.
After searching up and finding many examples of capacitive sensors, we came across a video explaining how to build a 3D tracking interface. The project looked really interesting to the three of us, as it was quite unique compared to some of the other sensors we had seen. It appeared to be a little bit above our skill and knowledge level but we decided we were up for the challenge. The Genuino code, processing code and YouTube tutorial for the project can be found below:
· Genuino and Processing Code: https://github.com/Make-Magazine/3DInterface
· YouTube Tutorial: https://www.youtube.com/watch?v=ikD_3Vemkf0
By making this project, we hoped to achieve the parameters of the project in an interesting and challenging way. We knew we had to use everyday materials, which is one of the reasons we chose the 3D tracking interface, which is made of cardboard, tinfoil and makes use of an everyday audio cord. The project we made exemplifies motion and movement perfectly by engaging the user in an interactive experience where movement is pivotal and also one of our goals. Gesture is also incorporated into the project. It is interesting to see that most users make a fist with their hand while using the tracking interface.
We wanted to tackle the theme of distance and proximity head on. The 3D tracking interface deals with this theme by engaging the user in an interactive experience in which they move their hand in a 3D space. The three aluminum proximity sensors calculate the distance of the users hand from each respective sensor. These calculations are made in processing where they are displayed via a ball moving in 3D space.
Due to the materials of the box it isn’t entirely aesthetically pleasing, however; we tried to make it an aesthetically pleasing box by making it a perfect 1ft squared box. We would have liked to make the box out of something more than cardboard, however; we had already spent to much money on the materials that we couldn’t expand any further. We have grown to like the cardboard as the box itself is simple and doesn’t look overly complicated but instead something familiar. This maintains a level of comfort for people engaging with it, as they may be more comfortable trying to use it. The audience outside of the class may be people interested in tech but doesn’t know where to start. This is a very engaging project and due to the home made materials it shows any audiences that they can make complex tech with ease at home. This can be shown to anyone as an example of something they never thought they could make becoming possible.
We encountered a minor problem after we had completed building our wires and box. We successfully uploaded the Genuino code but when we went to run the processing we couldn’t get the ball to move in 3D space. After combing the code we couldn’t find any problems, which was frustrating. We later found out that the code needs to be calibrated by holding down left click and moving the hand across the space.
Steven built the box while Austin and Jay soldered the wires together. Once it was all built the group effort was put into the code. We meticulously hunted through the code together to come up with the solution to why it wouldn’t work.
Arduino Code:
#define resolution 8 #define mains 50 // 60: north america, japan; 50: most other places
#define refresh 2 * 1000000 / mains
void setup() { Serial.begin(115200);
// unused pins are fairly insignificant, // but pulled low to reduce unknown variables for(int i = 2; i < 14; i++) { pinMode(i, OUTPUT); digitalWrite(i, LOW); }
for(int i = 8; i < 11; i++) pinMode(i, INPUT);
startTimer(); }
void loop() { Serial.print(time(8, B00000001), DEC); Serial.print(" "); Serial.print(time(9, B00000010), DEC); Serial.print(" "); Serial.println(time(10, B00000100), DEC);
}
long time(int pin, byte mask) { unsigned long count = 0, total = 0; while(checkTimer() < refresh) { // pinMode is about 6 times slower than assigning // DDRB directly, but that pause is important pinMode(pin, OUTPUT); PORTB = 0; pinMode(pin, INPUT); while((PINB & mask) == 0) count++; total++; } startTimer(); return (count << resolution) / total; }
extern volatile unsigned long timer0_overflow_count;
void startTimer() { timer0_overflow_count = 0; TCNT0 = 0; }
unsigned long checkTimer() { return ((timer0_overflow_count << 8) + TCNT0) << 2; }
Processing Code
1.
import processing.serial.*; import processing.opengl.*;
Serial serial; int serialPort = 2; // << Set this to be the serial port of your Arduino - ie if you have 3 ports : COM1, COM2, COM3 // and your Arduino is on COM2 you should set this to '1' - since the array is 0 based
int sen = 3; // sensors int div = 3; // board sub divisions
Normalize n[] = new Normalize[sen]; MomentumAverage cama[] = new MomentumAverage[sen]; MomentumAverage axyz[] = new MomentumAverage[sen]; float[] nxyz = new float[sen]; int[] ixyz = new int[sen];
float w = 256; // board size boolean[] flip = { false, true, false};
int player = 0; boolean moves[][][][];
PFont font;
void setup() { size(800, 600, OPENGL); frameRate(25);
font = loadFont("TrebuchetMS-Italic-20.vlw"); textFont(font); textMode(SHAPE);
println(Serial.list()); serial = new Serial(this, Serial.list()[2], 115200);
for(int i = 0; i < sen; i++) { n[i] = new Normalize(); cama[i] = new MomentumAverage(.01); axyz[i] = new MomentumAverage(.15); }
reset(); }
void draw() { updateSerial(); drawBoard(); }
void updateSerial() { String cur = serial.readStringUntil('\n'); if(cur != null) { //println(cur); String[] parts = split(cur, " "); if(parts.length == sen ) { float[] xyz = new float[sen]; for(int i = 0; i < sen; i++) xyz[i] = float(parts[i]);
if(mousePressed && mouseButton == LEFT) for(int i = 0; i < sen; i++) n[i].note(xyz[i]);
nxyz = new float[sen]; for(int i = 0; i < sen; i++) { float raw = n[i].choose(xyz[i]); nxyz[i] = flip[i] ? 1 - raw : raw; cama[i].note(nxyz[i]); axyz[i].note(nxyz[i]); ixyz[i] = getPosition(axyz[i].avg); } } } }
float cutoff = .2; int getPosition(float x) { if(div == 3) { if(x < cutoff) return 0; if(x < 1 - cutoff) return 1; else return 2; } else { return x == 1 ? div - 1 : (int) x * div; } }
void drawBoard() { background(255);
float h = w / 2; camera( h + (cama[0].avg - cama[2].avg) * h, h + (cama[1].avg - 1) * height / 2, w * 2, h, h, h, 0, 1, 0);
pushMatrix();
// Due to a currently unresolved issue with Processing 2.0.3 and OpenGL depth sorting, // we can't fill the large box without hiding the rest of the boxes in the scene. // We'll use a stroke for this one instead. noFill(); stroke(0, 40); translate(w/2, w/2, w/2); rotateY(-HALF_PI/2); box(w); popMatrix();
float sw = w / div; translate(h, sw / 2, 0); rotateY(-HALF_PI/2);
pushMatrix(); float sd = sw * (div - 1); translate( axyz[0].avg * sd, axyz[1].avg * sd, axyz[2].avg * sd); fill(255, 160, 0, 200); noStroke(); sphere(18); popMatrix();
for(int z = 0; z < div; z++) { for(int y = 0; y < div; y++) { for(int x = 0; x < div; x++) { pushMatrix(); translate(x * sw, y * sw, z * sw);
noStroke(); if(moves[0][x][y][z]) fill(255, 0, 0, 200); // transparent red else if(moves[1][x][y][z]) fill(0, 0, 255, 200); // transparent blue else if( x == ixyz[0] && y == ixyz[1] && z == ixyz[2]) if(player == 0) fill(255, 0, 0, 200); // transparent red else fill(0, 0, 255, 200); // transparent blue else fill(0, 100); // transparent grey box(sw / 3);
popMatrix(); } } }
stroke(0); if(mousePressed && mouseButton == LEFT) msg("defining boundaries"); }
void keyPressed() { if(key == TAB) { moves[player][ixyz[0]][ixyz[1]][ixyz[2]] = true; player = player == 0 ? 1 : 0; } }
void mousePressed() { if(mouseButton == RIGHT) reset(); }
void reset() { moves = new boolean[2][div][div][div]; for(int i = 0; i < sen; i++) { n[i].reset(); cama[i].reset(); axyz[i].reset(); } }
void msg(String msg) { //using 'text(msg, 10, height - 10)' results in an exception being thrown in Processing 2.0.3 on OSX //we're going to use the console to output instead. println(msg); }
2.
class MomentumAverage { float adapt; float avg; MomentumAverage(float adapt) { this.adapt = adapt; reset(); } void note(float x) { if(x == Float.POSITIVE_INFINITY) return; else avg = (avg * (1 - adapt)) + (x * adapt); } void reset() { avg = 0; } }
3.
boolean linear = true; float minDistance = 1, maxDistance = 4;
class Normalize { float min, max; Normalize() { reset(); } void note(float x) { if(x < min) min = x; if(x > max) max = x; } float normalize(float x) { if(min == max || min == Float.POSITIVE_INFINITY) return 0; float n = map(x, min, max, 0, 1); return constrain(n, 0, 1); } float linear(float x) { float normalized = normalize(x); if(normalized == 0) return 1; float linear = sqrt(1 / normalized); linear = map(linear, minDistance, maxDistance, 0, 1); //println(linear); return constrain(linear, 0, 1); } float choose(float x) { return linear ? linear(x) : normalize(x); } void reset() { min = Float.POSITIVE_INFINITY; max = Float.NEGATIVE_INFINITY; } }
0 notes