Mike's 6-Axis Articulated Robot

A spool of crimp pins for the JAE battery connections finally arrived in the mail. These were some of the smallest crimp pins I've ever used and I really struggled to get a good connection. This is a very small version of the "DuPont" style crimp pins shown in the diagram below.

Specifically this style of pin has two "wings". One is designed to crimp around the polymer insulation, and the smaller wings to crimp around the conductor. With these tiny pins, my crimper is simply too large to properly crimp the wings. Also the insulation, once crimped, manages to squeeze between both sets of wings leading to a poor connection. I finally settled on crimping both wings to the conductor. This worked nicely.

image294 (2).jpg

1652123125749.png

Here is the finished battery. It has the wires soldered to the connection tabs and is wrapped in kapton tape.

image289.jpg

Here are the crimped pins loaded into the connector.

image291.jpg

The procedure is pretty simple. The new battery is connected to the spare slot above the existing battery, then the old battery is removed.

image292.jpg

Swap completed!

image293.jpg

The procedure ends with resetting the Preventative Maintenance alarm date to 5/9/2024. Now the teach pendant does not message "REPLACE BATT." each time it is turned on.
 
Got a couple of small items done yesterday. First off, the replacement connector for the J2 motor electromagnetic brake arrived in the mail. I broke the retaining tab off the original one and I've been having issues with the brake engaging at runtime thanks to this connection. I bought the pin insertion and removal tool for this series of connectors, but it really didn't work. Ended up having to cut off the old connector and pins, and crimped on new pins and assembled the new connector. It snapped back together with a satisfying click and I haven't heard the brake clicking off while running anymore. Great success.

1652275617391.png

I also got the robot side of the tooling connector soldered up. Didn't get pictures of the inside of this one, but it looked exactly like the other connectors I built. The cable has (19) 20 AWG conductors which power both the solenoid valve bank inside the robot and the (10) pass through conductors to the end of arm tooling connector. I was somewhat surprised that there is not a cable that goes directly to the control box to control the valves. I'll have to assemble some sort of junction box to join the VALVE output cable to the TOOL cable going to the robot. I guess all applications are custom for this robot so they left it to the user to integrate the robot side tooling. I had to add 4 wraps of heavy shrink wrap to bring the cable jacket diameter up to the size of the clamp on the circular connector.

image296.jpg

image297.jpg

I'm noticing that the robot is not positioning quite perfectly. I think this started following my J2 gearbox cleanout. I need to re-do the master calibration and hopefully that will clear the issue up. The issue is apparent when using X-Y rotation mode. In this case, the robot should keep XYZ position and rotate about an imaginary point in the middle of the tool flange. This visually worked really well before, but now I see deviations. Not the end of the world, but it would be really nice to have it working properly.
 
Ha, seeing the Intel i960 on that board brings back memories.
 
Ha, seeing the Intel i960 on that board brings back memories.
OK, I know the i386/387 which is present on another part of the board, but couldn't find much on the i960? Call you tell me about it? Any cool stories?
 
OK, I know the i386/387 which is present on another part of the board, but couldn't find much on the i960? Call you tell me about it? Any cool stories?
It has been too long, I know I spent quite a while getting gcc to work as a Sun/Sparc hosted cross-compiler (or may it was a Sun i386) to feed into the i960. I also worked some with the i860 at the time, probably around 1990. The i960, as I recall, was intended as an embedded processors for operations not quite using an operating system, but needing some protected memory features and memory mapping IIRC. The i860 was an even weirder processor that could be set up to run either big or little endian, mostly targetted at being a very-long instruction word (VLIW) number cruncher. We (me and a guy working for me) ported our SCSI control code in attempt to build a board for a parrallel processing 6-DOF (degree of freedom) real-time ballistic missile simulator, the idea being to create a test bed for potential star-wars era ICBM interceptors. Early days of parallel computing, semaphores where a new concept at the time. I was exploring the possibility of an i960 front end on an i860 number cruncher, concurrently with trying the same thing with an i486 board, the newest in that line of processors from Intel at the time.

It was an interesting working environment, in a university research context. I was on a team of about a dozen research engineers, divided into two groups. I was the only US Citizen in my group, which meant I was the only one eligible for a clearance even though I was junior to many of the other full-timers. (Also several grad students). Learned lots about the radiation hardening electronics. We were scheduled to go into an underground nuclear detonation test with our development missile processor. Program was terminated (change of politics and the realization that a full up star wars missile defense system was not practical) before that actually came to pass.

