CEB 3D Printer: Difference between revisions

From Open Source Ecology
Jump to navigation Jump to search
mNo edit summary
No edit summary
 
(9 intermediate revisions by one other user not shown)
Line 1: Line 1:
'''Concept (Illustrated Below):'''
'''Concept (Illustrated Below):'''
This idea is to develop an automated brick-laying system that can build homes from the ground up, literally.  Using a combination of the CEB Press, a conveyor belt, gripper, and a common machine configuration (TBD), the machine acts like a large 3D printer which picks and places compressed bricks robotically.
This idea is to develop an automated brick-laying system that can build homes from the ground up, literally.  Using a combination of the CEB Press, a conveyor belt, gripper, and a common machine configuration (TBD), the machine acts like a large 3D printer which picks and places compressed bricks robotically.
Also see [[Automated_construction]]




<div style="text-align: center;">
<div style="text-align: center;">
[[Image:CEB_3DP_Architecture.png]]
<u>'''Concept Diagram'''</u> <p></p>
[[Image:CEB_3DP_Architecture.png ]]
  </div>
  </div>


Two video animations, originally made as Java applets, illustrate two such designs:
Two video animations, originally made as Java applets, illustrate two such designs:


<u>'''Animation (Gantry Design)'''</u>


 
<div style="text-align: center;">
<div style="text-align: center;">  
<u>'''Animation (Gantry & Cable Designs)'''</u> <p></p>  
{{YoutubePopup|Il1stSJcZTU|big}}
{{YoutubePopup|Il1stSJcZTU|big}}
{{YoutubePopup|0HDd9J_Cc14|big}}
  </div>
  </div>






<u>'''Animation (Cable Design)'''</u>
<div style="text-align: center;">
<u>'''High-Level Actuator & Feedback Architecture:'''</u><p></p>
[[Image:CEB3DPrinterActuatorArchitecture.png]]
[[Image:CEB3DP_FeedbackArchitecture.png‎ ]]
</div>




<div style="text-align: center;">  
<u>'''Logic Flowchart:'''</u>
{{YoutubePopup|0HDd9J_Cc14|big}}
 
<div style="text-align: center;">
[[Image:CEB3DP LogicFlowChart.png‎]]
  </div>
  </div>


Line 138: Line 146:




<u>'''FUNCTION NAME''':</u> <br>
<span style="color: blue">'''INPUT TO FUNCTIONS'''</span> <br>
<span style="color: rgb(204, 102, 0);">'''OUTPUT OF FUNCTIONS'''</span> <br>
<nowiki>*</nowiki>: unfinished or incorrect function, will change within a week.
<u>'''Read Encoders Function:'''</u> Read digital encoders and scale the value accordingly to return <span style="color: rgb(204, 102, 0);">'''current length'''</span> in feet.  This function will need to be written after testing is done, but I can provide skeleton code soon.*
<pre>
&nbsp;
Code coming when encoder selection is finalized.
&nbsp;
</pre>
----
 
