Published: February 24, 2015, Edited by: Mads Hobye

Robot arm v. 0.3.

Design Credit: Nikolaj Møbius, Mads Hobye and Nicolas Padfield, Bo Thorning.

We have made a super cheap (less than 1000 dollars) industrial robot arm to enable students to hack larger scale robotics and to enable small local productions to use robots in their processes without breaking the bank. It is a product of a 3 day sprint.

You can reproduce it yourselv with basic Fablab tools. All the diagrams and software are avaliable below. It is released under CC NC-BY.

More photos can be found here:
https://fablabruc.app.box.com/s/7d8s8wj5lszzbzeefliob6sq0lx58qhs

Video

First run:

Bruteforce testing:

Students experimenting with gesture control:

Gui

http://zapmaker.org/projects/grbl-controller-3-0/
https://github.com/grbl/grbl/wiki/Using-Grbl

How to build:

CNC Diagrams:

https://www.dropbox.com/sh/z767egd28nl7zxg/AAArs4eBXXDk09jff0cIiPuXa?dl=0

Parts (basic setup without hand):

Wiring

This is the basic wiring of GRBL:

This is an image of our first version (without end-stops):

Green: Common enable.
Black: Common ground.
White: Dir XYZ.
Brown: Pulse XYZ.

The color codes on the steppermotors does not make sense. This is the order we found to be working:

Upload firmware

Installing firmware on Arduino - GRBL:
https://github.com/grbl/grbl/wiki/Compiling-Grbl

Note: You may get a conflict when compiling in Arduino. Remove all other libraries from your library folder (../documents/arduino/libraries).

Firmware setup

Set enable to newer timeout. Use a serial connection and write:

$1=255

Set homing:

$22=1

Remember to set serial to baud: 115200

Useful G-codes

Set zero point for robot:

G10 L2 Xnnn Ynnn Znnn

Use zero point:

G54

Typical initialization to center robot:

G10 L2 X1.5 Y1.2 Z1.1
G54

Move robot to position fast:

G0 Xnnn Ynnn Znnn

Example:

G0 X10.0 Y3.1 Z4.2 (return)

Move robot to position at specific speed:

G1 Xnnn Ynnn Znnn Fnnn

G1 X11 Y3 Z4 F300 (return)

F should be between 10(slooooow) and 600(fast)

Default units for X,Y and Z

When using default step/units settings (250 step/unit) for GRBL and
stepper drive set up for 800 step/rev the following units apply for all axis:

+- 32 units = +- 180 degrees

Processing code example:

This code can communicate directly with the Arduino GRBL.
https://github.com/damellis/gctrl

Remember to set serial to baud: 115200

Modified version with correct baud rate and homing command:

import java.awt.event.KeyEvent;
import javax.swing.JOptionPane;
import processing.serial.*;

Serial port = null;

// select and modify the appropriate line for your operating system
// leave as null to use interactive port (press 'p' in the program)
String portname = null;
//String portname = Serial.list()[0]; // Mac OS X
//String portname = "/dev/ttyUSB0"; // Linux
//String portname = "COM6"; // Windows

boolean streaming = false;
float speed = 0.001;
String[] gcode;
int i = 0;

void openSerialPort()
{
  if (portname == null) return;
  if (port != null) port.stop();

  port = new Serial(this, portname, 115200);

  port.bufferUntil('\n');
}

void selectSerialPort()
{
  String result = (String) JOptionPane.showInputDialog(this,
    "Select the serial port that corresponds to your Arduino board.",
    "Select serial port",
    JOptionPane.PLAIN_MESSAGE,
    null,
    Serial.list(),
    0);

  if (result != null) {
    portname = result;
    openSerialPort();
  }
}

void setup()
{
  size(500, 250);
  openSerialPort();
}

void draw()
{
  background(0);  
  fill(255);
  int y = 24, dy = 12;
  text("INSTRUCTIONS", 12, y); y += dy;
  text("p: select serial port", 12, y); y += dy;
  text("1: set speed to 0.001 inches (1 mil) per jog", 12, y); y += dy;
  text("2: set speed to 0.010 inches (10 mil) per jog", 12, y); y += dy;
  text("3: set speed to 0.100 inches (100 mil) per jog", 12, y); y += dy;
  text("arrow keys: jog in x-y plane", 12, y); y += dy;
  text("page up & page down: jog in z axis", 12, y); y += dy;
  text("$: display grbl settings", 12, y); y+= dy;
  text("h: go home", 12, y); y += dy;
  text("0: zero machine (set home to the current location)", 12, y); y += dy;
  text("g: stream a g-code file", 12, y); y += dy;
  text("x: stop streaming g-code (this is NOT immediate)", 12, y); y += dy;
  y = height - dy;
  text("current jog speed: " + speed + " inches per step", 12, y); y -= dy;
  text("current serial port: " + portname, 12, y); y -= dy;
}