It was my first full time job, before I finished my PhD. Was a lot of fun because I had the support to pretty much do whatever I wanted. I remember drawing up a simple CAD drawing of a multi-computer VME rack we could use to add to the unix machines we used to do VLSI design and test vector generation. It was a "lazy morning before a meeting" thing that I threw out at our group meeting, with a ballpark guess of cost. Just sort of a concept drawing/brain fart. After lunch, the program director (big boss) called me into his office and started asking me about it. Within 15 minutes I was told to "build it". When built it was also the first computer in our group connected to the internet, and we suddenly had email and a whole host of other stuff.

How do you cool a missile processor that includes a outer space component, and an expected runtime of maybe 10 minutes? Phase change of an appropriate quantitiy of "wax" was the answer. My first exposure to dealing with a real power budget question, as more power -> more heat -> more wax -> more mass -> more missile.
 
Last edited:
Been a while since I've last posted about this project, but some progress has been made and I wanted to share.

My latest focus has been to create a usable end of arm tooling (EoAT) that I can start messing around with. I bought a cheap used Destaco RP-5 robot gripper and needed to mount it to the end of the arm. I put up a drawing a ways back for this design, but unfortunately I did not account for some aspects of the size of the gripper in my design and it left screws inaccessible. I also just got the lathe and mill set up at the new house, so I was able to machine this.

I drafted up the entire assembly in Solidworks and here is what I came up with. The largest cylinder in the rear represents the critical dimensions of the robot's J6 tooling platter. The smaller cylinder with the flat on it is my custom adapter, and finally the green block is the RP-5 gripper without jaws installed.

image303.PNG

Here is the adapter puck. It is just shy of 2" in diameter and is made from 4140 steel. The large counterbored holes in the picture below mount this puck to the robot with M5x0.8 SHCS. There is a reamed hole for a 5mm dowel pin which fixes the rotational alignment of the gripper to the robot. A circular boss mates to a small recess in the back of the gripper to center it on the puck.

image301.PNG

From the rear, the circular recess fits snugly to the robot's tooling platter and locates the tool in X, Y, and Z. The dowel is all that is needed to fully locate the tool.

The machined flat serves two purposes. First it clocks the part when I flip it for machining so the two sides line up rotationally. Second, it creates the datum from which the J6 joint can be zeroed. When the flat is parallel to the floor and J1-J5 joints are zeroed, then J6 is also at zero.

image302.PNG

I forgot to get pictures of machining this, but it is a pretty simple part.

image298.JPG

image299.JPG

image300.JPG

The next step was wiring the Valve output cable to the robot tooling cable. This would best be done inside some sort of larger junction box, but for now I only did a basic solder job between the wires.

Here is the VALVE output cable. I traced the wire colors back to the pins on the connector.

image306.jpg

Here is the ugly splice job connecting the thicker robot tool cable to the thin VALVE cable.

image309.jpg

A simple program was written in the robot control to open and close the gripper at 500ms intervals. This program was run in a looping fashion to keep the gripper moving until the CYCLE STOP key was pressed on the teach pendant.

Code:
PROGRAM 20
0010 VON 5
0020 VOFF 6
0030 TIM 50
0040 VON 6
0050 VOFF 5
0060 TIM 50
0070 END

And here is a short video of the gripper running:


Next up is to design gripper jaws that can hold a variety of lego bricks and try to write a simple pick and place program. I'd eventually like to expand this idea to have it assemble complex lego designs.
 
Yesterday was another wildly successful day with the robot. First and foremost, I was able to redefine the J6 calibration position to match the data in the manual. J6 should have been calibrated against a bolt on the tool flange using the Denso calibration jig (shown below). I do not have this piece of tooling and while I could recreate the concept from their illustrations, it would not be accurate to sub thousandth of an inch dimensions to achieve a matching accurate calibration.

1656508304115.png

Instead, I brought the robot down flat to the table top and balanced a straight edge on the machined flat on the tooling adapter puck. Using a dial height gauge, I rotated J6 until the height at each end of the straight edge read the same. I then modified the calibration position of J6 to be 0.0000 degreees, and ran a single axis calset for the joint. Now, the joint position display reads 0.0000 degrees when the dowel pin hole is at the 9-o'clock position. Since my model in CAD uses this orientation, I was able to measure the offsets and angles to define the tool coordinate system.