<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="content-type">
<title>pageEncoders</title>
</head>
<body >
<p class="MsoNormal"><b style=""><span style="font-size: 14pt;">How do
you get “cable length” from encoders?<o:p></o:p></span></b></p>
<p class="MsoNormal"><o:p></o:p>Encoders gives feedback on incremental
position and direction
only, from which you can use to find velocity, acceleration, total distance
travelled,
etc.<span style="">&nbsp; </span>However, you don’t have a <u>reference
point</u> for starting out: meaning that as soon as the software is
powered on,
and the actuators start moving you may have travelled 0.5234’.<span
style="">&nbsp; </span>But from where?</p>
<p class="MsoNormal">
<o:p></o:p></p>
<p class="MsoNormal"><o:p></o:p><u>Home position sensors</u> are used
by triggering a sensor/switch
at a pre-determined location so that after the sensor is tripped, the
length is set to originate from that pre-determined length.  So for example, if you know the switch/sensor is triggered when the gripper is 5.1234' away from the top pulley - along the length of the cable - then reset the encoder count and the new length will be 5.1234' +/- the sensor count (converted to ft.) <span style="">&nbsp;
</span></p>
<p class="MsoNormal">
<span style=""> </span><o:p></o:p></p>
<p class="MsoNormal"><o:p></o:p>This can be as simple as releasing all
3 motors, and pulling
on one until the gripper is 1 foot length from, the top pulley – a
location
where it will never be in normal operationally.<span style="">&nbsp;
</span>An attachment connected that flips a switch.<span style="">&nbsp;
</span>Once flipped, measure the actual physical location
and this becomes a constant in software.</p>
<br><br>
<p class="MsoNormal"><big><span style="font-weight: bold;">An Example:</span></big><br>
<o:p></o:p></p>
<p class="MsoNormal"><o:p></o:p>Let’s say that this encoder (from
omron.com ) with a <b style="">40mm external shaft diameter</b> and a <b
style="">resolution of 300 pulses/rotation</b> is used.<o:p></o:p></p>
</body>
</html>
<div style="text-align: left;">
[[Image:CEB3DP_OmronEncoderExample.png]]
</div>
<html>
<body>
The <b style="">Home position
sensor routine</b> runs for each motor.<span style="">&nbsp; </span><o:p></o:p>
<p class="MsoNormal">Let’s say the encoders are mounted so that there
they spin
from the friction on the cable, without-slipping.<span style="">&nbsp; </span>If
the cable moves in the releasing direction
<span style="font-weight: bold;">one foot</span> in length, the encoder
spins this direction:<span style=""> <br>
</span></p>
<br>
<p class="MsoNormal"><br>
</p>
</body>
</html>
----
<u>'''The example in Code:'''</u>
<html><br>
<pre><span style="color: rgb(126, 126, 126);">//&nbsp;1&nbsp;millimeter&nbsp;=&nbsp;0.0032808399&nbsp;feet</span><br><br>mm2ft&nbsp;=&nbsp;0.0032808399;&nbsp;&nbsp;&nbsp;<span style="color: rgb(126, 126, 126);">// conversion variable</span><br>counts_per_rev&nbsp;=&nbsp;300;<br><br>diameter&nbsp;=&nbsp;40;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(126, 126, 126);">// mm</span><br>diameter&nbsp;=&nbsp;40*mm2ft;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(126, 126, 126);">// convert shaft to ft.</span><br><br>circumference&nbsp;=&nbsp;diameter*pi;<br><br>distance_per_rev&nbsp;=&nbsp;circumference<br><br><span style="color: rgb(126, 126, 126);">//******************************************************//</span><br><span style="color: rgb(126, 126, 126);">//&nbsp;Example:&nbsp;distance&nbsp;=&nbsp;1&nbsp;ft.&nbsp;how&nbsp;many&nbsp;counts&nbsp;are&nbsp;recorded?</span><br><br>distance&nbsp;=&nbsp;1;<br>counts&nbsp;=&nbsp;(counts_per_rev)*(1/distance_per_rev)*distance<br><br><span style="color: rgb(126, 126, 126);">//&nbsp;counts&nbsp;=</span><br><span style="color: rgb(126, 126, 126);">//&nbsp;</span><br><span style="color: rgb(126, 126, 126);">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;727.66</span><br><br><span style="color: rgb(126, 126, 126);">//&nbsp;rounded&nbsp;down&nbsp;to&nbsp;727&nbsp;as&nbsp;counts&nbsp;are&nbsp;integers</span><br><br><span style="color: rgb(126, 126, 126);">//&nbsp;Example:&nbsp;counts&nbsp;=&nbsp;1000.&nbsp;How&nbsp;much&nbsp;distance&nbsp;travelled?</span><br><br>counts&nbsp;=&nbsp;1000;<br>distance&nbsp;=&nbsp;(distance_per_rev)*(1/counts_per_rev)*counts<br><big><br><span style="color: rgb(126, 126, 126);">//&nbsp;distance&nbsp;=</span><br><span style="color: rgb(126, 126, 126);">//&nbsp;</span><br><span style="color: rgb(126, 126, 126);">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.3743&nbsp;(feet)</span></big><br><br><span style="color: rgb(126, 126, 126);">//******************************************************//</span><br><br></pre>
</html>
----
<u>'''Calculate Length Function:'''</u> Now that <span style="color: blue;">'''desired gripper position'''</span> & all 4 <span style="color: blue;">'''current lengths'''</span> are known, <span style="color: rgb(204, 102, 0);">'''desired length'''</span> for each cable can be calculated.*(current length is already known actually from previous function, will update code soon)
<html>
<pre>
<span style="color: #CC6600;">float</span> px, py, pz; <span style="color: #7E7E7E;">// p (x,y,z) is the current position of the gripper</span>
<span style="color: #CC6600;">float</span> dpx, dpy, dpz; <span style="color: #7E7E7E;">// p (x,y,z) is the desired position of the gripper</span>
<span style="color: #CC6600;">float</span> Bheight = 12.0, Blength = 18.0, Bwidth = 12.0; <span style="color: #7E7E7E;">// Base dimensions at 12'x18'x12'</span>
<span style="color: #CC6600;">float</span> B1x = 0.0,    B1y = 0.0,      B1z = Bheight; <span style="color: #7E7E7E;">// top point of base rod 1</span>
<span style="color: #CC6600;">float</span> B2x = 0.0,    B2y = Blength,  B2z = Bheight; <span style="color: #7E7E7E;">// top point of base rod 2</span>
<span style="color: #CC6600;">float</span> B3x = Bwidth,  B3y = Blength,  B3z = Bheight; <span style="color: #7E7E7E;">// top point of base rod 3</span>
<span style="color: #CC6600;">float</span> B4x = Bwidth,  B4y = Blength,  B4z = Bheight; <span style="color: #7E7E7E;">// top point of base rod 4</span>
<span style="color: #CC6600;">float</span> L1,L2,L3,L4, dL1,dL2,dL3,dL4; <span style="color: #7E7E7E;">// Current and desired length variables</span>
<span style="color: #7E7E7E;">//&nbsp;This&nbsp;function&nbsp;calculates&nbsp;the&nbsp;length&nbsp;that&nbsp;each&nbsp;of&nbsp;the&nbsp;cables</span>
<span style="color: #7E7E7E;">//&nbsp;must&nbsp;be&nbsp;in&nbsp;order&nbsp;to&nbsp;attain&nbsp;the&nbsp;desired&nbsp;gripper&nbsp;position.</span>
<span style="color: #CC6600;">void</span> get_lengths()
{
&nbsp;&nbsp;
&nbsp;&nbsp;<span style="color: #7E7E7E;">// Lengths are determined from top of base rod to gripper,</span>
&nbsp;&nbsp;<span style="color: #7E7E7E;">// so this does not include length from motor to pulley </span>
&nbsp;&nbsp;<span style="color: #7E7E7E;">// at the top of the rod.</span>
&nbsp;&nbsp;
&nbsp;&nbsp;L1&nbsp;=&nbsp;dist3d(B1x,&nbsp;B1y,&nbsp;B1z,&nbsp;px,py,pz);&nbsp;&nbsp;<span style="color: #7E7E7E;">// Length of cable 1 in feet</span>
&nbsp;&nbsp;L2&nbsp;=&nbsp;dist3d(B2x,&nbsp;B2y,&nbsp;B2z,&nbsp;px,py,pz);&nbsp;&nbsp;<span style="color: #7E7E7E;">// Length of cable 2 in feet</span>
&nbsp;&nbsp;L3&nbsp;=&nbsp;dist3d(B3x,&nbsp;B3y,&nbsp;B3z,&nbsp;px,py,pz);&nbsp;&nbsp;<span style="color: #7E7E7E;">// Length of cable 3 in feet</span>
&nbsp;&nbsp;L4&nbsp;=&nbsp;dist3d(B4x,&nbsp;B4y,&nbsp;B4z,&nbsp;px,py,pz);&nbsp;&nbsp;<span style="color: #7E7E7E;">// Length of cable 4 in feet</span>
&nbsp;&nbsp;
&nbsp;&nbsp;<span style="color: #7E7E7E;">// Desired lengths calculated the same way.</span>
&nbsp;&nbsp;
&nbsp;&nbsp;dL1&nbsp;=&nbsp;dist3d(B1x,&nbsp;B1y,&nbsp;B1z,&nbsp;dpx,dpy,dpz);&nbsp;<span style="color: #7E7E7E;">// Desired length of cable 1</span>
&nbsp;&nbsp;dL2&nbsp;=&nbsp;dist3d(B2x,&nbsp;B2y,&nbsp;B2z,&nbsp;dpx,dpy,dpz);&nbsp;<span style="color: #7E7E7E;">// Desired length of cable 2</span>
&nbsp;&nbsp;dL3&nbsp;=&nbsp;dist3d(B3x,&nbsp;B3y,&nbsp;B3z,&nbsp;dpx,dpy,dpz);&nbsp;<span style="color: #7E7E7E;">// Desired length of cable 3</span>
&nbsp;&nbsp;dL4&nbsp;=&nbsp;dist3d(B4x,&nbsp;B4y,&nbsp;B4z,&nbsp;dpx,dpy,dpz);&nbsp;<span style="color: #7E7E7E;">// Desired length of cable 4</span>
&nbsp;&nbsp;
}
<span style="color: #7E7E7E;">//____________CALCULATE_THE_3-D_DISTANCE_(L-3_NORM)________________//</span>
<span style="color: #CC6600;">float</span> dist3d(<span style="color: #CC6600;">float</span> p1x, <span style="color: #CC6600;">float</span> p1y, <span style="color: #CC6600;">float</span> p1z, <span style="color: #CC6600;">float</span> p2x, <span style="color: #CC6600;">float</span> p2y, <span style="color: #CC6600;">float</span> p2z)
{
&nbsp;&nbsp;<span style="color: #CC6600;">float</span> dist3 = <span style="color: #CC6600;">sqrt</span>((p2x-p1x)*(p2x-p1x) + (p2y-p1y)*(p2y-p1y) + (p2z-p1z)*(p2z-p1z));
&nbsp;&nbsp;<span style="color: #CC6600;">return</span> dist3;
}
</pre>
</html>
<u>'''PID Function:'''</u> Now that <span style="color: blue;">'''desired length'''</span> and <span style="color: blue;">'''current length'''</span>  are known, <span style="color: rgb(204, 102, 0);">'''motor output'''</span> and <span style="color: rgb(204, 102, 0);">'''direction'''</span>  for each motor can be calculated.
<html>
<body>
<pre>
<span style="color: #CC6600;">float</span>[] err = <span style="color: #CC6600;">new</span> <span style="color: #CC6600;">float</span>[4];  <span style="color: #7E7E7E;">// error array</span>
<span style="color: #CC6600;">float</span>[] dir = <span style="color: #CC6600;">new</span> <span style="color: #CC6600;">float</span>[4];  <span style="color: #7E7E7E;">// direction array</span>
<span style="color: #CC6600;">float</span>[] out = <span style="color: #CC6600;">new</span> <span style="color: #CC6600;">float</span>[4];  <span style="color: #7E7E7E;">// output array</span>
<span style="color: #CC6600;">float</span> kp = 500;  <span style="color: #7E7E7E;">// this gain is arbitrary, but must be positive</span>
<span style="color: #CC6600;">float</span> Prop;      <span style="color: #7E7E7E;">// Variable used for proportional gain.</span>
<span style="color: #CC6600;">float</span> max_output = 100; <span style="color: #7E7E7E;">// Saturate the output at 100, also arbitrary</span>
<span style="color: #7E7E7E;">//___________________PID_FUNCTION______________________//</span>
<span style="color: #CC6600;">void</span> pid() <span style="color: #7E7E7E;">// Actually just P for simplicity's sake</span>
{
&nbsp;&nbsp;
&nbsp;&nbsp;Prop&nbsp;=&nbsp;kp*err[motorIndex];&nbsp;<span style="color: #7E7E7E;">// P = const*(desired_length - current_length)</span>
&nbsp;&nbsp;out[motorIndex]&nbsp;=&nbsp;Prop;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// output = P;</span>
&nbsp;
&nbsp;&nbsp;<span style="color: #CC6600;">if</span> (out[motorIndex] > 0)  dir[motorIndex] = 1; <span style="color: #7E7E7E;">// Get direction either 1</span>
&nbsp;&nbsp;<span style="color: #CC6600;">else</span> dir[motorIndex] = 0;                      <span style="color: #7E7E7E;">// or 0</span>
&nbsp;&nbsp;
&nbsp;&nbsp;<span style="color: #CC6600;">constrain</span>(out[motorIndex], -max_output, max_output); <span style="color: #7E7E7E;">// saturate output</span>
&nbsp;&nbsp;out[motorIndex]&nbsp;=&nbsp;<span style="color: #CC6600;">abs</span>(out[motorIndex]); <span style="color: #7E7E7E;">// now that we know direction, we</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// just need the absolute output</span>
}
</pre>
</body>
</html>
<u>'''Write to Motors Function:'''</u> Digital write to speed controllers (output is amplified using the higher current & voltage power source from 12V batteries.  This function, just like the encoders will need to be written after/while testing is done, but I can provide skeleton code soon. *
<pre>
&nbsp;
PWM code coming soon.
&nbsp;
</pre>




Line 146: Line 333:




----


<div style="text-align: center;">
<html>
<u>IRC Experimental Meeting Test Chart:</u>
<head>
This chart is used to display group meeting times on the OSE Internet Relay Chat (IRC) http://opensourceecology.org/wiki/Irc where groups can discuss project ideas and progress with realtime feedback. Group member names, IRC chat usernames, and status of sub-projects are listed.
<meta content="text/html; charset=ISO-8859-1"
</div>
http-equiv="content-type">
<title>page2</title>
</head>
<body>
<big><span style="font-weight: bold;">Strategy to Design and Build:</span></big><br>
<br>
<span style="text-decoration: underline;">PHASE 1: Proof-of-Concept</span>
(5-10 people)<br>
<br>
1. Gripper Design<br>
&nbsp;&nbsp;&nbsp; a.) Research what's available for this application
in terms of
ballpark specs and power requirements, decide if feedback is necessary<br>
&nbsp;&nbsp;&nbsp; b.) Actuator Selection: motors/servos<br>
&nbsp;&nbsp;&nbsp; c.) Produce CAD of all mechanical parts<br>
<br>
2. Mechanical Design (ideally 2 people should be on this)<br>
&nbsp;&nbsp;&nbsp; a.) Research materials<br>
&nbsp;&nbsp;&nbsp; b.) Produce CAD models and assembly<br>
&nbsp;&nbsp;&nbsp; c.) Perform FEA and verify deflection assumptions
based on realist
forces and prescribed displacement:&nbsp; i.e., if using Aluminum and
part
is being stretched laterally, how much does it deflect?&nbsp; If
greater
than 1 cm, redesign, consider alternative material, or simply account
for this in software.<br>
&nbsp;&nbsp;&nbsp; d.) Bill of materials<br>
<br>
3. Communication to gripper<br>
&nbsp;&nbsp;&nbsp; a.) Wireless would be nice:
http://www.sparkfun.com/tutorials/128, research and justify selection
of technology to go with.<br>
&nbsp;&nbsp;&nbsp; b.) Test at least one solution once purchased for
range and loss of communication.<br>
&nbsp;&nbsp;&nbsp; c.) Find what data needs to be sent and how often
(actually this is
probably easy, could be as simple as grip/ungrip 10 Hz - not bad)<br>
<br>
<span style="font-weight: bold;">Goal:</span> be able to manually input
single position coordinates, e.g.
(x,y,z)=(4.213',5.9234',1.512') and measure how accurate and consistent
system is, i.e. is it biased to one side at a higher level? Can
mechanical shortcomings be remedied in software.<br>
&nbsp;&nbsp;&nbsp; <br>
<br>
<span style="text-decoration: underline;">PHASE 2: Scaling up and
adding complexity</span><br>
<br>
4. Data input - Using XML or .txt file, pass in from PC to
microcontroller via serial connection a list of coordinates.<br>
&nbsp;&nbsp;&nbsp; a.) Write program to design a structure &amp; output
XML file - the
one complication here is to post-process the solid and write
sub-routines to convert solid into something to be completely built
from bricks.<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; i.) Tutorial on how to do so<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ii.) Generate at least 2 sample
files.<br>
&nbsp;&nbsp;&nbsp; b.) Write program to read XML file and send to
microcontroller<br>
&nbsp;&nbsp;&nbsp; c.) Arduino sub-routine to read in data.<br>
<br>
5. A simple control board for translational speed, display number of
brick, start, stop, etc.<br>
<br>
6. Base Mobile Platform -
http://www.robotcombat.com/store_tanktreads.html either tank treads or
wheels<br>
&nbsp;&nbsp;&nbsp; a.) Research<br>
&nbsp;&nbsp;&nbsp; b.) CAD<br>
&nbsp;&nbsp;&nbsp; c.) Integration with current software
</body>
</html>




