![]() |
The robot arm in its untouched state |
I also have an Arduino I bought some time ago. While it was interesting to play with small samples, controlling LEDs on a breadboard for example, having the robot meant I could try something more involved.
A search on Google for ideas came up with the following article about using capacitive distance sensing to make a 3D hand sensor Instructables 3D Controller. I figured this would give quite an interesting demo of using my arm to move the robot arm.
The first step was to create the 3D sensor. The instructions are fortunately straightforward and apart from refreshing some rusty soldering skills I encountered no issues.
The question about how I would be able to use the sensor to control motions in two directions along each axis was an interesting one. A simple analysis of the response in the Arduino serial monitor showed that the signal rose at an increasing rate closer to the sensor, However at a point about 1/3 of the distance from each sensor to the edge of the cube a movement of 1-2 inches would result in a change of signal of 5 units in each direction. I could use this as the basis of the controller.
My approach was to program a 2 second wait after an initial upload or reset of the Arduino, I could use this time to put my hand in the correct position within the sensor cube. At the end of the 2 seconds any movement that changed the response by greater than +/- 5 units would cause the arm to move along that axis in the corresponding +/- direction.
Finally, I needed a motor shield for the Arduino. For this prototype I stuck with the standard version which provides control over two motors. This would obviously restrict the scope of the project since the robot arm itself has 5 motors.
The completed prototype is shown below. I used the X axis to control the grabber and the Z axis to control front and back movement.
![]() |
The completed prototype |
Well, to begin with the sensor was too unforgiving. You had to begin the session with your hand just in the right place. This isn't a good situation from a user perspective.
The processor loop doesn't allow two axes to be engaged simultaneously.
Finally, the sensor is also subject to noise such that the response changes over time.
I'll not be taking this approach any further but this has been a good project in terms of putting together several technologies. The arm certainly won't be mothballed!
The code for the Arduino is given below:
// Based on a sample by By Kyle McDonald// From the instructables project at:// http://www.instructables.com/id/DIY-3D-Controller/#define resolution 4#define mains 50 // 60: north america, japan; 50: most other places#define refresh 2 * 1000000 / mains/*Digital Pins:12, 3, 9 Channel A13, 11, 8 Channel B5,6,7 Sensor*/int xSensor = 5;int ySensor = 6;int zSensor = 7;int baseX = 0;int baseY = 0;int baseZ = 0;void setup() {Serial.begin(115200);//Setup Channel ApinMode(12, OUTPUT); // Initialise Motor Channel A pin - DIRECTIONpinMode(9, OUTPUT); // Initialise Brake Channel A pin - BRAKE//Setup Channel BpinMode(13, OUTPUT); // Initialise Motor Channel A pin - DIRECTIONpinMode(8, OUTPUT); // Initialise Brake Channel A pin - BRAKEpinMode(xSensor, INPUT);pinMode(ySensor, INPUT);pinMode(zSensor, INPUT);startTimer();// Wait 2 seconds before we start moving. To allow you to get your hand in placedelay(2000);}void loop() {int xPos = time(xSensor, B00100000);// For some reason the first xPos comes back as -1if (baseX == 0 && xPos > 0){baseX = xPos;}int yPos = time(ySensor, B01000000);if (baseY == 0){baseY = yPos;}int zPos = time(zSensor, B10000000);if (baseZ == 0){baseZ = zPos;}if (yPos - baseY > 5){Serial.println("Y up");digitalWrite(12, HIGH); // Establish forward direction of Channel AdigitalWrite(9, LOW); // Disengage the break for Channel AdigitalWrite(8, HIGH); // Engage the Brake for Channel BanalogWrite(3,244); // Spin the motor on Channel A at full speed}else if (yPos - baseY < -5){Serial.println("Y down");digitalWrite(12, LOW); // Establishes backward direction of Channel AdigitalWrite(9, LOW); // Disengage the Brake for Channel AdigitalWrite(8, HIGH); // Engage the Brake for Channel BanalogWrite(3, 244); // Spin the motor on Channel A at half speed}else if (xPos - baseX > 5){Serial.println("X up");digitalWrite(13, HIGH); // Establish forward direction of Channel BdigitalWrite(8, LOW); // Disengage the break for Channel BdigitalWrite(9, HIGH); // Engage the Brake for Channel AanalogWrite(11,244); // Spin the motor on Channel B at full speed}else if (xPos - baseX < -5){Serial.println("X down");digitalWrite(13, LOW); // Establishes backward direction of Channel BdigitalWrite(8, LOW); // Disengage the Brake for Channel BdigitalWrite(9, HIGH); // Engage the Brake for Channel AanalogWrite(11, 244); // Spins the motor on Channel B at half speed}else{Serial.println("Neutral");digitalWrite(8, HIGH); // Engage the Brake for Channel BdigitalWrite(9, HIGH); // Engage the Brake for Channel A}}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 importantpinMode(pin, OUTPUT);PORTD = 0;pinMode(pin, INPUT);while((PIND & 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;}
No comments:
Post a Comment