void keyPressed()
{
  if (key == '1') speed = 0.001;
  if (key == '2') speed = 0.01;
  if (key == '3') speed = 0.1;

  if (!streaming) {
    if (keyCode == LEFT) port.write("G91\nG20\nG00 X-" + speed + " Y0.000 Z0.000\n");
    if (keyCode == RIGHT) port.write("G91\nG20\nG00 X" + speed + " Y0.000 Z0.000\n");
    if (keyCode == UP) port.write("G91\nG20\nG00 X0.000 Y" + speed + " Z0.000\n");
    if (keyCode == DOWN) port.write("G91\nG20\nG00 X0.000 Y-" + speed + " Z0.000\n");
    if (keyCode == KeyEvent.VK_PAGE_UP) port.write("G91\nG20\nG00 X0.000 Y0.000 Z" + speed + "\n");
    if (keyCode == KeyEvent.VK_PAGE_DOWN) port.write("G91\nG20\nG00 X0.000 Y0.000 Z-" + speed + "\n");
    //if (key == 'h') port.write("G90\nG20\nG00 X0.000 Y0.000 Z0.000\n");
    if (key == 'v') port.write("$0=75\n$1=74\n$2=75\n");
    //if (key == 'v') port.write("$0=100\n$1=74\n$2=75\n");
    if (key == 's') port.write("$3=10\n");
    if (key == 'e') port.write("$16=1\n");
    if (key == 'd') port.write("$16=0\n");
    if (key == '0') openSerialPort();
    if (key == 'p') selectSerialPort();
    if (key == '$') port.write("$$\n");
    if (key == 'h') port.write("$H\n");
  }

  if (!streaming && key == 'g') {
    gcode = null; i = 0;
    File file = null; 
    println("Loading file...");
    selectInput("Select a file to process:", "fileSelected", file);
  }

  if (key == 'x') streaming = false;
}

void fileSelected(File selection) {
  if (selection == null) {
    println("Window was closed or the user hit cancel.");
  } else {
    println("User selected " + selection.getAbsolutePath());
    gcode = loadStrings(selection.getAbsolutePath());
    if (gcode == null) return;
    streaming = true;
    stream();
  }
}

void stream()
{
  if (!streaming) return;

  while (true) {
    if (i == gcode.length) {
      streaming = false;
      return;
    }

    if (gcode[i].trim().length() == 0) i++;
    else break;
  }

  println(gcode[i]);
  port.write(gcode[i] + '\n');
  i++;
}

void serialEvent(Serial p)
{
  String s = p.readStringUntil('\n');
  println(s.trim());

  if (s.trim().startsWith("ok")) stream();
  if (s.trim().startsWith("error")) stream(); // XXX: really?
}

Virtual version