{| class="wikitable"
----
|+ This chart will be used as a temporary example. <p> Group Name </p> <p> Group Manager </p> <p> Meeting Time: 8PM-10PM EST </p>
! Task
! Name/Pseudonym
! IRC Username
! Status of Project
! Extra
|-
| Motor Testing
| vc_nepo
| vc_nepo
| 10 %
| Link
|-
| Encoder
| User B
| userBonIRC
| 20 %
|
|-
| Material Spec
| User C
| userConIRC
| Complete
|
|}

Latest revision as of 03:35, 21 December 2011

Concept (Illustrated Below): This idea is to develop an automated brick-laying system that can build homes from the ground up, literally. Using a combination of the CEB Press, a conveyor belt, gripper, and a common machine configuration (TBD), the machine acts like a large 3D printer which picks and places compressed bricks robotically.

Also see Automated_construction


Concept Diagram

CEB 3DP Architecture.png

Two video animations, originally made as Java applets, illustrate two such designs:


Animation (Gantry & Cable Designs)

http://img.youtube.com/vi/Il1stSJcZTU/0.jpg http://img.youtube.com/vi/0HDd9J_Cc14/0.jpg


High-Level Actuator & Feedback Architecture:

CEB3DPrinterActuatorArchitecture.png CEB3DP FeedbackArchitecture.png