Coordinate Systems and Tool Frames:
We need to have a quick discussion on the different types of coordinate systems and tool frames in the robot. The core of these are:
  • Global (base) coordinate system - located at 0,0,0 in the middle of the bottom of the robot mounting flange. Z axis points up, and X axis points away from the cables and ports on the rear of the robot. Most positions are displayed relative to this coordinate system.
  • Work coordinate system - multiple work coordinate systems may be defined. These move and rotate the origin point relative to the global origin. Useful for using the same program in multiple positions in the workspace.
  • Tool 0 - this is the default tool coordinate system with no offsets or rotations. The origin of this system is the center of the J6 tooling platter (picture above) with the dowel pin hole at the 9-o'clock position.
  • Tools 1-9 - these are the available tool offset frames. They allow robot motion to be described at the tip of the tool, accounting for any length offsets and rotations that might be applied.
1656511754352.png

While most are familiar with Euler angles (roll-pitch-yaw) to describe rotations an issue arises that there are actually 12 valid Euler angle representations which are often ambiguously defined when people discuss rotations. Roll-pitch-yaw usually indicated the XYZ Euler angle description, but different cultures may default to different conventions. There are other less ambiguous definitions of 3D rotations such as quaternions or rotation matrices, the latter of which is the method used by this robot. This is a bit of a complex topic but I'll link to some reading if you are interested:




And finally a calculator which converts between all the rotation descriptions: https://www.andre-gaschler.com/rotationconverter/

What matters to us is understanding that this robot expects the 3D rotation of the tool (and all programmed points) to be described as a rotation matrix which is unitary and orthogonal. To be unitary means that each coordinate system axis vector described by the matrix must be of length 1 (a unit vector). The robot control is kind enough to automatically reduce all vectors to length 1 if they were input with anything else. The vectors must also be orthogonal, which means to have all coordinate system axis vectors be at right angles to each other in 3D space. The control will complain to you if this is not achieved. Finally, a rotation matrix description is redundant as the 3rd vector in the coordinate system can be calculated from the first two following the right hand rule of coordinate system definitions and orthogonality. Thanks to this, the robot only requires 9 numbers to define a point, coordinate system, or tool offset.

The Denso robot used the following terminology: Approach Vector (aligned with the Z+ axis), Orientation Vector (aligned with the Y+ axis), and the Normal Vector (calculated from the other two and aligned with the X+ axis).

1656511713019.png

All position data is entered in the following format. The length of the vector defined by OX, OY, OZ must be of length 1 which can be calculated by sqrt(OX^2 + OY^2 + OZ^2). The same applies to the vector defined by AX, AY, AZ (the approach vector).

1656511732177.png

Following this logic, I needed to define TOOL 5, my pneumatic gripper. Tools are defined by TOOL programs which only contain the appropriate tool offsets. There are 9 user editable tool programs. These offsets are all applied from the J6 mechanical interface (platter) coordinate system.

1656512170374.png

From my Solidworks CAD model, I know the following critical dimensions are: Offsets in X and Y = 0mm, Offset in Z = 50.2520mm, Rotations about X and Y axes = 0 degrees, rotation about the Z axis = -135.000 degrees. This can be converted to the proper rotation matrix using formulas or the calculator above:
  • X = 0
  • Y = 0
  • Z = 50.2520
  • OX = .7071
  • OY = .7071
  • OZ = 0
  • AX = 0
  • AY = 0
  • AZ = 1
After applying these offsets and enabling tool 5, the robot correctly moves the joints to now control the rotations about the tip of the gripper jaws.

In this poorly filmed video, you can see the robot first establishing rotations about TOOL 0, the J6 tooling platter (behind the gripper interface), then it is stopped and TOOL 5 is enabled, followed by rotations about the tip of the gripper.

 
Last edited:
Using what I learned from the previous post, I wrote a simple, manually taught, pick and place program to move some lego bricks around. I got very lucky that the gripper without any jaws installed is the perfect width to grasp a 2x2 lego brick.

What amazes me is that this robot is repeatable enough to approach the lego brick without getting hung up. There is only a ~0.005" clearance between the open grippers and the lego.


The next step is to get a bit more familiar with the programming interface. Up until now, I've only taught positions manually from the teach pendant. This works but it is less than perfectly accurate as everything is lined up by eye. I want to offline code a program using point variables, then edit them with numerical data entry to get the orientations and positions perfect.

The robot is limited to 1200 8000 total lines of code shared across all programs. This is quite a bit, but still limiting for more complex operations. I'll need to familiarize myself with subroutine programming to reuse common sections of code like opening and closing the gripper, approaching a pick location, etc.
 