For students to experiment with robotics without breaking havoc to the physical surroundings we have made a small virtual processing sketch where they can run the commands and see the effect of their code.

  import peasy.*;

  PeasyCam cam;

  // Units: CM
  float b_height = 0;
  float a1 = 92;
  float a2 = 86;
  float snude_len = 20;
  boolean doZ = false;
  float base_angle;// = 0;
  float arm1_angle; // = 0;
  float arm2_angle; //= 0;

  float bx = 60;// = 25;
  float by = 60;// = 0;
  float bz = 60;// = 25;

  float x = 60;
  float y = 60;
  float z = 60;


  float q;
  float c;
  float V1;
  float V2;
  float V3;
  float V4;
  float V5;

  void setup() {
    size(700, 700, P3D);
    cam = new PeasyCam(this, 300);
    cam.setMinimumDistance(50);
    cam.setMaximumDistance(500);
  }
  void draw() {

    //ligninger:
  y = (mouseX - width/2)*(-1);
  x = (mouseY - height/2)*(-1);
  bz = z;
  by = y;
  bx = x;
  float y3 = sqrt(bx*bx+by*by);
  c = sqrt(y3*y3 + bz*bz);
  V1 = acos((a2*a2+a1*a1-c*c)/(2*a2*a1));
  V2 = acos((c*c+a1*a1-a2*a2)/(2*c*a1));
  V3 = acos((y3*y3+c*c-bz*bz)/(2*y3*c));
  q = V2 + V3;
  arm1_angle = q;
  V4 = radians(90.0) - q;
  V5 = radians(180) - V4 - radians(90);
  arm2_angle = radians(180.0) - (V5 + V1);
  base_angle = degrees(atan2(bx,by));

  arm1_angle=degrees(arm1_angle);
  arm2_angle=degrees(arm2_angle);
  //println(by, bz);
  //arm1_angle = 90;
  //arm2_angle = 45;
  /*
  arm2_angle = 23;  
  arm1_angle= 23;
  arm2_angle=23;
  */
    // interactive:

  //  if (doZ)
  //
  //  {
  //    base_angle = base_angle+  mouseX-pmouseX;
  //  } else
  //  {
  //    arm1_angle =arm1_angle+ pmouseX-mouseX;
  //  }
  //
  //  arm2_angle = arm2_angle+ mouseY-pmouseY;

  draw_robot(base_angle, -(arm1_angle-90), arm2_angle+90 - ( -(arm1_angle-90)));
   // println(base_angle + ", " + arm1_angle + ", " + arm2_angle);
  }

  void draw_robot(float base_angle, float arm1_angle, float arm2_angle)
  {

    rotateX(1.2);
    rotateZ(-1.2);
    background(0);

  lights();


    pushMatrix();

    // BASE
    fill(150, 150, 150);
    box_corner(50, 50, b_height, 0);
    rotate(radians(base_angle), 0, 0, 1);

    // ARM 1
    fill(150, 0, 150);
    box_corner(10, 10, a1, arm1_angle);

    // ARM 2
    fill(255, 0, 0);
    box_corner(10, 10, a2, arm2_angle);

    // SNUDE

    fill(255, 150, 0);
    box_corner(10, 10, snude_len, -arm1_angle-arm2_angle+90); 


    popMatrix();
    pushMatrix();


    float action_box_size=100;
    translate(0, -action_box_size/2, action_box_size/2+b_height);
    pushMatrix();
    translate(x,action_box_size- y-action_box_size/2, z-action_box_size/2);
    fill(255,255,0);
    box(20);
    popMatrix();
     fill(255, 255, 255, 50);
    box(action_box_size, action_box_size, action_box_size);


    popMatrix();
  }

  void box_corner(float w, float h, float d, float rotate)
  {
    rotate(radians(rotate), 1, 0, 0);
    translate(0, 0, d/2);
    box(w, h, d);
    translate(0, 0, d/2);
  }

  void keyPressed()
  {

    if (key == 'z')
    {

      doZ = !doZ;
    }
    if (key  == 'h')
    {

      // set all to zero
      arm2_angle = 0;
      arm1_angle = 90;
      base_angle = 0;
    }
     if (key == 'g')
    {

      println(degrees(V1));
      println(degrees(V5));
    }
    if (keyCode == UP)
    {
      z ++;
    }
      if (keyCode == DOWN)
    {
      z --;
    }

    if (key == 'o')
    {
      y = 50;
      z = 50;
      println(q);
      println(c, "c");
      println(V1, "V1");
      println(V2);
      println(V3);
      println(arm1_angle);
      println(V4);
      println(V5);
      println(arm2_angle);
    }
  }

GBRL Settings

Setting that has proven to work on our robots.

$0=10 (step pulse, usec) $1=255 (step idle delay, msec) $2=7 (step port invert mask:00000111) $3=7 (dir port invert mask:00000111) $4=0 (step enable invert, bool) $5=0 (limit pins invert, bool) $6=1 (probe pin invert, bool) $10=3 (status report mask:00000011) $11=0.020 (junction deviation, mm) $12=0.002 (arc tolerance, mm) $13=0 (report inches, bool) $20=0 (soft limits, bool) $21=0 (hard limits, bool) $22=1 (homing cycle, bool) $23=0 (homing dir invert mask:00000000) $24=100.000 (homing feed, mm/min) $25=500.000 (homing seek, mm/min) $26=250 (homing debounce, msec) $27=1.000 (homing pull-off, mm) $100=250.000 (x, step/mm) $101=250.000 (y, step/mm) $102=250.000 (z, step/mm) $110=500.000 (x max rate, mm/min) $111=500.000 (y max rate, mm/min) $112=500.000 (z max rate, mm/min) $120=10.000 (x accel, mm/sec^2) $121=10.000 (y accel, mm/sec^2) $122=10.000 (z accel, mm/sec^2) $130=200.000 (x max travel, mm) $131=200.000 (y max travel, mm) $132=200.000 (z max travel, mm)