Logic Flowchart:

CEB3DP LogicFlowChart.png


Sample Source Code: page`1

Pseudo Code
Arduino Code
DECLARE VARIABLES & FUNCTIONS

Initialize Output Channels
// Tell microcontroller which pins are output
Initialize Input Channels
 // Tell microcontroller which pins are input

MAIN LOOP

  For Motors 1 to 4:
      Read Encoder Values
      Calculate Motor Output to Achieve Desired Position
      Write to Motor Output Channel
      // Note: the motor signal is sent to a speed controller
     // to be amplified
  END FOR LOOP
 
END MAIN LOOP
void setup()
{
  pinMode(2, OUTPUT); // to Base motor 1
  pinMode(3, OUTPUT); // to Base motor 2
  pinMode(4, OUTPUT); // to Base motor 3
  pinMode(5, OUTPUT); // to Base motor 4

  pinMode(6, INPUT); // from digital Encoder 1
  pinMode(7, INPUT); // from digital Encoder 2
  pinMode(8, INPUT); // from digital Encoder 3
  pinMode(9, INPUT); // from digital Encoder 4
}

void loop()
{
  for (int motorIndex = 0; motorIndex < 3; motorIndex++)
  {
    read_encoders();
   
    pid();

    write_to_motors();
  } 
}


FUNCTION NAME:
INPUT TO FUNCTIONS
OUTPUT OF FUNCTIONS
*: unfinished or incorrect function, will change within a week.


Read Encoders Function: Read digital encoders and scale the value accordingly to return current length in feet. This function will need to be written after testing is done, but I can provide skeleton code soon.*

 
Code coming when encoder selection is finalized.
 




pageEncoders

How do you get “cable length” from encoders?

Encoders gives feedback on incremental position and direction only, from which you can use to find velocity, acceleration, total distance travelled, etc.  However, you don’t have a reference point for starting out: meaning that as soon as the software is powered on, and the actuators start moving you may have travelled 0.5234’.  But from where?

Home position sensors are used by triggering a sensor/switch at a pre-determined location so that after the sensor is tripped, the length is set to originate from that pre-determined length. So for example, if you know the switch/sensor is triggered when the gripper is 5.1234' away from the top pulley - along the length of the cable - then reset the encoder count and the new length will be 5.1234' +/- the sensor count (converted to ft.)  

This can be as simple as releasing all 3 motors, and pulling on one until the gripper is 1 foot length from, the top pulley – a location where it will never be in normal operationally.  An attachment connected that flips a switch.  Once flipped, measure the actual physical location and this becomes a constant in software.



An Example:

Let’s say that this encoder (from omron.com ) with a 40mm external shaft diameter and a resolution of 300 pulses/rotation is used.

CEB3DP OmronEncoderExample.png

The Home position sensor routine runs for each motor. 

Let’s say the encoders are mounted so that there they spin from the friction on the cable, without-slipping.  If the cable moves in the releasing direction one foot in length, the encoder spins this direction:




The example in Code:

// 1 millimeter = 0.0032808399 feet

mm2ft = 0.0032808399;   // conversion variable
counts_per_rev = 300;

diameter = 40;          // mm
diameter = 40*mm2ft;    // convert shaft to ft.

circumference = diameter*pi;

distance_per_rev = circumference

//******************************************************//
// Example: distance = 1 ft. how many counts are recorded?

distance = 1;
counts = (counts_per_rev)*(1/distance_per_rev)*distance

// counts =
// 
//        727.66

// rounded down to 727 as counts are integers

// Example: counts = 1000. How much distance travelled?

counts = 1000;
distance = (distance_per_rev)*(1/counts_per_rev)*counts

// distance =
// 
//        1.3743 (feet)


//******************************************************//



Calculate Length Function: Now that desired gripper position & all 4 current lengths are known, desired length for each cable can be calculated.*(current length is already known actually from previous function, will update code soon)


float px, py, pz; // p (x,y,z) is the current position of the gripper
float dpx, dpy, dpz; // p (x,y,z) is the desired position of the gripper

float Bheight = 12.0, Blength = 18.0, Bwidth = 12.0; // Base dimensions at 12'x18'x12'

float B1x = 0.0,     B1y = 0.0,       B1z = Bheight; // top point of base rod 1
float B2x = 0.0,     B2y = Blength,   B2z = Bheight; // top point of base rod 2
float B3x = Bwidth,  B3y = Blength,   B3z = Bheight; // top point of base rod 3
float B4x = Bwidth,  B4y = Blength,   B4z = Bheight; // top point of base rod 4

float L1,L2,L3,L4, dL1,dL2,dL3,dL4; // Current and desired length variables

// This function calculates the length that each of the cables
// must be in order to attain the desired gripper position.
void get_lengths() 
{
  
  // Lengths are determined from top of base rod to gripper,
  // so this does not include length from motor to pulley 
  // at the top of the rod.
  
  L1 = dist3d(B1x, B1y, B1z, px,py,pz);  // Length of cable 1 in feet
  L2 = dist3d(B2x, B2y, B2z, px,py,pz);  // Length of cable 2 in feet
  L3 = dist3d(B3x, B3y, B3z, px,py,pz);  // Length of cable 3 in feet
  L4 = dist3d(B4x, B4y, B4z, px,py,pz);  // Length of cable 4 in feet
  
  // Desired lengths calculated the same way.
  
  dL1 = dist3d(B1x, B1y, B1z, dpx,dpy,dpz); // Desired length of cable 1
  dL2 = dist3d(B2x, B2y, B2z, dpx,dpy,dpz); // Desired length of cable 2
  dL3 = dist3d(B3x, B3y, B3z, dpx,dpy,dpz); // Desired length of cable 3
  dL4 = dist3d(B4x, B4y, B4z, dpx,dpy,dpz); // Desired length of cable 4
  
}

//____________CALCULATE_THE_3-D_DISTANCE_(L-3_NORM)________________//
float dist3d(float p1x, float p1y, float p1z, float p2x, float p2y, float p2z)
{
  float dist3 = sqrt((p2x-p1x)*(p2x-p1x) + (p2y-p1y)*(p2y-p1y) + (p2z-p1z)*(p2z-p1z));
  return dist3;
}


PID Function: Now that desired length and current length are known, motor output and direction for each motor can be calculated.

float[] err = new float[4];  // error array
float[] dir = new float[4];  // direction array
float[] out = new float[4];  // output array

float kp = 500;  // this gain is arbitrary, but must be positive
float Prop;      // Variable used for proportional gain.
float max_output = 100; // Saturate the output at 100, also arbitrary

//___________________PID_FUNCTION______________________//
void pid() // Actually just P for simplicity's sake
{
  
  Prop = kp*err[motorIndex]; // P = const*(desired_length - current_length)
  out[motorIndex] = Prop;    // output = P;
 
  if (out[motorIndex] > 0)  dir[motorIndex] = 1; // Get direction either 1
  else dir[motorIndex] = 0;                      // or 0
  
  constrain(out[motorIndex], -max_output, max_output); // saturate output
  out[motorIndex] = abs(out[motorIndex]); // now that we know direction, we
                                          // just need the absolute output
}


Write to Motors Function: Digital write to speed controllers (output is amplified using the higher current & voltage power source from 12V batteries. This function, just like the encoders will need to be written after/while testing is done, but I can provide skeleton code soon. *

 
PWM code coming soon.
 






page2 Strategy to Design and Build:

PHASE 1: Proof-of-Concept (5-10 people)

1. Gripper Design
    a.) Research what's available for this application in terms of ballpark specs and power requirements, decide if feedback is necessary
    b.) Actuator Selection: motors/servos
    c.) Produce CAD of all mechanical parts

2. Mechanical Design (ideally 2 people should be on this)
    a.) Research materials
    b.) Produce CAD models and assembly
    c.) Perform FEA and verify deflection assumptions based on realist forces and prescribed displacement:  i.e., if using Aluminum and part is being stretched laterally, how much does it deflect?  If greater than 1 cm, redesign, consider alternative material, or simply account for this in software.
    d.) Bill of materials

3. Communication to gripper
    a.) Wireless would be nice: http://www.sparkfun.com/tutorials/128, research and justify selection of technology to go with.
    b.) Test at least one solution once purchased for range and loss of communication.
    c.) Find what data needs to be sent and how often (actually this is probably easy, could be as simple as grip/ungrip 10 Hz - not bad)

Goal: be able to manually input single position coordinates, e.g. (x,y,z)=(4.213',5.9234',1.512') and measure how accurate and consistent system is, i.e. is it biased to one side at a higher level? Can mechanical shortcomings be remedied in software.
   

PHASE 2: Scaling up and adding complexity

4. Data input - Using XML or .txt file, pass in from PC to microcontroller via serial connection a list of coordinates.
    a.) Write program to design a structure & output XML file - the one complication here is to post-process the solid and write sub-routines to convert solid into something to be completely built from bricks.
        i.) Tutorial on how to do so
        ii.) Generate at least 2 sample files.
    b.) Write program to read XML file and send to microcontroller
    c.) Arduino sub-routine to read in data.

5. A simple control board for translational speed, display number of brick, start, stop, etc.

6. Base Mobile Platform - http://www.robotcombat.com/store_tanktreads.html either tank treads or wheels
    a.) Research
    b.) CAD
    c.) Integration with current software