Last edited:
Got quite a bit more done from the programming side of the robot.

First task was to recreate a pick and place operation using variable defined positions rather than recorded points. This has a few benefits. First, you can reuse the same point many times without needing to teach that point over and over. Second, you can manually tweak the position and orientation as needed once the point is created.

There are 4 kinds of variables in the robot controller. Floating point, integer, joint point (6 float array), and position point (9 float array). You can have 1200 points (either joint or position) and 2047 each of floating point and integers.

I incorrectly stated that the controller was limited to 1200 lines of code. The correct value is 8000 lines of code shared between all programs/subroutines. You can have 100 programs, 100 subroutines, and 50 tools. Subroutines can be nested up to 16 deep. Each integer consumes 1/3 of a line of code, so adding 30 integers means you lose the ability to use 10 lines of code from the 8000. Floating point variables use 2/3 of a line of code, so adding 30 floating point variables means you lose the ability to use 20 lines of code from the 8000. Variables must be allocated manually and unused variables in the allocated count still reduce the number of lines you can use.

Here is the code I wrote to complete the program in the video below:

Code:
PROGRAM 30
0010 TOOL 5  //Setup tool offset
0020 VON 6  //Open Valve 5
0030 VOFF 5  //Close Valve 6
0040 TIM 50  //Delay 500ms
0050 ISP 50  //Set speed
0060 ACC 25  //Set Acceleration
0070 MV E,J0100  //PTP move to safe location in the air
---------------------------------------------------First Place----------------
0080 MVS E,P0101  //Linear move to approach point (exact)
0090 ISP 20  //Set Reduced Speed
0100 ACC 10  //Set Reduced Acceleration
0110 MVS E,P0102  //Linear move to pick location (exact)
0120 VON 5  //Open Valve 6
0130 VOFF 6  //Close Valve 5
0140 TIM 50 //Delay 500ms
0150 MVS E,P0101 //Linear move to approach point (exact)
0160 ISP 50  //Set full speed
0170 ACC 25  //Set full acceleration
0180 MVS E,P0103  //Linear move to drop approach point (exact)
0190 ISP 20  //Set Reduced Speed
0200 ACC 10  //Set Reduced Acceleration
0210 MVS E,P0104  //Linear move to drop point (exact)
0220 VON 6  //Open Valve 5
0230 VOFF 5  //Close Valve 6
0240 TIM 50 //Delay 500ms
0250 MVS E,P0103  //Linear move to drop approach point (exact)
0260 ISP 50  //Set Full Speed
0270 ACC 25  //Set Full Acceleration
---------------------------------------------------Second Place----------------
0280 MVS E,P0105  //Linear move to approach point (exact)
0290 ISP 20  //Set Reduced Speed
0300 ACC 10  //Set Reduced Acceleration
0310 MVS E,P0106  //Linear move to pick location (exact)
0320 VON 5  //Open Valve 6
0330 VOFF 6  //Close Valve 5
0340 TIM 50 //Delay 500ms
0350 MVS E,P0105 //Linear move to approach point (exact)
0360 ISP 50  //Set full speed
0370 ACC 25  //Set full acceleration
0380 MVS E,P0107  //Linear move to drop approach point (exact)
0390 ISP 20  //Set Reduced Speed
0400 ACC 10  //Set Reduced Acceleration
0410 MVS E,P0108  //Linear move to drop point (exact)
0420 VON 6  //Open Valve 5
0430 VOFF 5  //Close Valve 6
0440 TIM 50 //Delay 500ms
0450 MVS E,P0107  //Linear move to drop approach point (exact)
0460 ISP 50  //Set Full Speed
0470 ACC 25  //Set Full Acceleration
---------------------------------------------------Third Place----------------
0480 MVS E,P0109  //Linear move to approach point (exact)
0490 ISP 20  //Set Reduced Speed
0500 ACC 10  //Set Reduced Acceleration
0510 MVS E,P0110  //Linear move to pick location (exact)
0520 VON 5  //Open Valve 6
0530 VOFF 6  //Close Valve 5
0540 TIM 50 //Delay 500ms
0550 MVS E,P0109 //Linear move to approach point (exact)
0560 ISP 50  //Set full speed
0570 ACC 25  //Set full acceleration
0580 MVS E,P0111  //Linear move to drop approach point (exact)
0590 ISP 20  //Set Reduced Speed
0600 ACC 10  //Set Reduced Acceleration
0610 MVS E,P0112  //Linear move to drop point (exact)
0620 VON 6  //Open Valve 5
0630 VOFF 5  //Close Valve 6
0640 TIM 50 //Delay 500ms
0650 MVS E,P0111  //Linear move to drop approach point (exact)
0660 ISP 50  //Set Full Speed
0670 ACC 25  //Set Full Acceleration
---------------------------------------------------First Return----------------
0680 MVS E,P0103  //Linear move to approach point (exact)
0690 ISP 20  //Set Reduced Speed
0700 ACC 10  //Set Reduced Acceleration
0710 MVS E,P0104  //Linear move to pick location (exact)
0720 VON 5  //Open Valve 6
0730 VOFF 6  //Close Valve 5
0740 TIM 50 //Delay 500ms
0750 MVS E,P0103 //Linear move to approach point (exact)
0760 ISP 50  //Set full speed
0770 ACC 25  //Set full acceleration
0780 MVS E,P0101  //Linear move to drop approach point (exact)
0790 ISP 20  //Set Reduced Speed
0800 ACC 10  //Set Reduced Acceleration
0810 MVS E,P0102  //Linear move to drop point (exact)
0820 VON 6  //Open Valve 5
0830 VOFF 5  //Close Valve 6
0840 TIM 50 //Delay 500ms
0850 MVS E,P0101  //Linear move to drop approach point (exact)
0860 ISP 50  //Set Full Speed
0870 ACC 25  //Set Full Acceleration
---------------------------------------------------Second Return----------------
0980 MVS E,P0107  //Linear move to approach point (exact)
0990 ISP 20  //Set Reduced Speed
1000 ACC 10  //Set Reduced Acceleration
1010 MVS E,P0108  //Linear move to pick location (exact)
1020 VON 5  //Open Valve 6
1030 VOFF 6  //Close Valve 5
1040 TIM 50 //Delay 500ms
1050 MVS E,P0107 //Linear move to approach point (exact)
1060 ISP 50  //Set full speed
1070 ACC 25  //Set full acceleration
1080 MVS E,P0105  //Linear move to drop approach point (exact)
1090 ISP 20  //Set Reduced Speed
1100 ACC 10  //Set Reduced Acceleration
1110 MVS E,P0106  //Linear move to drop point (exact)
1120 VON 6  //Open Valve 5
1130 VOFF 5  //Close Valve 6
1140 TIM 50 //Delay 500ms
1150 MVS E,P0105  //Linear move to drop approach point (exact)
1160 ISP 50  //Set Full Speed
1170 ACC 25  //Set Full Acceleration
---------------------------------------------------Third Return----------------
1180 MVS E,P0111  //Linear move to approach point (exact)
1190 ISP 20  //Set Reduced Speed
1200 ACC 10  //Set Reduced Acceleration
1210 MVS E,P0112  //Linear move to pick location (exact)
1220 VON 5  //Open Valve 6
1230 VOFF 6  //Close Valve 5
1240 TIM 50 //Delay 500ms
1250 MVS E,P0111 //Linear move to approach point (exact)
1260 ISP 50  //Set full speed
1270 ACC 25  //Set full acceleration
1280 MVS E,P0109  //Linear move to drop approach point (exact)
1290 ISP 20  //Set Reduced Speed
1300 ACC 10  //Set Reduced Acceleration
1310 MVS E,P0110  //Linear move to drop point (exact)
1320 VON 6  //Open Valve 5
1330 VOFF 5  //Close Valve 6
1340 TIM 50 //Delay 500ms
1350 MVS E,P0109  //Linear move to drop approach point (exact)
1360 ISP 50  //Set Full Speed
1370 ACC 25  //Set Full Acceleration
---------------------------------------------------End of Program----------------
1380 MV E,J0100 //PTP move to safe location in the air
1390 END  //END of program




Position Table-----------------------------------
J0100 = Safe clearance position
P0101 = Approach point to pick location 1
P0102 = Pick location 1
P0103 = Approach point to drop location 2
P0104 = Drop location 2
P0105 = Approach point to pick location 3
P0106 = Pick location 3
P0107 = Approach point to drop location 4
P0108 = Drop location 4
P0109 = Approach point to pick location 5
P0110 = Pick location 5
P0111 = Approach point to drop location 6
P0112 = Drop location 6


One takeaway here is that the way I'm programming this is a very inefficient use of the limited lines of code in the controller. Each brick moved contributes 20 lines of code. I could still place ~400 bricks this way, but nothing more. In my next post, I'll explore the use of subroutines to offload the repetitive sections of code and reduce the program size.
 
Back
Top