Max MSP Patch

This patch controls up to 6 joints on the robot. This can also be used a generic GRBL controller.


----------begin_max5_patcher----------
6692.3oc6c00biaqj84Y9UvRUk27nEe+w9Vt2J9deYqY2L0lxdRkZJZKZOJi
rnJI54lr2J+2WRBHJRIQBPIBZ.a4JiiEEjXiCazciF.m9e+92M4tz+HYyjn+
yneM5cu6e+928txKUbg2oe86l7T7eb+h3MkMax8oO8TxxrIWodurj+Hq75e5
m9e1dsGV+3cEWCLEr8JoKy1L++Ko3pPT0kW97SyWtHIq7aFpu3p3r6+57kO9
k0I2mojLHTLkdUDjPy+nQDRwuQ4e6Q+l9yLeVoLjd2u+AIaxtu8zmy190WWT
VF+TonL4GWOOdwjh23ud+6K90UmIJb2eF8OiWGuXVzuL+4GdH5m+e+6H.jZG
xH6MvvwrBrfkCLXJGxE4fDrDjf7VfGxKI7b8WsCIJ6V8DJXxoPDhIf43gXJB
RPRxUQTboJSKnAULFnwlEymkrd6c56wqq9Je5OUu2uR9sImQ+U+LmxlxoDF.
VLFAUqGuEVQfcv8cOde5hz05AXEebvTNPff7h+RxfrhQbs.axIUB1579RVx5
ujrL9tEI0AulP51txCKRiyxu9pmypeYUKy9yUIJIZxjne6Df5kI+qbA7.8t0
Q+iz+YZNn2C6Qf1wdJWMFiNkqUyXrtrIw.S5FSNTMaXgkmR1rI9wjCvELpOH
BxHhHDUHBFUZxVzBhfdgQjVUTt9qeXc7xGGJUENuz0EkCJMTy6TMA6qfxmGX
PAQrGTH9Jnb6vBJLFcJCCERtsHC0WQlaFXjAHmJ3bLTZKxv7SjYUzOW.Ke4q
CEvH.4w.jORByKFOwjcBJ7dGqS86bxZc+U2gy+.yWj78j0almtrF39tIwqVU
6xuq1Go.k9cULGrqptz7kpKAqtz5juOe6mGWc03048+r7N+yqUB4eHXSTuY9
Sl2u8itEbPkA0vUAHKKmy.QVycTQHPKRu+aIypgB4Z.qRVNe4p0IaxCfMNSK
EUu8rjGhedQ1WN9Stlu+Cw2mz5G9nP86l7354yRWVHDM9jEWd6s6WifaC+nV
morEKiWcjO7l79wyatKdcAppCRCs8MyRSWz7spdPlqiGub9SwYIYyeZa.jae
y4OsZ87kYMtQpX.+5l6WmtXQiuJ0678i7NyxeVeex+Z9rru1X9.EuSdymuZ6
ifIUXzr4OlrIq40xhebSyqzXls0UBqO3sw02aP7cOmkkequZ2aerXyaarY9z
9JFSJYE+FU9.CU+A1diNwz8tQGZ153FntK2hh1H061ZnROj3D62Mm71dyx+G
+kep9abvz35vrV+gPTI3IKMqQQ6ab6.HD1NDtuzcjI0MPnWCS+66X7SYwqy9
aEOwNAzBzMZwxi0lmCWhRWibnI3BwrSiqciUc4vbfPylSboIbBaEDwsChH6.
QHtzggdRLx1QQYfChaxRWmD4BnjpxSmFIok5icgjPX..kkwEjcp9DXpXRfrx
XXUYyrKHA2NhP5pOuUJilT3g9p8uPiam5s9xr3r35NKafAp69cIq2qOV3Kt5
ykOPoJArQEo4I+in+q3ha8GzIoZayjGuYMak33MBTuMzi2FUxtpZErkuJbiF
0x2EqdiPjV5fxFsBd7VUlIxcH3e89Qy2cUxWszy8tjv1aEcHTY9DTBIhCxA6
A9hn9fq6t.uOfQQYoQUILy8Q+.kp43plACUXxeNT54g+rY+zHMjnEEUBSXLV
MeOiQ+.7AzZq4gAGNvXTckGfQ3ngy276y7mxkq728C3lBQGI7+HHIxZ+14vx
1a4d2wC7ts0RpCl5SGZu49IymW8rn716P0WPocSg4f2QAPvR1flyW5.zjPj0
PSN2HZhC.zzY1JPTZ+rUPtXqvaiV.JrLZAr2GsvsNOZAjZUKMGs.j7lHZAsx
iQK.P5EK.dPzBHBytnEfrKQKXLZAMZZNZAH+RzB8vVg3hsBCQK74QOwLHhkI
lQv78Dyb6nCdPIzRvi66f2MiO3oRPiEfm3RJAaIHe85GXQP9HeGCgfBHjA.i
MFh06bZy9udSjnPMbX1cdaQ9CAisybF.71MOgLpcQ9eIveKRSnBLMG3+k396
ggh1B6+hchs425Z2uZXRKyuEw6SF3MtOYfPtkIC7sP.Aaiwz33bo7x768fHB
fBgcQDHEWBIvXHAZzzbHAxKwDzGaErWU1J1s46WLeYa607RXq38O9CpMoOu9
9s2ScPlQMAvYIaxlur5nH7qUtr2qcec9rYM24+pMK+lBDTcHGrRopuRLK3j3
h062JQtXWB4KxLJ7jYnsJyP+Q2.xBOYtvmtcxr+Hx7fSjK2bvVIxL+QlsVyf
6OV5f1ZoC4OxLwVYF6Mxrspy9i1rsJy9itrzVuIRORlk1JyB+wNms1L7mgex
fShQVqL6MhL1Ze1CUbF5YJt8DoOYS72Sl8k7aQ9rl+RbV15428blZxh0OL8m
64F274RuGGl5iJDcbya6l93hz6hWnoOfpO6QNy1ueGH1SlVnQtMNWdFiyJIq
EFXGM1bXRMZr7ZU7G0wVgidvNRHijvPsTWTmFmrJuECD6c8YGxdW4Osn.IBx
ZxdWjtXuKl7kjKyt0cnASyjWXYSzP1EZvAujnwMNDM.kI0tNPP6DHfuj.wmR
xTr7hyXCwJVeoN+i0Ie3vQdBM2Q6OM2UyvfszbGiTgo0AA7fSZcEqAQyrWOT
DHjEXIq2XYcyJmIVRecgk79ikJiRmILJBHXrUNs5SIEVL93yY8iWqHls3i2Y
fSn3QmVLvI.us31J3NFwgQTK9VAMabgZqtPsUiA0VUp9QfUwbzicB1KJyV04
1JXdysn7PsgBTaAKrh.5vjfmEG1iJcGRFrRp1zZpMzxgLpae1c6AA2KsJccV
z8mBPZf5kv4yPnfUHULmFQEohHvodIiH4LWfjJuq1ijfvd2UsN5GWr3iK+3C
O3fw2HnxWgTwQKnW4adcGik0sUZDJ4gv9TqqCJziIYQoeazNkPpxF.ph5IoF
zT8B9qpKKj2chjNoIR9CNsHSTH0tlVwMycYejEBLsRV5iOtH4ziNV4x.g2so
Hoco6zv4a+14icF+rhp+FGacOlOSJGndg3hZteMG8LUF1tLlkrH9OiH.WDIi
x2KAqyWkIjzMaS7w8H1jrHB5Prr7aHRgnchkc37EclX4UCs14YlZ.Nr1Qj2b
tAnLuI4.cR0vXGnEo217X8Aq6f5kxAXEIrMtMOKM9TfQrAUN0zIvjxzQQLaY
yMoMXL81FmkN2cHo9+YAR5lzFrX9lQDJWUdZhNsA3P6zLgxiWxRN3TXF5LxN
lk6ukD4Dqk5jCpLVxHllnAgF3XoKhaomNbPvWsUHfyXJIv9ggANQslOWz0o4
ye0cHohJfLSlMXzqfYjrJYwBG5ogqUNOiivdfDBT450E8yo2klccRxr6hu+a
t3vvqWbcM2UgLlmUBx2SD3IuPmlFMqHFDhdASL5fFG3mC8Mk65knYEaAHD.3
hA0pjeQvkgOJMW+iXNIMC5RHxHZirPC8gn+AL5le3gnay+2my+20+vIsLJDq
xWABqOH6n9Q8sdpZaY2eRiixvxlapjx8bzxko61FPSlbhqDEQWGaDaKwYcWn
yN05blZes23ac65EUVbSlDp3GVw0D1heD2feeNbwOBnO3G1M32sAK9oiczV7
C4F76lIiEAafskHE7mS2H05yJn+bVcojvSlIzvSlwh.Tls8fjRs8TQ+z7YqR
yMRpsQfDkEDYBS4Z8vW.0qnrr5EMkF2CAnv6wl8GxZORlAAnLa6niB2BP+Pj
sUc9HlX8d9bg5ObPisvLjFdz4BFEdjskGIy39nZ3GVMH8QjQ9gHacnK9ilA0
1QfDOZ5Cnfievnrvy3L0VZXi5QyF11Y7PYm1rGTyJ.qVsGndM0Z7JnZmNiTm
ylxWMxyevZPnXGW6Il6sc7AyeFSy5Ur39gLyscLMBFfxLJ33OuRy83KTK0aa
pkBh5G0RIfGgZo9fz0bKE2oLK0fBoEzYR+fTxQfTrqQTV.gnZd2vdDUdLkzR
NbvoXZs6fK.0Vn5jMQ+83EK9uK3OirABwkbEUNQU67.NsKzlNJz3zKPmGfsn
yCec14IDhEcdvqyNOVPM24IxWocd0g21PmW75ryiTGGBCcd9KXme8I14As24
gxRuopZKCtydNaR2r+UqdIcKae4RMBfvBMBxXnQzb+ytq2S5SWF0UbVJJ6Be
7yPvQ2PwdlhvrjEQXP09d8bQDMM5oBDf1IYVRvCFhb5QH1lFBZP0PHbhEZH.
+UCgNzZH5nkLng.8XMD3vpg.ol0PvBO1FBcf0PzgT1sFBV5wZHCqWFLkYgFB
6MjWFcb2FzP3drFBdP0PP5Jhd2ZHD+UCgLzZH5ImXPCg9lINDDVXgFB9sjFh
ZxJFzPd6DGBjaiFxKcjpM31FqmfplRhIziSoMMNbDFhzZ.et1V8G3ZmUGFn.
05srqNLnLKzVcX.B7jpN.t2r6NoLoDHl.ZOEuWuprb2i2mtPw72Zx5FLkiYb
Du3uj4yysnbFbbXSN3bBuasutGg.et4HCqxAP8ZaAqqgbvWXaJsFi1P4BVCH
hcqImg7APegQjUMxNn0VYU4FkUZiABTytssm47VhNmzVOYqLUcbladgpah5x
eYVbVbsSaVEE+me2tKYOB8eWayE7pJMxNCS6VQRLdJt3GzU6ZJsklBlRgh7+
qVSEGuo4iTnk+rqoxi2RJdJGf4fZsTztnRyi5CT69KPsKpLffP10z19RyGSm
aAEI2dXmq1ENGAfQm..ijSkHpDwLCvHzTV4OlAXLTAaXi.rH2qAShgHK.3bC
ADDFYC.imJP.X86eaeo7oRl.QI1.v3SQClNEV9yfBvP4AeqC..Cx+RYD.xB.
N2AOfhjPy.LXJAhXRtM.L4zzf4E+HC..FNkJ4BA1JMXLmVWRau6iPbJDsCeG
f.8K7FLeYRsPx.SQD.rvjUtVBPRXk+kDgg.dy.yr18kJ33bOVaCNNOHQtfxA
rZ+Y0Wai.DyuyPLuXMvx82gQ.ZYTh.AFHKkKN8nNAIi1bMZcw.6ejelgPAqB
BYhNi7ab1NLpwyCSWDopYJ4iDmRMs2pfvSn5Pg5ePd5.hNCsigDgzgAh41.P
3.AfZahSW+g0MpTfm2LmzyOmpNaBrtwN.0OyV25nOOnfBQQd+VBJHeETtcPA
ErDOkggBIuBYT0Vz1QFruhL2LrHStgGAmiDxc5LvtQFOcgQVsWUH8LGFAD5M
slxvb2ojA.eaUN9TLYIWUKVTU5KhTbod7cod7MNjtOnLbRopDYZlArndCm62
UE+4S+3u7SiV89AgJAup58iIpVD58UouOkEuN6uchU8GCTFFCJxmTZY1BJr6
AMAWH1qVhjFe5jwsFDg35axOY6nnLvAwMYoqShbATRU6JPMRR0kfj.udG1XY
T5sAMlJlDcMFQSQmxShVDIc0msbgU5XwUZhAGeQVZIKpRlN4gkGAtcoQ7C5k
rcayjGuYMak33MBTuMzi2F0R+V0JXKeU3FMpkuKV8FgHszAkMZE73spbc42g
fUGfX26695943d2lQn254PUYJACT741AaHgCbE4EUputvtOfQQYoQMo6dmF7
CTsA.QpIvXlI989ZT7l8RhzPBVT0tGEisrHlh.9.X03XBOnLjOFUW2wXA+pY
MEo9oFF2TH5WgPzd9Mu1oHdu6nUmj3wnxFjTVRhxauCUeAkgJILG5dfW+RpP
y4KcQ0cmHqglbiU3ITHT9SclsBjpn4XusBxEaEdavBJ9B2hfEvdevB255fEP
pC0Jyn0VH4MQvBZcGP+J1FWBV3EJXAjZNVlCV.xtDrfwfEzno4fEf7KAKzCa
EhK1JLDrvmG6rxfHVlUFAy2yJysiM1oKg1VfcbeG6tYzwNMyZXF6DWxFXKA3
qW4.KBvG46XHDT.gr8JRei.FhU0DQlYmWuIRRnFNL6Kusv9gfw1SNC.d6liP
F0tv9uD0uEoHTAlli5+RP+8vPQaw7ewNw1bacsyWHLI0tEBi384A7FmmGP0w
+fgOi5y8qmvA1FgowQ4R4ko16AwC.UEpVywCHEWBHvX.AZzzb.AxKQDzGaEr
WU1JbSEv05JWgGU36rs3w3O0gEqKZuAXA9ze.YaQYo+T.qjhfq1lI4gmHasE
Ct2Hy1pX3ORrs5ED+ojdEbRrstq8mp2Hx1J6Ixe7jfrs.ph.gWcp0mjYX3Up
2fV6w1erLCs1ks+XoCxBPY15YSMT1muTG.C25.HQ1yhVGbGyEerE3vUUXs5r
YpKJwZsQese1YzWqlIXrl9ZErwfdoZCGt0Y3Pcxewdvf+RBF23NvnFeuXOXH
dIAiOkjsG0tzInbJ1n1R1K0Ig2NY5bA0Sn5YT+o5YBXJEHQPl8T8LiTgo0AA
7fybyEq.QybWOTrFjEXIr2XIVPTHm3rwRzqJrr2.IRsFQmEFFRpisYr6+JdS
tbG8wk+Ge7gGblAOdUU4SzoYN9Kakn7GWr3iKqiCCQuVsCEIc1sGEm+YoO93
hjImRm.CU0Sus+93zrplG9kRNpf1kASQLtrjg+aoayN8AP2ktNeXeSNdEQDx
x6KDmanjU9W4AhQkMkfix+jCKyv8ojhGRe74dUBGYFMWwv6hW.B6jh33j2XL
DGZ2lolQzk+QxEFh6BCwMDaWk4M236C0FUQsy9vJBMDSBdZAYuJUxPxHZRVs
JK2gErj9blIBBt7ZU55rn6OEfz.UdgEfhrzfULwGQQhUh.mJuLhjybARpbyX
ORBB.jrr2OoQFzW1z3aoy4kKS24tbxjSbPMk.1VncrgWMEmHsZ1jjz1NSHEM
ZEpPGI2oQOfNteCcc5SYuYkMjdUPPcA5zRtlJvOHNNFKq6g1HTx4gNV904y9
x0N.HoB9tg1DiGOTdH3VoqSO5iIYQoeazN5nprXfpXhXpgg7dAeF1U.N2chb
PrINeENsXIJPrRfRQU+cEdCKDndqF4.q+6Udk6BLBuauxS6R2oQry8aCw2oa
4cYrx8F5dLNKwApWHcAsUMNz7jeoxv1ewrjEw+YDA3hIhnBhgf0qkgIjzMmd
nw8bWlrHB5Prr7aHhX7bDR6HJFzYhkWMzZmmYQPfCqQaJHybL.yapBBcx77X
GnEoOMUX8os9fxI6AXEIrMtMOKM9TfQrAUN07xvjxEghX1xlax52X5sMNKct
6PR8+yBjzMY8aw7MiHTtp7PldZCvg1oYBUqKmwyXJIzKPGXVt+VRjSrVpysu
xXoZkx6xXIgF3XoKhaomNbPvWsELlyXJIv9ggANycmOWz0o4ye0cHo.aGCmg
QuBlQxpjEKbnmFtV47LX1j.IDnxkaO5mSuKM65jjY2Ee+2bAGon2jHPk+FjY
50A46IB7j2mBlFMqXKJhd8NM5fFG3zSxlxcuUz8EaOTD.3hA0pjeQvkgOJMR
3KXlSRyfthRMv.a8pU8ftcY1Ru6T6XpDbarb33ScYV7PXbcVce7hjHPwN7BT
HemXtzXV8.CpHmeHTZ7IVPjFDGqeCUY6vB8a7jQPQ1KzWu+qth23xUJKOsfk
EcYv4TVRwmgB5tp62XFnkyPUBqenJ3BpZitJi1GTEICNT87VfBsVmDY25SfD
dy5Szg1TwdwdsChoeqyFENg4mSEF9LblTcPmGw4oWLKoGh9Gvna9gGhtM+ee
N+eW+CmzdhhX0ZlgvZN1C0uBxyk8HZwwGktc9l1rQGO0RutRQ7U3FEEqnASa
wOhavuOGt3GAzG7C6F761fE+z4uzV7C4F76lIiE2eZMY0TzPbPQJdH+g5O47
viiqrWl8GNdjCrkvRCQYFDdxrOMFL7TMX1RMdTYvQmlL+AloVyLy9CiZRs0K
Xw9bOBFVxL0Vb9o4yVklGM3lsTYU4YEUs3nP8RP23UP0AC.oNUokupo73dPv
V6PT+gfpor9DknmHyj.bPMJ3XUapstnH9CLSrUcl5OQiSngm5LoOVMPdgHiE
gGLisVcleZtUQpS3IgoRM2gu.pOUTxpWLxNUwVar2ebPgskeww9C2FiQA3vC
q4Wb+IfKLH.k49Xs2OlPBRFdvLx5zexBTYFFVEXJLN7J+CXT3U9G7IYN7lNr
0Uk.p+L2Rns3LgFfkLM+w7LDDfxbexLN7RQ1nZa37lrHanHtsdTjMXGoFa7A
oqKxFbmVhMFTHsfZ26EjJNBhhcMfxBH.UyYxVCnziohVR9tNERqcGbAlVrwG
aruZaCWq1gj8kgvUapQE8BPlh4EorBimRONIgClhQTLPVxT3TJgKtZKwgKN1
SkJNTpG3O1H9O+wko48fEyu+a06cGc2N2bqN6evujo.czTFAIn3qJOdYrBx6
hQkZk+tYrcljP4JlSmyks9rPBt7rnymET0Qc5DdRjC84XufVMX.JnLX6OItL
pvBiRPLcpPpdR.EJ9riHQSEHHgfZ6AAmAvJnmHPbfA6SRjW9jnTTatuFUOX1
edA5GOGo5F1XwMZqN41HWMGNSfCmEvAZJCr.Q8MARLZBDCag7vFQ4gXg7Hfi
m7PsQdHim7vrQdjil7r2ihVjGP80V1oxydCcd4wGos3yHIODakG3377xyFew
wdl8GfM1mQim7f7KGp1IOXOSdFO+oTom4eWXq8G7nHODaFuSFuwWDa7mRvdl
7Ld9uv1nOSf9k7fGuwWXaleAV5YxCa7jGah2XOg9kWdFu3ev1LdGOd92Q13u
.C8L7YDsOaS7FzQz+kMwqRGwmW1n+PGQ+W1L+cxHZe1l4CRFQ+WVEO13YelX
yyKHb7FvisY.Fg3YFnAdVFVGuAXPfMOvJJ8tizLdrIf08EZmNBypHf7KwQ3a
xy34f2p4CNdwGJrweAb7legvl3wFO2oBas8LRY60Fuo7wy6N0V3Yj7saSrpd
lmTgusZtiosPqDnwFffFiVc7r+.Y1NBabVdPnMS2ANhZPPq7eMhlDg.pmEfH
DP7K6h.rW4iGBPtLFH0tBJd0pumrdi96rTVl7T7uq1ATkb5cwVfU8xxcdzj0
Iee911Wt4klDu99uNOK49rmWq19R+gfM48E2m+58++HouNAO
-----------end_max5_patcher-----------