# Mike's 6-Axis Articulated Robot



## macardoso

Hi All,

I'm very excited to share that after nearly 5 years of searching high and low, I have finally found a 6 axis robot that was affordable enough and the right size/shape for me to justify purchasing.




This robot is a 1999 Denso VS-6354CM 6 axis vertically articulated robot. These are the most flexible of all the robot types and can move around in 3D space, plus position the tool in any orientation (given that the workspace constraints allow it). This unit would typically be used for high speed, high accuracy, low payload applications. The previous owner had a air actuated dispensing tool on the end of the arm for spraying some sort of dark grey enamel or paint. There is a fair bit of overspray on the robot which I hope to find a solvent to remove, otherwise both the robot and controller are remarkably clean.

This was purchased from HGR.com, an industrial surplus supplier in Cleveland for less than $400. New robots of this size can run from $20k and up depending on options and software. I have never seen one sell this inexpensively so I had to jump on it. I plan to do a lot of research into this unit and hopefully get it running again. The robot did come with a matching controller and a teach pendant, however these are only 2 parts of the system needed to run the robot as the manufacturer intended. Many are currently available on eBay, however they total to more than the cost of the robot.

I plan to keep this thread formatted much like the project log for the other robot I own, a 4 axis SCARA robot. If you haven't seen that thread, check it out here: https://www.hobby-machinist.com/threads/mikes-scara-robot.84001/

*General:*

Manufacturer: Denso Robotics (Headquartered in Japan)
Model: VS-6354CM
Software Version: 9.57
Date Mfg.: December 6,1999
No. of Axes/Degrees Of Freedom: 6
Weight: 28kg (62lbs)
Payload: Up to 5kg (11lbs) with reduced dynamics. Rated dynamics at 1kg.
*System Part Numbers:*

Operation Station:
Teach Pendant Cable:
Robot Motor Cable:
Robot Encoder Cable:
Controller Power Cable:
IO Output 1 Cable:
IO Output 2 Cable:
IO Input Cable:
IO Valve Cable:
Floppy Drive:
Floppy Drive Cable:
Calibration Data File (Floppy Disk):
WinCAPS Robot File (Floppy Disk):
Parameter File (Floppy Disk):
*Kinematic Constants (Base Coordinates: X, Y, Z):*

Base/J1 Offset: (100mm, 0mm, 335mm)
J2/J3 Link Length: 255mm
J3/Wrist Center "P" Length: 285mm
Wrist Center "P"/Tool Flange Face: R75mm
Spherical Wrist
*Positioning:*

Positioning Repeatability: +/-0.0008" or +/-0.02mm
Positioning Accuracy: Not stated - determined by calibration, movement accuracy, joint length accuracy, etc. Usually within 0.005"
Max Reach at wrist center from center of base: 25.66" (652mm)
Min Reach at wrist center from center of base: 10.43" (265mm)
J1 Range: +/- 140 degrees (nominal)
J2 Range: +100/-55 degrees (nominal)
J3 Range: +73/-103 degrees (nominal) - this needs a double check
J4 Range: +/- 168 degrees (nominal)
J5 Range: +/- 120 degrees (nominal)
J6 Range: Continuous Rotary
J1/J2 Max Angular Speed (1kg payload): 176 degrees/s - Note 1
J3/J4/J5 Max Angular Speed (1kg pyload): 209 degrees/s - Note 1
J6 Max Angular Speed (1kg payload): 290 degrees/s - Note 1
XY Max Cartesian Speed (1kg payload): 857mm/s or 2024 inch/min or 1.9 mph - Note 1
J1 Calibration Position: 142.867
J2 Calibration Position: -57.6772
J3 Calibration Position: 164.806
J4 Calibration Position: 171.339
J5 Calibration Position: 126.247
J6 Calibration Position: 92.0430
Note 1: These speeds are not exact and are calculated from positioning time charts. Actual max speed would be somewhat higher since these figures include acceleration and deceleration.

*Motors:*

Motor Type: Panasonic Minas-A Series (I think). Licensed to DENSO with DENSO-only part numbers. Panasonic Part Numbers in *bold*.
Encoder Type: Tamagawa TS5643N151 98 17-bit absolute multiturn battery-backed serial encoders. This may differ between motors.
--------------------
J1 Part #: 410622-0491 (S/N: 11U15) *MSM022Q6U*
J1 Encoder Part #: ?
--------------------
J2 Part #: 410622-0501 (S/N: 11U15) *MSM042Q6V  *(Motor has 24VDC electromagnetic holding brake)
J2 Encoder Part #: ?
--------------------
J3 Part #: 410622-0511 (S/N: 11U16) *MSM022Q6V  *(Motor has 24VDC electromagnetic holding brake)
J3 Encoder Part #: ?
--------------------
J4 Part #: 410622-0551 (S/N: 11U16) *MSM5AZQ6Q*
J4 Encoder Part #: TS5643N151
--------------------
J5 Part #: 410622-0561 (S/N: 11U16) *MSM5AZQ6Q*
J5 Encoder Part #: TS5643N151
--------------------
J6 Part #: 410622-0571 (S/N: 11U16) *MSM5AZQ6Q*
Replacement J6 Part #: 410622-0631 (S/N: 01I10) *MSM5AZQ6Q*
J6 Encoder Part #: TS5643N151 98 (S/N: B32803E)
*Mechanical:*

J1 Gearing arrangement: Direct Drive to Harmonic Gearset
J1 Harmonic Gearset Ratio/Part #: 100:1 (calculated), P/N unknown
--------------------
J2 Gearing arrangement: Direct Drive to Harmonic Gearset
J2 Harmonic Gearset Ratio/Part #: 100:1, Harmonic Drive P/N: 25-100-921494-17
--------------------
J3 Gearing arrangement: Direct Drive to Harmonic Gearset
J3 Harmonic Gearset Ratio/Part #: 80:1, Harmonic Drive P/N: 20-80-921496-12
--------------------
J4 Gearing arrangement: Belt Drive to Harmonic Gearset
J4 Belt Ratio/Tooth Count/Part #: 1:1, 28T (driving) to 28T (driven), Belt: MBL S3M219
J4 Harmonic Gearset Ratio/Part #: 80:1, Harmonic Drive P/N: HS14-80-921773-14
J4 Total Gear Ratio: 80:1
--------------------
J5 Gearing arrangement: Belt Drive to Harmonic Gearset
J5 Belt Ratio/Tooth Count/Part #: 1:1, 28T (driving) to 28T (driven), Belt: ???
J5 Harmonic Gearset Ratio/Part #: 80:1, Harmonic Drive P/N: HS14-80-921773-5
J5 Total Gear Ratio: 80:1
--------------------
J6 Gearing arrangement: Belt Drive to Bevel gearset to Harmonic Gearset
J6 Belt Ratio/Tooth Count/Part #: Ratio: 1:1, 28T (driving) to 28T (driven), Belt: MBL S3M267
J6 Bevel Gearset Ratio/Tooth Count: Ratio: 1:1, 20T (driving) to 20T (driven)
J6 Harmonic Gearset Ratio/Part #: Ratio: 50:1, Harmonic Drive P/N: SF14-50-921826-4
J6 Total Pre-J5 Coupling Ratio: 1:1
J6 Total Post-J5 Coupling Ratio: 50:1
*Maintenance:*

Torque mounting bolts and gearbox bolts to spec (in Chapter 6 of manual) every 3 months (~250-500 hours of operation)
Clean controller fan filters every 3 months (~250-500 hours of operation)
Drain grease and pump new grease into each joint every 4000 hours of operation (1-2 years depending on duty cycle).
Apply grease to inside of plastic covers where wire bundles slide every 4000 hours of operation (1-2 years depending on duty cycle).
Replace encoder backup battery every 2 years.
Replace controller memory backup battery every 2 years.
Grease: Kyodo Yushi, MULTEMP AC-N high performance lithium grease made from synthetic hydrocarbon oil and synthetic ester oil.
*Electrical/Pneumatic:*

10 conductors for robot tool passthrough. Available on back of wrist.
1 air/process gas inlet. Internal solenoid valves. (3) double acting valves. (6) output ports available on back of wrist.
CN10 (Control Motor Power): JAE 24-28S
CN11 (Control Power Input): DDK 18-10 CE05 JAPAN
CN13 (Robot Motor Power): JAE 24-B28PC
CN20 (Robot Tool Input): JAE 25-24PC
*J1 Axis Motor Data:*

Rated Power (W): 200
Torque Constant (N*m/A_rms): *???*
Rated Torque (N*m): *???*
Peak Torque (N*m): *???*
Inertia (Kg*m^2): *???*
Poles Per Revolution (n): *???*
Winding Resistance (Ohms): *???*
Winding Inductance (H): *???*
Inductive Time Constant (ms): *???*
Rated Voltage (Volts): 200
Rated Speed (RPM): 3000
Maximum Speed (RPM): 5000
Continuous Current (A): *???*
Peak Current (A): *???*
Damping Coefficient (N*m/(Rad/s)): *???*
Voltage Constant (V_rms/k_RPM): *???*
Overload Limit (%): *???*
Acceleration (Rev/s^2): *???*
Thermal Model Parameters:
Rth-we (C/W): *???*
Cth-we (W*s/C): *???*
Rth-wa (C/W): *???*
Cth-wa (W*s/C): *???*

Flux Saturation Curve (% Nominal Inductance): Use 1.0 for all values
Brake: None
*J2 Axis Motor Data: *

Rated Power (W): 400
Torque Constant (N*m/A_rms): *???*
Rated Torque (N*m): *???*
Peak Torque (N*m): *???*
Inertia (Kg*m^2): *???*
Poles Per Revolution (n): *???*
Winding Resistance (Ohms): *???*
Winding Inductance (H): *???*
Inductive Time Constant (ms): *???*
Rated Voltage (Volts): 200
Rated Speed (RPM): 3000
Maximum Speed (RPM): 5000
Continuous Current (A): *???*
Peak Current (A): *???*
Damping Coefficient (N*m/(Rad/s)): *???*
Voltage Constant (V_rms/k_RPM): *???*
Overload Limit (%): *???*
Acceleration (Rev/s^2): *???*
Thermal Model Parameters:
Rth-we (C/W): *???*
Cth-we (W*s/C): *???*
Rth-wa (C/W): *???*
Cth-wa (W*s/C): *???*

Flux Saturation Curve (% Nominal Inductance): Use 1.0 for all values
Brake: 24VDC, power to release
*J3 Axis Motor Data:*

Rated Power (W): 200
Torque Constant (N*m/A_rms): *???*
Rated Torque (N*m): *???*
Peak Torque (N*m): *???*
Inertia (Kg*m^2): *???*
Poles Per Revolution (n): *???*
Winding Resistance (Ohms): *???*
Winding Inductance (H): *???*
Inductive Time Constant (ms): *???*
Rated Voltage (Volts): 200
Rated Speed (RPM): 3000
Maximum Speed (RPM): 5000
Continuous Current (A): *???*
Peak Current (A): *???*
Damping Coefficient (N*m/(Rad/s)): *???*
Voltage Constant (V_rms/k_RPM): *???*
Overload Limit (%): *???*
Acceleration (Rev/s^2): *???*
Thermal Model Parameters:
Rth-we (C/W): *???*
Cth-we (W*s/C): *???*
Rth-wa (C/W): *???*
Cth-wa (W*s/C): *???*

Flux Saturation Curve (% Nominal Inductance): Use 1.0 for all values
Brake: 24VDC, power to release
*J4/J5/J6 Axis Motor Data: *

Rated Power (W): 50
Torque Constant (N*m/A_rms): *???*
Rated Torque (N*m): *???*
Peak Torque (N*m): *???*
Inertia (Kg*m^2): *???*
Poles Per Revolution (n): *???*
Winding Resistance (Ohms): *???*
Winding Inductance (H): *???*
Inductive Time Constant (ms): *???*
Rated Voltage (Volts): 100/200
Rated Speed (RPM): 3000
Maximum Speed (RPM): 5000
Continuous Current (A): *???*
Peak Current (A): *???*
Damping Coefficient (N*m/(Rad/s)): *???*
Voltage Constant (V_rms/k_RPM): *???*
Overload Limit (%): *???*
Acceleration (Rev/s^2): *???*
Thermal Model Parameters:
Rth-we (C/W): *???*
Cth-we (W*s/C): *???*
Rth-wa (C/W): *???*
Cth-wa (W*s/C): *???*

Flux Saturation Curve (% Nominal Inductance): Use 1.0 for all values
Brake: None







Again, not much of a machining project, but I enjoy this community and hope you will follow along!

-Mike

I think this is the last robot my wife will let me bring home 

EDIT 1/31/2022: Added data from manuals. Added some motor data.
EDIT 2/3/2022: Added missing motor part numbers. Added some motor data.
EDIT 2/8/2022: Added info about replacement J6 motor and mechanics information on J4, J5, J6.
EDIT 2/10/2022: Added mechanics information on J1, J2, J3
EDIT 2/14/2022: Corrected gearbox ratio
EDIT 3/3/2022: Confirmed J3 gear ratio, added J3 gearbox part number


----------



## macardoso

Couldn't resist taking some of the covers off the robot right away. Some beautiful mechanics under the hood. They get complicated in some places since the cables need to be routed around in a way that they don't snag or bend too sharply as the robot contorts into various positions.













One motor for the Joint 6 rotation is removed in the image below.




And the inside of the controller:




Look at that pair of Intel i386 DX/387 DX! I got a big smile seeing those!




A screen shot of 1 of the 6 servo amplifiers inside this box.


----------



## rabler

Any idea what you will use it for?


----------



## macardoso

rabler said:


> Any idea what you will use it for?


Right now, it will be very much about the journey, rather than the destination. I love reverse engineering old stuff and getting it working. My last robot took me well over a year to get it fully operational, so I expect this will fall into that same level of difficulty. 

Things I could do with it:

Load tools into my CNC mill
Load parts into my CNC mill
Both at the same time 
Attach a small router/milling cutter and generate full 5 axis machining motion
Silly assembly/workcell tasks
Take it to the nearest high school or First robotics team to get kids interested in STEM.


----------



## Boswell

Awesome score.  I really enjoyed your 4-axis robot recovery/restore so I am eagerly looking forward to following you on this one.


----------



## rabler

macardoso said:


> Right now, it will be very much about the journey, rather than the destination. I love reverse engineering old stuff and getting it working. My last robot took me well over a year to get it fully operational, so I expect this will fall into that same level of difficulty.
> 
> Things I could do with it:
> 
> Load tools into my CNC mill
> Load parts into my CNC mill
> Both at the same time
> Attach a small router/milling cutter and generate full 5 axis machining motion
> Silly assembly/workcell tasks
> Take it to the nearest high school or First robotics team to get kids interested in STEM.


No tool needs a justification, so ‘the journey’ is a great reason.  I’m watching this thread with fascination.  I remember building gcc as a cross compiler, cobbling together a memory mapped interface to a Sun 3 workstation, and writing a bare-bones SCSI i/o routines to load programs and save data from a 386/387.  We were building parallel simulation machines.


----------



## macardoso

The robot is pretty good shape, but there a few problems that I already know of:

The Joint 6 motor (the smallest one) is binding up. Could be bad bearings, corrosion, or a bent shaft. The encoder looks good and the phases check out without shorts or opens. I might be able to repair it, but replacements, even if available could be $200-300.
The robot is covered in overspray from whatever dispensing process it was doing before. I haven't found a solvent yet that cleans it up. This is purely cosmetic, but I want this thing to shine!
The motors have Tamagawa serial encoders in them. This limits my options significantly to select a replacement servo drive to run them. The encoders are absolute multiturn (good) but need a battery backup in them or the data is reset to 0 (bad). The battery was last changed in 2011, so I can pretty much guarantee it is dead.
The robot has no homing switches. Thanks to the absolute encoders, no homing is needed. However if the encoders zero out, the calibration is lost and the robot has no idea where it is. (EDIT: See Note below)
The calibration is stored in the robot controller, and I don't have any way to read it without buying all the pieces I am currently missing. This data too is likely stored is battery backed memory. I expect this battery to also be dead and all robot parameters and program data to be lost.
The J2 motor/gearbox is incredibly stiff and I've barely budged it. I hope this is not related to a damaged motor and gearbox and is more a function of how large of a motor/gear ratio there is at that joint and how much friction exists to backdrive it.
The J3 motor is moderately stiff. I hope this is not related to a damaged motor and gearbox and is more a function of how large of a motor/gear ratio there is at that joint and how much friction exists to backdrive it. This one is a lot better than the J2 which makes sense since it takes less load in operation.
This robot is out of support from DENSO for over 15 years. They were kind enough to give me the manuals, however I was told there would be no more support. I think I can only call in once or twice more before they cut me off, so I need to carefully pick which questions I want to ask.
The motors have DENSO branded labels on them, but I'm 95% sure they are Panasonic servos. Depending on how amenable Panasonic is to helping me, it might be VERY difficult to get the data I need on the motors to get them running on 3rd party drives. Sometimes these specially branded components come with contracts that prevent companies like Panasonic from supporting me. Age is on my side as many of these products are fully discontinued and everyone understands there is essentially no commercial reason to keep things secret anymore.
The manual for this robot omits any data about the motors, gearboxes, or pinouts for the various cable harnesses.
EDIT: J6 motor is toast. The permanent magnet rotor fragmented and cannot be repaired. I have to replace this unit.

EDIT: If I had actually read the manual, I would have known that the J2 motor and J3 motor have 24VDC holding brakes on them. I really shouldn't have been trying to force them around by hand with the brake engaged. On the plus side, I feel it less likely that there is gearbox or motor damage on those axes. The "brake" option was a different model robot and I assumed that because I didn't have it, my robot had no brakes whatsoever.

NOTE: There is a sticker on the robot which has all of the angular offsets at the CALSET position (basically hardstops on all axes). I should be able to use these numbers to calibrate the robot for the kinematics. My last robot did NOT have these numbers and it was a pain to measure them. Not even sure how I would do that with this one. It was very nice that DENSO included them. Additionally, the manual entails a procedure to zero out the encoders when powered to store their position at CALSET. Assuming the robot has never been crashed, this should be good. I am missing the J6 calibration fixture, so that axis' CALSET number will not be any good, but it is also the easiest to measure and is somewhat arbitrary. The rest are very important for the kinematics.

From the manual:


----------



## macardoso

rabler said:


> No tool needs a justification, so ‘the journey’ is a great reason.  I’m watching this thread with fascination.  I remember building gcc as a cross compiler, cobbling together a memory mapped interface to a Sun 3 workstation, and writing a bare-bones SCSI i/o routines to load programs and save data from a 386/387.  We were building parallel simulation machines.


I pride myself in a wide swatch of knowledge, but I have absolutely no clue what half of what you said means


----------



## rabler

macardoso said:


> I pride myself in a wide swatch of knowledge, but I have absolutely no clue what half of what you said means


University project, we were building a special purpose computer to provide real-time simulation of ballistic missiles and missile interceptors.  Reagan era star wars.  Idea was a test bed for potential “brains” for those interceptors.  It used 32 cpus.  Couldn’t run a regular operating system on the processors due to real-time constraints.  I was working on a 2nd gen machine, upgrading from 286 to 386.  Hardware, software, and disk storage …


----------



## macardoso

rabler said:


> University project, we were building a special purpose computer to provide real-time simulation of ballistic missiles and missile interceptors.  Reagan era star wars.  Idea was a test bed for potential “brains” for those interceptors.  It used 32 cpus.  Couldn’t run a regular operating system on the processors due to real-time constraints.  I was working on a 2nd gen machine, upgrading from 286 to 386.  Hardware, software, and disk storage …


Wow, that is an awesome application. It's amazing that a lot of that stuff is likely still running on 80's hardware.


----------



## macardoso

Attached the PDF manual that I received from DENSO. Had to compress it and split into 6 parts to fall within H-M's limit of 4MB per attachment.


----------



## C-Bag

macardoso said:


> I love reverse engineering old stuff and getting it working.


wow, proves my theory that there is someone for every imaginable task.  I'm not an electronics guy so it's a no go for me. But to incorporate a smaller arm into my process is a long wished dream. I'm watching the prices of those small robot arms come down with interest.


----------



## macardoso

Here is an overview of the system as DENSO intended.






The required components are

Robot - Have it!
Robot Controller - Have it!
Operating Panel - Missing ($250 on ebay). From tables in the manual, the teach pendant covers all the functions of the operator panel.
Power Cable - Missing, unknown part #. 
Robot power cable - Missing, unknown part #
Robot encoder cable - Missing, unknown part #
Manuals - I have the important one, missing the programming manual
Spare Fuses - Missing, not important, easy to replace
Initialization Floppy Disks - Have the WinCAPS software thanks to DENSO (runs on Win95 or Win98). Missing disk 2, calibration data
The optional components are:

IO cables, (1) Digital Input, (1) Valve Control, (2) Digital Output, all missing, some available on eBay for (~$150 each)
Teach Pendant - Have it!
Teach Pendant Cable - Missing
Extension cables - Don't need them.
Cooling Fan system for controller - Don't need it
Floppy Disk Drive - Needed to load calibration data and offline programs
WinCAPS software - Have it!
Data Disk for specific robot to enable with WinCAPS - Missing

Here is a nice illustration of the robot's main components:




Pictures of the controller connections:






A drawing of the Operating Panel (which I don't currently have):




And the specifications for my model of robot (highlighted in Yellow):




A nice drawing of this robot's working area:






Graphic of robot connections:




Built in solenoid valve specifications:




And controller specifications:



And the teach pendant drawing:




Will have to dive into a lot more detail in a later post, but here are the 6 possible poses with this robot.




And all 8 possible poses. Some are unreachable due to mechanical limitations of this robot.


----------



## rabler

Looks like you got lucky with someone at DENSO willing to share some things.  Would be nice to find the programming manual.  Hopefully the missing cables are something you can find the right pin-outs for and just make up yourself.


----------



## macardoso

So I hinted at this in my earlier posts, but I have 4 options to get this running:

Get all the required components for this robot's original system and run it as the manuals entail.
Scrap the original controller and run the robot on Allen Bradley PLC and servos. This is how I got my other robot running.
Kinetix 2000 (which I have) or Kinetix 5300 (which I don't have) servo drives *might* be able to run the motors without any changes (compatible feedback).
A feedback converter board may allow me to run these motors with any servo drive (difficult task, only if absolutely necessary).

Find servo drives which are compatible with the feedback from the motors and can use Step/Dir commands. Run on LinuxCNC on a PC.
Find servo drives which are compatible with the feedback from the motors use Robot Operating System on a PC.
I'm leaning towards #2 since I could use a unified program to run either of my robots (or run them together), but perhaps I could find what I need to try either #1 or #2.


----------



## macardoso

rabler said:


> Looks like you got lucky with someone at DENSO willing to share some things.  Would be nice to find the programming manual.  Hopefully the missing cables are something you can find the right pin-outs for and just make up yourself.


Yes, they were very helpful so far. Adamant that they wouldn't provide support but definitely got me going with manuals and software. I have a ton of questions to ask them, so I need to order them in order of most to least important. Maybe I can get a few more answered before they block my phone #!

I expect I'll need info from DENSO, Panasonic, and Tamagawa (makes motor encoders).


----------



## macardoso

Here is a snip from a Panasonic Minas A1 and A3 manuals (attached).  The part numbers are not quite right, but they are close. Even if DENSO has some special options added, the motor electrical parameters would most likely match the off the shelf motors from Panasonic.

Here is the J6 motor for example: MSM5AZQ6Q

I'm guessing, low inertia (MSM vs MSMA, probably the same thing), 50W, 100/200V.  Q6Q is likely: Custom Encoder, Custom Motor Specification, Custom Motor Structure.





Additionally, the Panasonic manual has the best description of the serial packet framing of the encoder I have seen yet.











Also found an old MSMA manual containing just a bit of the motor data I need. Attached.


----------



## macardoso

Went back an edited some earlier posts. Apparently the J2 and J3 motors have electromagnetic holding brakes which lock the motor when power is removed. The manual clearly showed this, but I missed it. These brakes keep the robot from falling over when power is removed. 

This explains why I was unable to move J2 at all and why J3 was so difficult to move by hand. It is bad for the brakes to force them to move while engaged, so I'm going to cross my fingers that I did not do damage. 

There was an option for this robot to have brakes on all axes, but this does not have that option. I guess I assumed that since mine didn't have them on all joints, then it didn't have them on any.

Notice the 3 connectors on the J2 motor below. The big one on the far right is the encoder, the 4 pin one in the middle is the motor power + GND, and the 2 pin one on the left is the brake. The red 2 pin connector, tucked along the side of the motor, is the place to short out the encoder when the robot is in the CALSET (calibration set) position to zero the encoder counts. This is necessary if the robot has crashed, gone too fast, or the batteries backing up the encoder data have died.


----------



## rabler

Mike,
Not on your "what to do with the robot" list, but you keep showing soft drinks and bottled water in the background, so I've got to think you're going for the robotic bartender


----------



## matthewsx

macardoso said:


> -Mike
> 
> I think this is the last robot my wife will let me bring home


----------



## macardoso

Well, first bit of bad news. From an earlier post I mentioned the J6 motor was binding up and was extremely hard to rotate by hand. These should be buttery smooth. Anyways, I just learned that the motor is fragged. No hope of saving it.

I used a bearing puller to gently remove the stuck pulley.



There was some dark grit right at the rubber shaft seal, but nothing concerning. The seal surface was in good condition. Some grease behind the seal likely improves water protection.



Pulling the front casting revels the stator windings. The front bearing spins smoothly.



Removing the rest of the covers allowed me to see what was going on inside. At this point I suspected a fully seized rear bearing.



But alas, removing the stator coils revealed a shattered rare earth permanent magnet on the rotor. I have no way to repair this. There is no sign of impact to the motor or a crash of the robot. I can only guess that this was a defective motor or the motor ran away at a high overspeed and destroyed the rotor with centrifugal forces.



So the J6 motor is trash. My options are to replace with an identical part, or to replace it with a comparable servo motor like an Allen Bradley TLY series motor with -B feedback (Tamagawa 17-bit serial).

If I want to run this on the original control, I think I will need to find a 1:1 replacement. Sucks...


----------



## macardoso

Well double bummer. This motor is not easy to find. Found one ebay listing for $730 from China (I put in a super lowball offer), and a few from some sketchy online sites. Messaged them all but I don't expect to be able to get the exact one.

Another option would be to find the corresponding Panasonic motor and rework the connector. If I found an electrically identical unit, then I could fix the mismatched connectors or mechanical interfaces easy enough. The Panasonic MSMA5AZS1A looks to be the identical motor with different connectors on the wires, different wire/housing interfaces, and a straight shaft vs 2 flats. This would likely be my best bet. I currently see 12 under $200 from China on eBay.

Finally I can look for what motor options I have floating around in my box of goodies. Without home switches, it will need to be an absolute encoder. Also, unless the motor I have has the exact same electrical properties and encoder, I'd never be able to use the original control box. Ugh.


----------



## strantor

For replacement of the motors and drives, you might want to consider something a little more agnostic. I am not very familiar with Panasonic servos but if I'm going to assume it's one of those proprietary affairs where you use the Panasonic software for the Panasonic drive, and in the software you have to select a Panasonic motor part number in the list which tells the drive everything it needs to know about inertia, LCR, brake, etc. and there is no provision for entering these values manually. 

From your previous posts I take it you're an Allen Bradley/Rockwell guy so I'm sure you're familiar with the Ultra 3000 and Ultra 100 drives. These are dime a dozen on eBay and great drives you can use with just about any servo motor. 

Do you have any reason for sticking with the Minas drives?


----------



## macardoso

strantor said:


> For replacement of the motors and drives, you might want to consider something a little more agnostic. I am not very familiar with Panasonic servos but if I'm going to assume it's one of those proprietary affairs where you use the Panasonic software for the Panasonic drive, and in the software you have to select a Panasonic motor part number in the list which tells the drive everything it needs to know about inertia, LCR, brake, etc. and there is no provision for entering these values manually.
> 
> From your previous posts I take it you're an Allen Bradley/Rockwell guy so I'm sure you're familiar with the Ultra 3000 and Ultra 100 drives. These are dime a dozen on eBay and great drives you can use with just about any servo motor.
> 
> Do you have any reason for sticking with the Minas drives?


Well you seem to have a great view into my head  

I won't comment about whether or not I work at Rockwell since I am often posting about hacking stuff to make it work in ways they may or may not want people doing. I'll leave that to your imagination.

This time around, I actually have the matching original robot control for this robot. It uses completely custom boards and drives and does NOT contain any panasonic drives that I can see. Everything is DENSO branded and designed I am assuming. The servo amplifiers are "dumb" and receive (from my initial look into this) a torque command and produce AC output. These amplifiers do not have any closed loop control circuitry that I can identify. Based on this, I believe the DENSO motherboard running i386 DX, i387 DX, and i960 processors handles all the serial communications to the encoders, all the closed loop motor control, and all the motor model parameters. I can almost guarantee that stuff is not exposed to the user. If I want to have the option to use the original control, then I need to replace the motor with an identical or electrically identical motor.

I have a handful of Ultra 3000 and Kinetix 2000 drives from work that I can play with. The Ultra 3000, when used standalone, allows you to create custom data for any motor (provided you can get it) and run a wide variety of feedback types. From the manual:



The last robot I had ended up with Incremental w/ Halls after my feedback converter board. The "Intelligent" encoders referenced in the Manual are Sick Stegmann Hiperface encoders. Unfortunately, these drives do not support Tamagawa Absolute Serial encoders. Additionally, if you try to run the drive over SERCOS fiber-optic (the easiest way to get the drive to get commands from the PLC in "integrated" mode) you lose the ability to custom define motors without Rockwell supplied Custom Motor Files (.cmf). I figured out how to generate my own, but there is a lot of firmware level nonsense that makes this really tricky to get working, hence why Rockwell prefers to supply known good CMF files for their partner companies only.

The Kinetix 2000 suffers from the same CMF issue, although I have somewhat worked around this in the past. These rack based drives would be perfect for running these motors and even natively support Tamagawa 17-bit serial encoders, although the jury is still out if the Rockwell supported Tamagawa encoders match, or are compatible with, the Tamagawa encoders in my motors. I also see that the Tamagawa encoders on Rockwell motors are programmed with the motor data, so I don't know if the firmware will allow me to use unprogrammed motors, or if I can program them myself with the proper meta-data to make this all work.




So the last comment was replacing them with some agnostic motors and yes, this is an option, but it means the robot will never run on the original control again, and it would be difficult (and expensive) to find the right sized motors with compatible mechanical dimensions and electrical performance. I'd have to find matching servo drives for these as true agnostic motors really do not exist (more money) and I'd have to find a way to get these controlled by the Rockwell PLC (needed for robot kinematics) which pretty much limits me to analog interface modules (1756-M02AE).

Rockwell has new drives, the Kinetix 5100 and Kinetix 5300, which support Tamagawa 17-bit serial feedback and are on the more "open" Ethernet/IP platform which allows users to avoid the CMF files and enter data by hand, however I don't have any of these, and since they are newer, I doubt I'll get any to screw around with. I would probably have the same meta-data issue as well.




Finally, reusing the existing motors only works if Panasonic is really nice and provides me the (sometimes proprietary) motor electrical characteristics. I might be able to measure some, but I've never done that before.

Interfacing to the servos is the hardest part of this robotics nonsense in my opinion.

-Mike


----------



## strantor

macardoso said:


> Well you seem to have a great view into my head
> 
> I won't comment about whether or not I work at Rockwell since I am often posting about hacking stuff to make it work in ways they may or may not want people doing. I'll leave that to your imagination.


Well my imagination didn't have to work very hard to fill in the blanks there. Maybe I'm just an imaginative guy...


macardoso said:


> This time around, I actually have the matching original robot control for this robot. It uses completely custom boards and drives and does NOT contain any panasonic drives that I can see.


My bad. I thought I saw something about minas drives earlier. I was skimming, so maybe you were commenting on the lack of them. Or my imagination filled in the blanks again.



macardoso said:


> Everything is DENSO branded and designed I am assuming. The servo amplifiers are "dumb" and receive (from my initial look into this) a torque command and produce AC output. These amplifiers do not have any closed loop control circuitry that I can identify. Based on this, I believe the DENSO motherboard running i386 DX, i387 DX, and i960 processors handles all the serial communications to the encoders, all the closed loop motor control, and all the motor model parameters. I can almost guarantee that stuff is not exposed to the user.


Gross.


macardoso said:


> If I want to have the option to use the original control,


Preserving the original control will be at the bottom of my list of priorities when I get a robot unless it's delivered as a complete working system. Different strokes for different folks. I find much more gratification in designing my own stuff, then trying to patch up someone else's. Especially when they've gone so far out of their way to prevent you doing so.


macardoso said:


> then I need to replace the motor with an identical or electrically identical motor.
> 
> I have a handful of Ultra 3000 and Kinetix 2000 drives from work that I can play with. The Ultra 3000, when used standalone, allows you to create custom data for any motor (provided you can get it) and run a wide variety of feedback types.
> View attachment 394815
> 
> 
> So the last comment was replacing them with some agnostic motors and yes, this is an option, but it means the robot will never run on the original control again, and it would be difficult (and expensive) to find the right sized motors with compatible mechanical dimensions and electrical performance. I'd have to find matching servo drives for these as true agnostic motors really do not exist (more money) and I'd have to find a way to get these controlled by the Rockwell PLC (needed for robot kinematics) which pretty much limits me to analog interface modules (1756-M02AE).
> 
> Rockwell has new drives, the Kinetix 5100 and Kinetix 5300, which support Tamagawa 17-bit serial feedback and are on the more "open" Ethernet/IP platform which allows users to avoid the CMF files and enter data by hand, however I don't have any of these, and since they are newer, I doubt I'll get any to screw around with. I would probably have the same meta-data issue as well.


[...]


macardoso said:


> Finally, reusing the existing motors only works if Panasonic is really nice and provides me the (sometimes proprietary) motor electrical characteristics. I might be able to measure some, but I've never done that before.


Inertia can be measured. LCR can be measured. Back emf can be measured. You can get an LCR meter on amazon/ebay for cheap. I've got one, not sure how accurate it is, but it's better than nothing.

An idea that just occurred to me (disclaimer: I've never done this): when you auto tune an induction motor with a VFD in sensorless vector mode, it measures all these electrical characteristics of the motor for you. If you autotune in sensored vector it also measures the inertia. A lot of higher end VFDs support permanent magnet motors. I'd bet $20... no, make that $5, that if you connect your servo motor with a 4096ppr incremental encoder on its business-end shaft to just about any modern full-featured VFD and run an auto tune, it would spit out most if not all the data you would need.

P.s. check out SEW servo drives. They allow you to put in the numbers for non-SEW motors and there's no *.xyz files involved.


----------



## macardoso

I did have the thought that this catastrophic failure is likely the reason this robot was removed from service. Batteries were last changed in 2011 which puts the date of failure more recently than that. Support and spare parts ended for this robot 15 years ago so the previous owners probably couldn't easily repair the unit. Wish nothing was wrong, but given that I found such a big failure I doubt there are any other major issues lurking. Hope I don't jinx it...


----------



## strantor

macardoso said:


> I did have the thought that this catastrophic failure is likely the reason this robot was removed from service. Batteries were last changed in 2011 which puts the date of failure more recently than that. Support and spare parts ended for this robot 15 years ago so the previous owners probably couldn't easily repair the unit. Wish nothing was wrong, but given that I found such a big failure I doubt there are any other major issues lurking. Hope I don't jinx it...


Where I work there are 2 robots and the encoder batteries get changed annually. Our PM schedule is rather... well, like a list of suggestions rather than decrees. Compressor oil might get changed at 2k hours like the manual says or it might get pushed back until someone _has_ _time_ to do it; nobody _makes_ _time_ for that. Air filters, bearing replacements, chain stretch measurements, gearbox oil changes, belt replacements, etc., all of it. But the encoder batteries different; they get changed on the day they're supposed to, with religious fervor. I suspect this behavior is driven by past experience and anywhere else that has robots and maintenance guys that have been around a while, would probably operate the same way. So, I would estimate time of death closer to 2011 than to 2022.


----------



## Cadillac STS

Can you use a motor with a double shaft front and back and put the original encoder back end on it?  Get a motor same specs and just replace that part leaving all the feedback servo encoders in place?


----------



## macardoso

strantor said:


> Preserving the original control will be at the bottom of my list of priorities when I get a robot unless it's delivered as a complete working system. Different strokes for different folks. I find much more gratification in designing my own stuff, then trying to patch up someone else's. Especially when they've gone so far out of their way to prevent you doing so.


So my thought is this. The original control is more or less ready to run (especially since I own the teach pendant). I'm missing these components (items in *bold *are things I'll need regardless):

Controller Power Cable
*Robot Motor Cable*
Teach pendant Cable
*Robot Batteries*
Control Batteries
So I'm pretty close to a minimum viable system, although the full system needs lots of other optional components. Missing cables could be homemade if needed. Having the control working as-is would mean I could teach the robot a program and move it around. I'd be a bit limited in complexity of programming and without the floppy drive backup system, I could only have 1 program and no parameter backup, but still functional.

My last robot took me about 18 months to get running on an AB PLC. I think I could go faster this time, but there are a lot of unknowns on the path, and having it working with the old control would be a big plus to me - even just for fun. I think I'd still want to get it running on the AB PLC due to the advanced capabilities to take advantage of.



strantor said:


> Inertia can be measured. LCR can be measured. Back emf can be measured. You can get an LCR meter on amazon/ebay for cheap. I've got one, not sure how accurate it is, but it's better than nothing.
> 
> An idea that just occurred to me (disclaimer: I've never done this): when you auto tune an induction motor with a VFD in sensorless vector mode, measures all these electrical characteristics of the motor for you. If you autotune in sensored vector it also measures the inertia. A lot of higher end VFDs support permanent magnet motors. I'd bet $20... no, make that $5, that if you connect your servo motor with a 4096ppr incremental encoder on its business-end shaft to just about any modern full-featured VFD and run an auto tune, it would spit out most if not all the data you would need.
> 
> P.s. check out SEW servo drives. They allow you to put in the numbers for non-SEW motors and there's no *.xyz files involved.



Measuring that data could be pretty reasonable. I have access to lots of drives to borrow from work. doing that might be possible. There are some touchy parameters, like the voltage and inductive time constants that I'd much rather get published data for, but if I can't, there is a possibility to measure them.

I'll check out the SEW drives for sure. One of the biggest limitations is sticking to an architecture that incorporates the robot kinematics. The full path planning and kinematics pipeline is too complex for a hobbyist to reasonable code from scratch so, at least as I know right now, I'm stuck with:

Original robot control
Rockwell PLC (one of only a few companies I know that do "open" robotics integration) with a small number of compatible servo drives. Analog interfaces won't permit use of the existing encoders.
Laptop running LinuxCNC and special hardware interfaces
Some application of ROS (Robot Operating System) which I know nothing about.


----------



## macardoso

strantor said:


> Where I work there are 2 robots and the encoder batteries get changed annually. Our PM schedule is rather... well, like a list of suggestions rather than decrees. Compressor oil might get changed at 2k hours like the manual says or it might get pushed back until someone _has_ _time_ to do it; nobody _makes_ _time_ for that. Air filters, bearing replacements, chain stretch measurements, gearbox oil changes, belt replacements, etc., all of it. But the encoder batteries different; they get changed on the day they're supposed to, with religious fervor. I suspect this behavior is driven by past experience and anywhere else that has robots and maintenance guys that have been around a while, would probably operate the same way. So, I would estimate time of death closer to 2011 than to 2022.


Yeah that's what I've learned. If the batteries go dead and you shut down the power to the robot, you're SOL. Have to do a full recalibration (which might mean hiring someone to come in). If the control goes dead, then you better have that floppy disk with the parameter restore or it is a dumb box.

Recalibration with this robot seems trivial, which is good news, but the missing controller parameter files is a real risk to getting this working with the original box.


----------



## macardoso

Cadillac STS said:


> Can you use a motor with a double shaft front and back and put the original encoder back end on it?  Get a motor same specs and just replace that part leaving all the feedback servo encoders in place?


Yeah, that'd work, but finding an electrically identical motor would likely be nearly impossible unless it were from the exact same series that this one was made from.  I think I could substitute a non-DENSO motor made by Panasonic at the same timeframe, because I doubt Panasonic retooled their motor winding line to make special motors for DENSO. But I don't think I could take a 50W Allen Bradley motor and get the original control to run it.

Slim chance, but maybe the original servo amplifier in the control box is dumb enough to not even care... hrmmmm.


----------



## macardoso

I should also mention that before I bought this unit, the DENSO tech warned me as to the age of the unit and the fact that few of this model were sold in the USA. Likely most went to asian markets. This seems to be the case as most spare and aftermarket parts are being sold in China, rather than the normal US places like Radwell.

I knew what I was getting into at least.


----------



## strantor

macardoso said:


> So my thought is this. The original control is more or less ready to run (especially since I own the teach pendant). I'm missing these components (items in *bold *are things I'll need regardless):
> 
> Controller Power Cable
> *Robot Motor Cable*
> Teach pendant Cable
> *Robot Batteries*
> Control Batteries


You're leaving a few things out aren't you? The important things you can't build yourself or get off ebay? Like... a unicorn floppy diskette, an obsolete unicorn panasonic motor that was custom order to begin with, motor data, a way to integrate anything but the Panasonic motor, any means connecting to the thing to make changes in the proprietary software, etc ( I thought there was more but lack the time/energy to go back and look).

It's your project and I'll stay tuned no matter which direction you go but I just feel like I'm watching someone buy and invest in tooling for one of those mill/lathe combo machines that I know they're going to outgrow in 6 months and wish they had just bought the lathe and the mill to begin with, rather than waste time and money on something else, just to end up buying the proper machines anyway in the end.


----------



## Cadillac STS

macardoso said:


> Yeah, that'd work, but finding an electrically identical motor would likely be nearly impossible unless it were from the exact same series that this one was made from.  I think I could substitute a non-DENSO motor made by Panasonic at the same timeframe, because I doubt Panasonic retooled their motor winding line to make special motors for DENSO. But I don't think I could take a 50W Allen Bradley motor and get the original control to run it.
> 
> Slim chance, but maybe the original servo amplifier in the control box is dumb enough to not even care... hrmmmm.



I would disagree with the idea that it would be difficult to find a replacement motor.  Find the voltage and rough size specs and there should be many choices.  Get one with the rear shaft to connect your sensors to and it should work.


----------



## macardoso

Cadillac STS said:


> I would disagree with the idea that it would be difficult to find a replacement motor.  Find the voltage and rough size specs and there should be many choices.  Get one with the rear shaft to connect your sensors to and it should work.


You might be right, but I do think it is a bit more complicated than that. Motor mechanical dimensions, power rating, and voltage matter greatly, but there are many other electrical and mechanical parameters which vary from motor to motor based on winding design that affect performance. These are:

Torque Constant
Rated Torque
Peak Torque
Inertia
Poles Per Revolution
Winding Resistance
Winding Inductance
Inductive Time Constant
Rated Speed
Maximum Speed
Continuous Current
Peak Current
Damping Coefficient
Voltage Constant
Overload Limit
Max Acceleration
All of these parameters are factoring into the Space Vector Pulse Width Modulation (SVPWM) algorithm that controls the motor. If they differ from the original motor by any significant amount then the control of the motor will suffer with symptoms of poor torque, excessive motor heating, or instability with the manufacturer programed servo gains.

If all else fails, I might have to try just what you are suggesting.

As an aside, this is the reason it is so difficult to mix and match servos between manufacturers. Usually these parameters are not publically available and often times servo drives only allow you to pick from a list of motors they tested the drive with and don't actually permit entry of custom values.


----------



## macardoso

strantor said:


> You're leaving a few things out aren't you? The important things you can't build yourself or get off ebay? Like... a unicorn floppy diskette, an obsolete unicorn panasonic motor that was custom order to begin with, motor data, a way to integrate anything but the Panasonic motor, any means connecting to the thing to make changes in the proprietary software, etc ( I thought there was more but lack the time/energy to go back and look).
> 
> It's your project and I'll stay tuned no matter which direction you go but I just feel like I'm watching someone buy and invest in tooling for one of those mill/lathe combo machines that I know they're going to outgrow in 6 months and wish they had just bought the lathe and the mill to begin with, rather than waste time and money on something else, just to end up buying the proper machines anyway in the end.


Oh I'm painfully aware of what I'm getting myself into. For me, this project is very much about just having fun learning and reverse engineering the old robot. I don't care quite so much about the long term use of the unit - although I do want it to work eventually. To buy a ready to run unit, even needing a LOT of work would have run in the $3-5k range and then I'd be just as limited by proprietary software.

I'll pull the gloves off and go for some more drastic approaches if I can't do the low hanging fruit.

I already have the PLC and servo drives which I am researching in parallel so we will see where this goes, even I don't know yet 

A lot will depend on how much info I can squeeze from DENSO and Panasonic.


----------



## strantor

Cadillac STS said:


> I would disagree with the idea that it would be difficult to find a replacement motor.  Find the voltage and rough size specs and there should be many choices.  Get one with the rear shaft to connect your sensors to and it should work.


If you're not aware, an AC servo motor is a totally different animal than an AC induction motor. If we were talking about a lathe spindle motor then sure, just go get one with the same voltage and rpm, good to go.

Here's an analogy: the motors (I think) you're probably thinking of (lathe/mill motors) are like a 5hp Briggs engine on a tiller. That engine goes out, you can put another Briggs or you can put a predator or just about any engine will work. These servo motors are more like the engine in a modern automobile, with control modules that speak Chevy, and a very specific model of Chevy. You can't just drop in a Ford engine or even a different model of Chevy engine and go. With a bunch of painstaking work involving programming, you could force it to work, but it is much better to just get the right engine. And the engine in this case is like a one out of an imported Lotus. They don't have piles of them laying around at the local scrap yard.


----------



## Cadillac STS

Would something like this be close enough, maybe swap out the magnet inside or a bigger part of the motor?









						Denso 410622-0631 Axis Robot Servo Motor MSM5AZQ6Q   | eBay
					

Find many great new & used options and get the best deals for Denso 410622-0631 Axis Robot Servo Motor MSM5AZQ6Q  at the best online prices at eBay! Free shipping for many products!



					www.ebay.com


----------



## matthewsx

Magnet building project?


----------



## strantor

Cadillac STS said:


> Would something like this be close enough, maybe swap out the magnet inside or a bigger part of the motor?
> 
> 
> 
> 
> 
> 
> 
> 
> 
> Denso 410622-0631 Axis Robot Servo Motor MSM5AZQ6Q   | eBay
> 
> 
> Find many great new & used options and get the best deals for Denso 410622-0631 Axis Robot Servo Motor MSM5AZQ6Q  at the best online prices at eBay! Free shipping for many products!
> 
> 
> 
> www.ebay.com


Yeah, actually. I think all the critical aspects of that motor you found are the same as what he needs. The 2nd half of the part number is different but that's probably to do with the encoder and any other custom options. I bet the rotor out of the eBay motor can replace the damaged rotor no problem.


----------



## Cadillac STS

One great way to find parts for something is to search for someone selling several robots of that kind or at least one.  Contact that person telling them what you need.  Contact eBay seller for example:  "I need this motor from this robot with this model number.  Do you have one or do you know who might?"    Some people may have it or know someone who does since they have the same robot.


----------



## macardoso

Cadillac STS said:


> Would something like this be close enough, maybe swap out the magnet inside or a bigger part of the motor?


Yes, actually I think that would work!



strantor said:


> Yeah, actually. I think all the critical aspects of that motor you found are the same as what he needs. The 2nd half of the part number is different but that's probably to do with the encoder and any other custom options. I bet the rotor out of the eBay motor can replace the damaged rotor no problem.


Yeah the 410622 is the DENSO part number. The first chunk is the series, maybe "Servo motor for old a** robot", and the second chunk is the individual PN, maybe "SCARA robot J3 Motor". I think the critical thing is the Panasonic number below "MSM5AZQ6Q". Bet if I matched that, or got real close, then I would get the motor I need.



Cadillac STS said:


> One great way to find parts for something is to search for someone selling several robots of that kind or at least one. Contact that person telling them what you need. Contact eBay seller for example: "I need this motor from this robot with this model number. Do you have one or do you know who might?" Some people may have it or know someone who does since they have the same robot.


That's a really good idea.


----------



## macardoso

Got pictures of the rest of the robot motor labels, edited the first post. 

The J4, J5, and J6 (broken) motors are all identical. This is nice because it cuts down on the number of unique motors I need to characterize. J1 is 200W, J2 is 400W w/ brake, J3 is 200W w/ brake, J4/J5/J6 are 50W.


----------



## macardoso

Here is a bit of info on the Controller Power connector. It was made by DDK (now Fujikura). The connector is a MIL-DTL-5015 part with arrangement 18-10.







I'll need a straight plug with female socket contacts.







I'll also need a cable clamp backshell



Rubber bushing may be needed to take up the thickness of the cable jacket.




EDIT: Here are some options to purchase:


			https://www.newark.com/amphenol-industrial/ms3106f18-10s/circular-conn-plug-18-10-cable/dp/34H5354
		




			https://www.newark.com/amphenol-industrial/ms3106a18-10s-res/circular-connector-plug-size-18/dp/96J8636
		




			https://www.mouser.com/ProductDetail/Amphenol-Industrial/MS3106A18-10S-RES?qs=YfwuOUGeHjy9Bb4fksa%252BQA%3D%3D&mgh=1&gclid=EAIaIQobChMI_Pa5icDk9QIVkh6tBh3c_gHPEAQYASABEgIHZPD_BwE
		




EDIT 2: Found the connector and backshell on eBay really cheap in unopened bags. Bought those. That should take care of the missing controller power cable. I'll need to do the same exercise for the robot motor cable with a 23 or 24 conductor cable.


----------



## strantor

macardoso said:


> EDIT 2: Found the connector and backshell on eBay really cheap in unopened bags. Bought those. That should take care of the missing controller power cable. I'll need to do the same exercise for the robot motor cable with a 23 or 24 conductor cable.


PM me if you need any more Cannon plugs. I have box full of randos. Might have what you need.


----------



## macardoso

strantor said:


> PM me if you need any more Cannon plugs. I have box full of randos. Might have what you need.


Will do - Thanks for the offer.


----------



## macardoso

One more thing. The control is rated for 210VAC +/-10% (189-231VAC) 1P 1.5kVA. I have 240V 1P residential power. To resolve this issue, I identified a transformer which I can get rather cheaply on eBay.




Doing a little hacky (but code legal) wiring, I could put 240V on the primary tapped at 277V. I could tap the 240V secondary. 240/277 = 0.866 and 0.866*240 = 208VAC. This is nicely within the 10% tolerance. Everything would be under the rated voltage and within the rated kVA.

Not even sure why it is that high. You'd never see all motors running at max, but even if they did, they'd pull 0.95kVA. Everything else is digital IO. I doubt the controller generates 550W of waste heat.


----------



## macardoso

Good news, I found that Goof Off cleans up the overspray from whatever this robot used to be dispensing. It doesn’t eat away at the plastic covers and while it does soften the enamel paint on the castings, as long as I don’t soak the enamel, I can wipe off the overspray very easily.  This thing is going to shine!


----------



## Cadillac STS

I noticed you are at Metro Detroit.  I grew up there by the GM tech center, 12 mile and Hoover.  Now I’m in West Michigan.

I checked and there may be support to download manuals for programming that and an active company to ask questions






						Discontinued Products｜support｜industrial robots｜DENSO WAVE
					

This page for DENSO WAVE’s discontinued robots and related products. WAVE serves as a leader in developing and manufacturing automatic data capture devices for QR codes and IC cards and industrial robots (FA equipment), etc.



					www.denso-wave.com


----------



## macardoso

Cadillac STS said:


> I noticed you are at Metro Detroit.  I grew up there by the GM tech center, 12 mile and Hoover.  Now I’m in West Michigan.
> 
> I checked and there may be support to download manuals for programming that and an active company to ask questions
> 
> 
> 
> 
> 
> 
> Discontinued Products｜support｜industrial robots｜DENSO WAVE
> 
> 
> This page for DENSO WAVE’s discontinued robots and related products. WAVE serves as a leader in developing and manufacturing automatic data capture devices for QR codes and IC cards and industrial robots (FA equipment), etc.
> 
> 
> 
> www.denso-wave.com



Just moved here. Still don't know where anything is, but we are close to the wife's family which is nice. Went to UofM for school so I do feel slightly like a Michigander.

That page shows a PDF to download, but it always fails with a 404 error. I have that question on my list to ask them so hopefully they will give me the last manual. We shall see!


----------



## macardoso

Did a bit of researching last night on the encoders for these motors and I see an issue brewing if I ever want to run these on my Allen Bradley servo drives.

The Allen Bradley Kinetix 2000 is a modular drive platform that supports Tamagawa 17-bit serial (sort of). Specifically it supports Tamagawa TL5669 series encoders with 17-bit single turn data (131072 counts/rev) + 16-bit absolute multiturn data (4096 revolutions rotary or +/- 2047 revolutions linear). In addition, the motor must be properly programmed with a "blob" file or a chunk of data that is saved on the encoder and allows the drive to self-identify the motor against an entry in the database. Unprogrammed motors or motors with data not in the database are not allowed. I do have experience manipulating a custom motor file (CMF) to add a valid entry to the database, but never got it to work quite right; for unrelated reasons I believe. I do not have, nor have ever seen, a breakdown of all the values in the blob data. This would be a major challenge to decode and manipulate. Again, the SERCOS environment (the family of drives containing the Kinetix 2000) was never designed to be open to 3rd party devices at all. I also have no clue how one would even program these encoders. This might be done at the factory and not be possible by a user.






My motors have Tamagawa TS5643N151 encoders. I can't find exact data on these yet, but it looks like they might be 11-bit per turn (2048 counts/rev) + 13-bit absolute multiturn data. These motors will either have an unprogrammed "blob" file, or they will have one programmed to talk with the RC3-V6A robot controller.




The Panasonic series of motors I have, when the default "S" encoder is selected, advertised 17-bit encoders (no mention of absolute multiturn range). I had hoped these might be 1:1 compatible with my servo drives, but I know now that it won't be that easy. The DENSO part number has a "Q" (custom selection) in the encoder spot of the part number which makes me think they selected a non-standard encoder option.

One solution I am brewing up in my head is to insert a microprocessor between the encoder and the drive. This could read the 11-bit data packet and reformat the whole thing to look like a data packet that a 17-bit encoder would have put out. It could probably even insert blob data without needing to program the encoder. This microprocessor would then send that new packet to the drive. I theorize that if I am careful with the packet structure and quick enough in manipulating the data, the drive would never know there was a mismatched encoder on the other end. This is the same idea as my feedback interface boards for my last robot (pic below), but a completely different implementation.




Of course this is all a moot point if Panasonic doesn't wish to share their motor parameters with me. I emailed them yesterday and have my fingers crossed. Replacing the motors isn't really realistic as I would be spending several hundred dollars per axis (times 6!).


EDIT: One additional thought... The closest match to the TS5643N151 encoder on Tamagawa's website advertises 11bit/turn and 13bit/Multi-Turns, Incremental 2,048C/T. The number of encoder wires exiting the motors on the robot was quite a few more than the 7 wire interface advertised for the serial only interface. I think that this is because the encoders not only put out serial data but also incremental AQB tracks. If this is the case, then there also could be a unique opportunity to run these motors are generic TTL incremental encoders. I could do the Wake N' Shake self sensing commutation, or add a board between the motor and drive which uses the serial data to initialize the hall effect commutation signals to the right angle for AQB + Halls feedback. I might even be able to message the absolute position data to the PLC somehow outside of the drive interface and run the motor incrementally after the initial absolute position startup sequence. I think I'd like to try to stick to pure serial, but this gives me options which is good.

Thinking more, I'd guess this is how the RC3-V6A controller talks to these motors. One serial message to pull the absolute position data, and then only AQB incremental after that.


----------



## macardoso

I've also come up with what I consider to be a minimum viable system for the original robot RC3-V6A controller. *Bold *indicates I own or have a path forward on the item already.





*Robot* - have it
*Motor Cable* - I can build myself
*Encoder Cable* - bought one on eBay really cheap
*Power Cable* - bought the parts to make one
*Step Down Transformer*, 240/208, available for around $100 on eBay
*Teach Pendant* - have it
*Robot Controller* - have it
Teach Pendant Cable - missing and not available online. Will need to build.
Initialization Floppy Disk - missing. Will ask DENSO to sell disk or provide parameters for entry by Teach Pendant
Programming Manual - Hoping DENSO can provide. I would expect they would. Some programming info is in the manual I have
*Encoder/Controller batteries* - Generic 3.6V batteries available online. I can replace the batteries with new ones.
*CALSET Data* - I believe I have this from a sticker on the robot.
*J6 Mastering Fixture* - missing. Might be able to machine my own, or make a new design and generate my own J6 CALSET data. Not important.
Assuming the controller is not busted for some unknown reason, I need to buy a couple things, make a few cables, get a manual from DENSO, and get the critical parameters for the controller from DENSO. Really seems somewhat doable - I hope.


----------



## macardoso

Little update. I found and purchased a replacement motor for that damaged one. It should be a 1:1 replacement but we will have to see. There were *extremely* few options (this was the only US based seller) and the going price seemed to be around $600-800 for a used motor. I got mine on best offer for a bit over $100. That hurt, especially since I just bought the robot, but I know it was a good price. It is in the mail now, and I'll make a post about installing the new motor when it arrives.




Alright. After digging through the bowels of the internet, I've managed to scrounge up some specification documents on the encoders inside my motors. One of my goals is to control this robot with some Kinetix 2000 AC Servo drives. In order to do this, I will definitely need to do some hackery with the encoder interface to maybe get the drives to accept the motors.

These encoders are a bit strange if you've only worked with standard optical or magnetic encoders before. These encoders are still optical transmissive, but they have 11 tracks on them producing 2048 unique readings per revolution (encoder reads binary, so 2^11 = 2048). This is called the single turn data and it can be read at any time without the need for homing or even battery backup. This encoder also has a special circuit that counts the number of full revolutions completed any time it is powered up or on battery backup. This is the multiturn data and mine can track 13 bits or 8192 revolutions (+/-4096). This data can only be maintained while the encoder is powered, hence the need for the battery backup. The encoder enters a low power sleep state when operating on battery only and will still track motor motion but only up to 6000rpm.

Check out the code wheel!




Rather than streaming the data in real time, the encoder saves the data to memory and responds to serial message queries. The options are to read the position data, write to EEPROM, read from EEPROM, and read extended statuses. The information for exactly how this interface works varies in detail from manual to manual, but with all the different sources of info I have found, I think I understand roughly what is going on. Check out the serial specification for the position data.



Alright, so where am I going with this. Well the bad news is that this data is NOT what my servo drive is looking for. Unfortunately the Kinetix 2000 servo drive is only designed to talk with a TS5669N124 encoder inside an Allen Bradley TLY motor. This encoder is a 17 bit serial encoder with 16 bits of multiturn data. The serial data format is a bit different to accommodate the extra data length. So if I want to be able to get my motors running on these drives, I need to manipulate the serial data from my motors on the fly to reformat it into the data expected by my servo drives.

Fortunately because this is serial, I don't expect it to be impossible. A microprocessor with proper transceivers should be able to collect and relay the serial message from the encoder to the drive, manipulating the data as needed. The question will be if there is sufficient time to do so between sequential reads. I do not know the frequency of data requests from the drive, but I wouldn't expect it to be any faster than say 250us. A full frame transmission, per the spec above is 84us, although adding more data for the 17-bit format might stretch that out. That gives roughly 80us to read the serial buffer, perform the necessary operations, and begin transmitting the outgoing packet to the drive. The drive might also have timeouts which limit the response time of the encoder further. A demanding application but not feeling impossible.

The TS5669N124 encoder specification (the encoder designed to work with the servo drives I have) has a lot of detail on the EEPROM memory which can be used to store motor data. The specification for the TS5643N151 encoder (I actually only have the spec for a TS5643N100) does not have detail on these functions. This might mean that my encoder does NOT have EEPROM memory. If this is the case, then my application gets more demanding as my serial interface must then interpret the incoming request from the drive and identify if EEPROM data is requested. If so, I could inject a fake EEPROM response directly from the microprocessor without needing to send the request to the encoder itself.

Still waiting to see if Panasonic will share the motor characteristics with me. Both this information and the encoder interface must work to run these motors. I could substitute an incremental only option, thanks to the extra incremental tracks on my encoder, but that brings with it issues of commutation and homing (remember my robot does not have home switches).

Motor commutation is a remaining mystery. I do not see anything related to the encoder which indicates how commutation is accomplished. I'm guessing that Allen Bradley motors have their single turn data zeroed right at the commutation transition between two specific phases and that data is maintained for the life of the encoder. If this was done at the factory, then all motors would have a 0 degree commutation offset. Only the non-battery backed singe turn data would be needed to get the commutation angle. The TS5669N124 motor has documented commands for zeroing the single turn data, my TS5643N151 does not seem to have this function.

EDIT: Another data point that suggests that these encoders might have different functions and capabilities is the control chip part number difference. The Panasonic motor encoder TS5643N151 uses the Tamagawa ASIC AU5660. The Allen Bradley motor encoder TS5669N124 uses the Tamagawa ASIC AUA5262.


----------



## macardoso

Been working away at cleaning the robot for a few days now and just ran out of Goof Off (the only thing that takes off the overspray). I decided to open up the mechanics a bit, as knowing the gear ratios within the arm is very important to getting this running on a Rockwell PLC down the road.

I started on the J6 tool platter since this axis was already partially disassembled due to the bum motor. I took 8 long bolts out of the flange at the end of the robot, but left 4 short bolts held the two halves of the harmonic drive assembly together. This entire assemble then slid out of the end of the arm (after getting past a pretty tight O-ring gasket).







This revealed a Harmonic Drive brand SF14-50-921826-4 harmonic drive gearbox. Here is the closest match to an active product today: https://www.harmonicdrive.net/products/gear-units/gear-units/csf-2uh

The grease is sitting inside the Flexspline with the ring gear around the outside (the part the bolts go into). The "50" in the part number indicates this gearbox has a 50:1 reduction ratio.




Here is the wave generator. A super thin race bearing pressed onto an elliptical hub. As a motor turns the elliptical hub, the outer race of the bearing flexes with a wave traversing it. This drives the flex spline into two lobes of engagement with the ring gear. Wikipedia has a good article on it: https://en.wikipedia.org/wiki/Strain_wave_gearing




Removing bolts from the bevel gear driving shaft allows the J6 bevel gear module to slide out the side. There was a satisfying pop of a tight tolerance bore and an airtight cavity behind it.




Looking inside this bore, you can see a depression in the grease that matches the bevel gear I just removed, as well as the mating bevel gear, visible coming in from the left of the bore. These gears each have 20 teeth and only serve to change the direction of the rotary motion to line up with the J6 harmonic drive.




This J6 driven pulley that goes into the bevel gearbox rotates with the nod of the wrist (J5 motion). This means that if the J5 motor is rotated and J6 motor is not, both joint 5 and joint 6 will rotate. This is known as differential coupling and makes the job of the software guy (me...) a bit trickier since J6 motor must track the geared down motion of J5 any time motion on J6 is not desired. Fortunately, this is the only example of this coupling on my robot. Some types of 6 axis robots place all the wrist motors (3-4) on the elbow and drive the mechanics with shafts, gears, and belts. This is done to get as much weight away from the end of the arm as possible, but greatly complicated the control issues with coupled kinematics. 


Anyways, this post got long, I'll do another one for J5 and J4. I will also update the first post with the new information about the mechanical elements.


----------



## macardoso

Alright, so J5 and J4 look quite similar to J6.

The J5 harmonic drive is driven by a wave generator mounted on a bearing block at the end of the arm. The motor (bottom left) is belted to this with a 1:1 ratio timing belt. Removing 9 bolts let me pull out the wave generator.




This exposed the flex spline cup attached to the swiveling wrist. The Harmonic Drive part number was lasered on the ring gear: HS14-80-921773-5. This is an 80:1 reduction. Notice the smaller teeth around the perimeter of the flex spline and ring gear compared to the J6 pictures. I got some of the extra grease worked into the bearings and teeth, then bolted it back together.




The J4 harmonic drive is located at the very rear of the elbow. It drives a shaft which in turn rotates a large crossed roller bearing slew ring about midway down the upper section of the arm.




Again, removing the wave generator bearing block revealed the ring gear with the lasered part number: HS14-80-921773-14. This is also an 80:1 reduction. Everything was greased and reassembled.




Here are 2 shots of the wave generator. It is hard to see, but the thin bearing race (somewhat copper colored) is elliptical. Looks very strange since you think of bearing races as being amazingly circular. That outer bearing race is pressed lightly into the flex spline. The entire inside section rotates at the motor speed, while the bearing race and flexspline rotate at the 1/80th reduced speed. Since there are no rolling elements, there is no need for backlash in the mechanism and it can attain near zero backlash measurements.







Popping open the robot base showed a mess of wire colors. The good news is this gave me a lot of clues as to what all the colors mean. Would still really like a pinout for the connectors.

The encoder backup battery is normally velcroed to the top of that metal case. I have it removed to see if I can get a replacement or build my own.


----------



## macardoso

Got the robot encoder cable in the mail today. $35 shipped and brand new. I couldn't make it myself for that price.




I figured out what the connector on the teach pendant is (I hope!). It is a very obsolete Hirose Electric 10 pin connector. Could only find it for sale in the UK, so I bought one - will likely take a bit to get here. Hirose RM15TP-10S. My understanding is this is a RM product family, shell size 15, threaded plug, 10 pin, female sockets, solder cups. 




Here is the receptacle on the teach pendant.




I opened up the teach pendant to see what was inside:




Found it interesting that the keypad is a flexible plastic sheet over real buttons, rather than a membrane keypad. Feels funny to use compared to stuff today, but I bet it is bullet proof.




Under the keypad is the main board. It consists of a Hitachi H8/325 "Microcomputer", a serial line driver, and some resistor networks used to read the buttons. A deadman switch on the side is required to jog the robot.




I still have had no luck finding an original teach pendant cable or motor power cable. I'll likely be building my own. The motor power cable will need to be 18AWG with at least 23 conductors, but 25 is much more common. A shielded cable would be preferable. IGUS makes some nice high conductor count control cables perfect for this application. The one I think is best runs about $5.50 per foot, or $100 to match the length of the encoder cable (6m). Ouch! CF881-07-25 is the part number. Add in the cost of the connectors at each end too. I'll need this regardless of if I use the original control or my own drives.


----------



## macardoso

Great news! The replacement motor arrived today. The Denso part number is different due to it having a different drive attachment for a different robot.




The motor shaft was an exact match, which I could not confirm before buying.




Got the original hardware installed. The encoder connectors are a different color plastic, but have the same encoder wire colors, same pinout, and same series connector. I think it is an exact match. Kinda don't want to open it up to check the encoder since it is currently water resistant.




The motor fit back in just where it was supposed to. Belt was tensioned to "finger tight".




Back of the motors is visible from the J5 motor/gearbox side. A longer motor with a brake (my only other option) would not have fit.




And the arm with all the belt and wrist covers back on! Mostly done cleaning this part, still need to do a lot of cleaning on the lower sections.


----------



## macardoso

I have been accumulating questions for DENSO, Panasonic, and Tamagawa. I finally decided to polish up some emails and send them out. Have heard nothing back from Panasonic or Tamagawa, however there is one US based support engineer for DENSO that has been answering my emails. I sent him a book and he said he was willing to help get the info I needed, although it will take several weeks. This guy is awesome!

Anyways he started by sending me an extra manual which I didn't have before. Apparently this robot was made on December 6, 1999. They were probably pushing all the robots out the door that they could before the Millennium Bug took them down  

This was manufactured with software version 9.57. This came with a number of added functions and benefits over the base model. This new document (attached in 3 parts) highlights the features of this higher version of software.

I haven't read the whole document yet, but I did pick out one interesting tidbit.

A new "inching" function was added which moves the robot, what I am assuming, is one encoder count at a time. This is neat info because I think I can calculate the gearbox ratios from it.




Using joint 5 as a known example, the control receives 2048 pulses per rev (depending if this is counts or pulses, we might be off by a factor of 4). Divide the circle by this amount and that's 0.175781 degrees per pulse. We know this goes through an 80:1 gearbox, so we divide this number by 80. This is 0.002197 degrees per encoder pulse at the wrist (after the gearbox). OK let's bring in that factor of 4 again, and we get 0.000549 degrees per count (x4 quadrature interpolation). That's the published number!!

OK so lets look at this again. Since all the motors have the same encoder (likely), then *J2 and J3 have 80:1 gearboxes*.

Lets calculate J1. So (((360/2048)/x)/4)=0.00044. Then "x" (the gear ratio) is 99.88:1. Accounting for rounding and truncation, we know this means the *J1 gear ratio is 100:1*! We can double check by just comparing ratios. (0.00055/0.00044)*80 = 100

This was cool!


----------



## macardoso

Quick update. Had a pretty productive weekend on this project.

While messing around with this unit, I noticed there was a small yet noticeable click or a small bit of movement from the J2 shoulder joint when I pushed on it. This joint should be really stiff and the gearbox should have no backlash, so I decided to investigate.

The motor was easily removed with (4) allen head cap screws. That distinctive butter yellow grease is everywhere. Although I immediately noticed this gearbox has a significant amount of brown/copper colored staining around the wave generator and the flex spline teeth.





The part number on the gearbox is 25-100-9921494-17. This indicates a 100:1 gear reduction. Strangely this does not match what I estimated from my previous post. I trust the gearbox part number more than manufacturer documentation.




The wave generator was held onto the motor shaft by a locking screw and cap on the end of the shaft. Once removed, the wave generator was a snug slip fit on the shaft. This motor has an electromagnetic holding brake so I cannot rotate the shaft by hand.




Once I removed the mounting ring, I could see nearly 3/4" of dried up grease and lots of dark coppery material. Yuck




And double yuck. There is the wave generator. The bearing was incredibly gritty and full of mud brown junk. This was heartbreaking since replacement gearboxes (even from eBay) cost more than I paid for the whole robot.




I started cleaning with lots of paper towels and WD-40. Hours later, I got the wave generator all cleaned up. Amazingly, this seems to be OK. The bearing is very smooth, and a visual inspection of the raceways under magnification doesn't show obvious signs of spalling, galling, or bad wear. The balls are a little less than mirror finish, but that's to be expected from a 23 year old machine.




I also removed all the excess grease from the flexspline cup and anywhere else I could reach. I would have liked to remove the entire flexspline cup to clean the teeth and the teeth on the ring gear, however, after removing all 8 bolts, it was still stuck in the cavity incredibly tightly (it had 6 slip fit pins, a tight locating boss, and the mesh of the gear teeth). I gave up and spent an hour straight flushing the teeth with spindle bearing oil. The oil eventually was running pretty clean, slightly brown but no grit, so I called it good.




I wanted to buy the original grease MULTEMP AC-N (Lithium grease with diester oil and moly), but this is a high end grease from Japan and I couldn't easily find it for sale. One reference showed a price of $950 per 5kg hand packing pail, so probably not worth it. I found a generic lithium soap grease with moly and graphite additives which I hope is chemically compatible with the remnants of the existing grease. That's on order right now. The greasing passages on this are impressive and should permit greasing of all wear components in the gearbox, plus flushing of old grease, in a single shot port.

Edit, After reinstalling, the click is gone and while there may be a slightest smidge of movement in the joint, it is likely from the small amount of play in the motor brake. This is perfectly acceptable for use and will not cause any issues.

I should probably open up and clean all the other gearboxes too...


----------



## macardoso

Quick side post on the harmonic drive

Here is wave generator of the gearbox. The steel core is ground in the shape of an ellipse and has a thin walled high compliment ball bearing pressed over it, deforming into an ellipse itself. How would you manufacture this to ultra precision tolerances? This same gearbox was used on the Apollo lunar rover.




The back side has a pair of precision slots milled and ground into it.




These match to a steel disk with some sort of dry lubricant PVD coating on it. There are precision ground pads and dogs on this component.




The aluminum hub fits the dogs on the other side of that steel disk. Note that the dogs are 90 degrees rotated to the ones on the other side in the previous picture. This is the coolest and most unexpected feature of the unit. It is an integral oldham style shaft coupler to account for radial misalignment between the motor and gearbox. The aluminum part floats inside the wave generator and has a small amount of radial travel. Thanks to the tight fitting slots in the coupling, there is no rotational play.




On the front, a shim pack and bronze washer preload the oldham coupling mechanism and are held in place by a retaining clip. All super compact. A really innovative design.


----------



## macardoso

Got a big can of Goof-Off and was able to remove the rest of the paint and overspray to get this thing cleaned up. Looks really nice now in my opinion. I even got the spray gun cleaned up. This looks to be an airless sprayer using high pressure product feed and pneumatics to control the ON/OFF of the sprayer. Not sure what I could use it for, but I'm not throwing it out.




Ordered 20' of motor cable (25 conductors, 18AWG, shielded) and got (hopefully correct) mating MIL-SPEC connectors for each end. These were available for ~$180 each, new from Digikey, but I got them on eBay for $8 and $10 respectively. Whoo! They are solder cup variety.







The teach pendant connector should arrive today, cross your fingers I ordered the right one. I also put in best offers on the Valve, Input, Output 1, and Output 2 cables on eBay. These are for connecting the controller to external devices. I don't *need* them so I offered a low amount which I'd be happy to buy them for. Would be nice to have a full set of cables, but not worth investing a ton of money into.




As a bonus, I cleaned the whole shop too. Really makes it nice for the next time I want to go mess around with something.


----------



## macardoso

Teach Pendant connector arrived today from RS Components in the UK and it was a perfect fit. That was super lucky. 







Trying to identify this connector. It is for an ESTOP button and currently has a shorting plug installed. 




Finally, I got my best offer accepted after a bit of negotiation with the seller on those 4 cables. All in all, I've spent a fair bit more than the cost of the robot replacing the broken motor and getting the missing cables and such. The low price on the robot isn't quite so great after all that but still a killer deal compared to what I would have had to pay for a complete system if one were even available. I think I'm done getting stuff for now. Should have all the necessary components to get this running unless the entire controller is no-good.


----------



## macardoso

Denso support sent me "Owner's Manual B - Programming"! It is 480 page monster. If I get the original control box working (currently my plan) this will be invaluable. Even for such an old robot, there are some pretty advanced control features that this incorporates. I'd have difficulty adding all of this into a custom programmed PLC control.

Had to upload in 9 parts to get around the 4MB attachment limit


----------



## macardoso

Even better, he sent me the service manual! This has some of the most important info I've been looking for. Especially cable pinouts!

Still haven't found out the teach pendant wiring, but there was one clue in the manual after a quick scroll through.


----------



## macardoso

I was also given a screenshot of an RC5 controller wiring document. Apparently DENSO repair shops use the same single phase cable for all RC3/5/7 controllers.


----------



## rabler

Keep the updates coming, I'm fascinated!


----------



## macardoso

Searched ebay for "antique 4 pin connector" since I was giving up hope and look what pops up 8 listings down. That is the right plug for the ESTOP circuit!


----------



## macardoso

The manuals I got from Denso did not contain any information about the wiring of the teach pendant connector. I sent a message to every seller of one of these teach pendants on eBay in a hail mary that they might be willing to help me pin out the cable.

Someone was nice enough to do this for me! 




I'll have to do some double checking before I plug this in and power it on, but it checks out against the information in the posted earlier.




Some people are just awesome!


----------



## Cadillac STS

macardoso said:


> Searched ebay for "antique 4 pin connector" since I was giving up hope and look what pops up 8 listings down. That is the right plug for the ESTOP circuit!
> 
> View attachment 396524


Having an Estop button in hand during the programming will be essential to stop it from making an unintended move


----------



## macardoso

Cadillac STS said:


> Having an Estop button in hand during the programming will be essential to stop it from making an unintended move


Oh for sure! There is one on the teach pendant, but this one allows for a remotely mounted ESTOP button.


----------



## Cadillac STS

Check it out.  I searched Denso Robot Forum and there is one!  Likely the place you will get lots of help






						Denso Robot Forum - Robotforum - Support and discussion community for industrial robots and cobots
					

Help regarding Denso robots




					www.robot-forum.com


----------



## macardoso

Cadillac STS said:


> Check it out.  I searched Denso Robot Forum and there is one!  Likely the place you will get lots of help
> 
> 
> 
> 
> 
> 
> Denso Robot Forum - Robotforum - Support and discussion community for industrial robots and cobots
> 
> 
> Help regarding Denso robots
> 
> 
> 
> 
> www.robot-forum.com


Hey! That was a great idea! I had posted on there before for my other robot and not gained much traction, but hey, let's see what I can figure out!

Thanks!


----------



## macardoso

I'm going through each gearbox and cleaning out the old grease, washing the critical components, and filling with fresh grease. I got some nice low viscosity lithium grease that I'd like to use. Would have preferred the original grease, but I could not easily find it and the cost if I could would have been unreasonable. I am not a tribology expert by any means, but I figure one lithium grease with molybdenum additives is pretty close to another lithium grease with molybdenum additives. Good enough for hobby use. 

The old grease is cracked in places where it pooled up, indicating the base oil has run out and mostly the thickener remains. Dark brown staining on sliding and rolling members indicates lubrication starvation and wear.


----------



## macardoso

Alright, I'm somewhat on hold while I'm waiting for parts to come in the mail and waiting on information from Denso.

I thought with the latest pinouts from the robot service manual, it might be interesting to check out one of the serial encoders. Fortunately I still have the original J6 motor with the broken magnets, so I can use that encoder to mess around with and not risk damaging the motors I need.

If I choose to build my own control with a Rockwell PLC, I'll need to hack a system to get these non-compatible encoders to talk to my servo drives.

Since the last robot, I finally bought an oscilloscope for myself. It is a Siglent 4 channel 200MHz scope. In this setup, I have an arduino which I'm only using for the 5V power right now, but I might try hooking it up to read the serial data. The red/blue wires are power going to the encoder, and the green wires are 2 channels of differential serial. This is a single ended serial where the encoder only transmits and there is no receiving provision for the controller to talk to the encoder. Data seems to be streamed continuously after the encoder is powered on.










Here is a zoomed in view of the 2 channels showing one full pair of transmissions (specification below). These signals are encoded in manchester code where the data is the direction of the edge (rising/falling) rather than the voltage (high/low). The blue channel is a mirror copy of the yellow channel for noise immunity.




And the specification. I need to decode the data I see on the screen. I don't think my scope can decode or trigger on manchester encoding, so I'll be doing this by hand most likely. 




Just a quick update - will follow up with more info later once I get into decoding this.


----------



## macardoso

This was actually super easy to decode. The stop bit on the second frame got a bit wonky, but that might be my error. I think all the data lined up correctly.

Anyways, here is the above image decoded. The single turn data is 992 counts out of 2048 or 174.375 degrees from where I powered on. Additionally the multiturn count is 4 which is reasonable since I spun it a few times.

It is also reporting a battery error, overspeed error (perhaps related to battery error, or this is how the motor blew up), battery alarm, and preload status. 








I'd like to understand the CRC field. It is 3 bits, but the manual does not describe how to calculate it.


----------



## DavidR8

I'm in complete awe of anyone who does this kind of work. 
<mindblown/>


----------



## rabler

Quick check shows some Arduino libraries for manchester encodings…

Having a scope is really worthwhile for something like this.


----------



## rabler

Been a while, but you'll need to figure out what polynomial they used for CRC.  Looks like about 40 bits of data.    There are a few places places that publish common polynomials for the size of bit field, as only a limited number of polynomials give good error checking.


----------



## macardoso

Alright, made some progress last night.

Ran a more thorough test last night of the encoder. Powered it on with the shaft in a known position and saved the serial data. The I rotated the shaft 2 rotations CCW when viewing the shaft face and tried my best to get it lined up.

Here is the serial packets immediately after power on.






After decoding them, I can see I am at 1184 counts (of 2048) for the single turn data, and 5 revolutions on the multiturn data. OK, well does that make sense? The single turn data is absolute and does not require the battery to back it up. The zero count location should be aligned with the zero electrical degree position for commutation (or a known offset like 90*). So yes, a non-zero single turn value is expected at power on. What about that multiturn data? That should be battery backed and get reset after a power loss.

Well it turns out that the encoder has a supercapacitor that keeps the encoder powered for up to an hour after power loss to facilitate replacing the backup batteries. The capacitor is expected to age down to 15 minutes after 10 years (it's been 22.5  ). So the multiturn counter didn't reset while I was preparing for this test.







Also, take a quick note that the PS flag (Pre-Load Status) is set to 1 right now.

OK. So with the encoder powered, I manually rotated the shaft 2 revolutions CCW. Then I captured the serial data again and decoded it.







As expected, the single turn data is 1141 counts of 2048. This is very close to the starting single turn position of 1184. The multiturn counter has decremented to 4. I expected 3 so not sure about that... Maybe I did move it only 1 rev? Not positive.

Notice now that the PS bit is 0. This bit is indicating the the accuracy of the data is limited until the shaft has been disturbed by 2 degrees mechanical. Since I moved the shaft 2 full revolutions, this cleared the PS bit.

I'm not sure what "renews 5 bit absolute data to 11 bit absolute data" means. Not sure if this is the single turn or multiturn data. I'm assuming singe turn. If this is the case, there is a 2^6  (2^(11-5)) count (64 count) uncertainty in the single turn position right at start-up until the shaft has been disturbed. This could account for the difference in single turn counts between the two readings (1184 vs 1141) or that could have just been my inaccuracy in lining up the shaft exactly on the same mark.




I also figured out the CRC based on @rabler previous post. This is a polynomial CRC. Specifically it is a 3 bit X^3 + x +1 (also known as a 1011 polynomial CRC). You can do the math by hand or use an online calculator to generate a CRC from the data. This online calculator even includes a provision to check the CRC after a simulated transmission. The CRC includes the ADDRESS, DATA, and FRAME fields, but not the START, STOP, or CRC fields (obviously, since this is what we are calculating).

This CRC is a highly efficient method of checking the data for random bit flips with an extremely low probability of one getting past. CRC codes are able to detect double bit flips. More robust methods like hamming codes provide more certainty in the error checking, and even on the fly error correction at the receiving end, but use more data for the error correction. This was obviously not desirable to the encoder designed as they wanted to broadcast the data as fast as possible and this meant small data packets. A CRC also provides more resiliency than a simpler checksum, which can only protect against a single bit flip.

If this were to be done with Hamming Codes, the 36 bits of data would have needed to be broken into groups of 26 bits (Hamming(31,26)) and would have needed 70 bits to transmit the same data that this CRC scheme transmits in 50 bits. We can see that this CRC scheme is nearly 30% more efficient than Hamming codes.

I had one additional thing to look into. A new set of single and multiturn positions come over serial every 84us. This encoder also outputs quadrature encoder signals at an increased resolution of 2^13 bits (8192 counts per revolution). So if we choose to use both the serial data AND the raw encoder data, we can increase our usable resolution of the encoder, while remaining aware of the absolute position, and even cross checking the position data from two sources. Assuming the motor max speed of 5000rpm, each quadrature count arrives every 1.47us. This is much faster than the serial rate, giving us better tracking of the motor position. While a serial only solution would likely work, I think the final implementation of the encoder interface board should use this additional data.

I also took a moment to hook up an AM25C32I RS422 Differential Line Receiver. I actually had exactly one left over from making the encoder interface boards from the last robot and also managed to find a small SOIC16 to DIP breakout board. Soldered it up real quick and it worked perfectly!







The yellow and pink traces are the differential RS422 inputs, and the blue trace is the 0-5V single ended signal coming out of the AM26C32I differential line receiver. This signal should be perfect for wiring into an arduino. Notice how much cleaner this signal looks too! I think I can use my UNO with software serial and a FTDI to read text to a serial monitor, or I can buy a Arduino Mega with 2 hardware serial ports. I don't think software serial supports manchester decoding, but the hardware serial seems to with a library.


----------



## macardoso

Connectors have been arriving. The big ones are the robot motor power cable connectors. The black one in the middle is the correct power plug (the blue one is the same but with a wrong backshell). And the small silver one was an incredibly hard to find connector used for the robot ESTOP.




I found this by searching "Vintage 4 pin connector" on eBay. It is a perfect fit - crazy lucky find. Was advertised for use with old CB radio microphones. I still have no idea what this connector actually is. 




Cables have been arriving too!




These 4 cables are new - old stock DENSO branded cables matched for this controller. Can't believe I found them. Weren't cheap, but probably worth it.







And this is the motor power cable. 25 - 18AWG conductors, plus ground, overall shield, high flex. Again, not cheap, but the only option I found for shielded high conductor count cable.







I need to buy a transformer to step my 240V down to 208V but I'm going to hold off on that until I know I can use this control box. It isn't too expensive, but I don't want to keep sink money into this controller if I don't know it will work.


----------



## macardoso

Well the whole Arduino thing was a bust. I set up a basic program with manchester decoding and tried to get the serial port talking at all the standard baud rates. The max baud rate supported by the manchester library was 57600 baud. I never caught a single serial packet.

Working on an oscilloscope makes it pretty easy to get zoomed in and forget how fast these signals are coming in. In this case, the serial data is 2Mbps or 1M baud. There is no way a microprocessor with a 16MHz clock can keep track of a 2MHz signal, let alone do anything with it, write to memory, read other serial channels, etc. 

I have a STM32 Nucleo development board that clocks in at 200MHz. Definitely a higher performance chip. I might mess around with this and see if I can decode the signals, but I'm shopping for a new microprocessor that can do the job. I've boiled the tasks it need to perform down to the following:

Read quadrature encoder @ 680kHz, update position in memory. Interrupt based?
Read serial channel (2Mbps, 1M baud, manchester encoding), verify CRC, parse data, save to memory. 24kHz packet refresh rate.
Compare quadrature encoder position and serial data, cross check for errors.
Read serial channel (2.5Mbps, NRZ encoding), verify CRC, parse data. Unknown packet rate. Assume 24kHz.
Write serial channel (2.5 Mbps, NRZ encoding) using data from memory. Perform basic math on data (bit shift, fill zeros, etc.), calculate CRC, generate packet format with proper start and stop sequences. Refresh rate matches request frequency of the previous read operation.
I think this is in the realm of a high end micro, or perhaps an FPGA...

I have someone at work who can loan me a motor with the encoder I am trying to emulate. That way I can scope all the communications with the drive and fully document what I need to develop. I'm going to hold off on that for a little while.

-Mike


----------



## macardoso

Researched this a bit more and a top contender is a Teensy 4.0 (https://www.pjrc.com/store/teensy40.html) running a Cortex-M7 at 600MHz. Unbelievably, this thing only costs $20. One per axis + peripherals isn't cheap, but it is attainable. If performance is excessive, I could conceivably run up to 3 axes through this, although I don't think that would be worth the headache. 




I understand this can handle return-to-zero (RZ or "normal") serial up to 5Mbaud which meets my needs for both serial protocols. It has 7 hardware serial ports (not counting the USB interface) and is programmed through the Arduino IDE. All looking good. Signals must be 3.3V which means I'll be level shifting. Perhaps there are RS-422 transceivers which accept 3.3V logic...

Actually coding this will not be trivial, but it seems like this has the hardware needed to do it.


----------



## macardoso

One more option. If an FPGA is better suited to this task (not sure yet) then Seeed Studios make the Tang Nano board (https://www.seeedstudio.com/Sipeed-Tang-Nano-FPGA-board-powered-by-GW1N-1-FPGA-p-4304.html). This one is $6




Or the Tang Primer FPGA / RISC-V. This one is more powerful and is $20




My understanding is FPGA is great at sequential logic (would have been perfect for my other robot's feedback interface boards), but not sure how it handles serial.


----------



## macardoso

*Mechanical/Controls Update: *I am slowly working through opening up each joint and cleaning the gearboxes. J2 is done and I have J3 open right now. It is in better shape, but also looking somewhat starved of lubrication and some brown staining on the harmonic drive. It is less gritty than the J2 gearbox however. Eventually I'll need to grease all these joints, and I don't have the right grease, so I might as well clean them out now.




Haven't heard any updates from Denso in a while. I'm trying to lay low and not bug the guy. I might check in again a week or two from now. The main info I'm waiting on is figuring out if the controller parameters can be restored now that the battery is dead. This would originally been done with a floppy disk and a floppy drive "loader" sold optionally with the robot. Without this data I think the control is pretty much dead.

*Encoder / Rockwell servo drive conversion Update: *Been spending a bit of time testing the waters with this idea of converting the encoder signals into something my Rockwell servos would like. Right now my "simple" task is to get a micro controller to read the serial coming out of the robot encoders and be able to store the data in memory. I'll update on that below. If that works, I want to set up the encoder channels to be read using one of the processor's built in quadrature decoder channels. If that works, I'll try to have the serial data and the encoder data in one program, and add a cross check to verify the incremental position against the absolute data in the serial, each time a new packet arrives. If that works, then I need to characterize the communications between the servo drive and a known working motor with the type of encoder I need to emulate. Then I need to program the microcontroller to be able to respond to drive requests in the same format as those motors. Finally I need to bring it all together and use the serial data from the robot to load data into memory, followed immediately by the processor using the contents of that memory to write back to the servo drive requests. Lot of work, but making incremental moves forward.

I picked up a Teensy 4.1 from my local computer supply store. This is a $20 Arduino IDE compatible board, running a Cortex-M7 processor at 600MHz - insane! I compared a lot of options and I started with this one since it has 7 serial ports, each up to 5Mbps, quadrature decoders, and hopefully enough computing power to handle all the tasks I want to do.

Blue board in the lower left is a breakout board for an AM26C32I RS422 differential line receiver, the one right above it is a 5V to 3.3V level shifter that actually works at 2MHz, and the big green board is the Teensy 4.1. It is only about the size of a flash drive. The Teensy 4.0 would also be a perfect fit, and is half the size (but the computer store was sold out)




I am *really* rusty on my embedded programming so this is painful to get started on. I'm incrementally working my way towards the first task of reading the serial stream from the robot encoders. The speed of the signal (2 Mbps, or 2,000,000 bit transitions per second), the manchester encoding, and the non-standard data framing (18 data bits, 3 CRC bits, precision start and stop bits) all make this tricky. I haven't been able to find any library which supports what I want to do so I am expecting I'll have to capture the data, bit by bit using interrupts and interval timers.

I found a super helpful white paper that talked about several processors with CLUs (Configurable Logic Units) like the PIC16F150x and how they implemented manchester decoding the the CLU before the processor gets involved. One of the tricks is that, if you can synchronize with the start bit, the logic level is equal to the voltage level 1/4 cycle before the transition point.

In the image below, the manchester data is sampled in the middle of each grid as it transitions. Transitions on the grey lines do not count. If we were to carefully time the micro to sample at exactly 25% of the way through each grid, then the measured voltage would be equal to the logic state of that bit, without needing to parse the rising/falling edge.


In my best MS paint skills, I've added blue ticks indicating where the processor should sample the signal. Each tick is separated by 1us. The trick will be timing the start of this sequence to align with the right spot in the data. The CRC should provide a good check against getting misaligned in the data.


Based on this, my plan for the code is:

Arm rising edge interrupt (triggers a special function that interrupts everything when a digital input transitions low to high)
When triggered, record time, arm falling edge interrupt
When triggered, record time
Calculated difference in time between interrupts
If equal or greater than ~3.5us (actual start bit is 3.625us), then a start bit was found, continue to step 5
If less than ~3.5us, then it was not a start bit, go back to step 1

Delay small amount (couple hundred nanoseconds) as necessary to align the sampling position with 25% of each data frame
Start a periodic timer @ 1us intervals. Timer triggers interrupt service routine
Each timer interrupt, sample the signal, save value to memory, repeat 21 times
Disable periodic timer interrupt, wait 1 us for stop bit to pass, arm rising edge interrupt (aka. return to step 1)
Process data and save to memory. Do other tasks. There is a 17us delay here where nothing will happen
This code requires the processor's attention every 1us, however most of the implementation is completed in an interrupt service routine with extremely minimal processing. This should leave the processor mostly free to handle other tasks. If the processor needs to "focus" on another task like reading the serial data from the drive, or replying with a serial message to the drive, then interrupts can be turned off and the serial messages from the robot will temporarily be ignored.

Quadrature counts cannot be ignored, however, serial packets from the encoder can be ignored as much as needed. Since they repeat Ad Infinium, missing one packet will not impair the processor's ability to retrieve position data from the next packet.

So hopefully, drive communications always takes priority and an immediate response is sent, quadrature data is handled by hardware and is serviced as much as possible (no count can be missed), and the serial data from the robot is serviced whenever there is time, and we don't care is a couple packets here and there are missed.

If anyone reading has embedded programming experience and knows a better way to do this - please let me know!


----------



## macardoso

My first super simple program, I am echoing the signals coming in on a digital input out onto a digital output. This is triggered by a pin change interrupt on the input pin.

This was a success and proves a few things. First, pin change interrupts work and I can successfully catch each pulse. It also proves that there is enough processor speed to actually do something during the interrupt service routine (ISR). digitalReadFast() and digitalWriteFast() functions come with overhead to interface with the IO. These likely take up most of the processing time. In total, triggering the ISR, reading the input state, copying that data to the output pin, and writing that value to an actual voltage took about 120ns or 72 clock cycles. This is pretty good. In reality, I won't be doing the digital write, which should save some time. If I could set up both rising and falling edge interrupts (not sure if possible) then there also would be no need for a digital read either.

EDIT: With dual interrupt service routines (RISING and FALLING) I was able to eliminate the digitalReadFast() and get the skew down to 100ns or 60 clock cycles. I think this is about as good as it gets without DMA.

EDIT: Direct Memory Addressing (DMA) is another option to improve speed. This is way outside my wheelhouse, but my understanding is that the IO ports are set to slow mode when making the pins available to the processor for read/write. The IO port can be placed in fast mode for DMA, which could reduce latency. But then the pins can only be handled by DMA. I don't know if these timing interrupts can be accomplished with DMA.

My timing goal is to synchronize within 250ns, so I think the capability is there.

In the image below. Yellow is the signal from the encoder, blue is the signal echoed by the micro. The 3rd measurement (FRFR[1-3]) is the skew between the first rising edge of each of the channels, or the delay in processing the signal.






		C++:
	

#include <avr/io.h>
#include <avr/interrupt.h>

/* This code takes a high speed input on pin 15 and echos it on pin 13
* This was to try to recreate the manchester encoded serial data @ 2Mbps
* This code is successful with a skew of ~120ns or 72 clock cycles
* Most of this time is likely digitalReadFast() and digitalWriteFast()
* Time is not affected by choosing other pins
*/

int PinInt1 = 15;
int PinOut1 = 13;

void setup() {
  // put your setup code here, to run once:
  pinMode(PinInt1, INPUT); // sets the digital pin as output
  pinMode(PinOut1, OUTPUT); // sets the digital pin as output
  Serial.begin(115200); //Start USB logging to computer
  attachInterrupt(digitalPinToInterrupt(PinInt1), isrService, CHANGE);
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(1000);
  Serial.println("Running");
}

void isrService()
{
  digitalWriteFast(PinOut1, digitalReadFast(PinInt1));
}


----------



## macardoso

Got another test program written. 

This one expands on the lessons learned on the previous piece of code and focuses on properly identifying the start bit of the serial burst. To do this, I enabled a register which counts the 600MHz clock cycles in a 32 bit memory address. This overflows every 7.16 seconds so care needs to be taken to handle the overflow case.

I trigger an interrupt on the rising edge and grab the cycle counter value. I then disarm the rising edge interrupt and arm the falling edge interrupt. When the pulse falls, I grab the cycle counter again, save it in another variable, and disable the falling edge interrupt. A flag is set indicating that a pulse has been measured.

In the non-interrupt code, once the flag is set, the cycle count at the rising edge is subtracted from the cycle count at the falling edge. If the falling edge count is less than the rising edge count, then the counter rolled over and we need to do (cycleCountFalling + 2^32) - cycleCountRising. The "LL" after the 2^32 constant forces the processor to perform the intermediate math on a 64 bit wide memory address to avoid truncation. The result is checked. If too short or too long (shouldn't happen) then we know the pulse measured wasn't the start pulse. We clear the flag and re-arm the rising edge interrupt to catch the next pulse.

If the pulse width falls in the range of a start pulse, we begin our packet sequence. Right now, all this does is delay a precise value to align a diagnostic output pulse on the desired measurement location (250ns prior to the next rising pulse). Eventually this will start a periodic interrupt timer which reads the data starting at 250ns prior to the next manchester transition, then exactly 1us thereafter for a total of 21 reads. Having a bit of trouble with this periodic interrupt at the moment.

There is a bit of time to be saved by checking the port interrupt flag rather than just the pin change. Many pins share one port interrupt, so if a pin interrupt is enabled, then at the time of the interrupt, the processor must take time to figure out which pin triggered the interrupt. If I am only using one pin per port, then this extra check is not needed.






		C++:
	

#include <avr/io.h>
#include <avr/interrupt.h>

int PinInt1 = 15;
int PinOut1 = 13;
volatile unsigned int clockCyclesRising = 0;
volatile unsigned int clockCyclesFalling = 0;
unsigned int clockCyclesElapsed = 0;
volatile bool intFlag = 0;
IntervalTimer myTimer;

void setup() {
  pinMode(PinInt1, INPUT);
  pinMode(PinOut1, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(PinInt1), isrServiceRising, RISING);
  ARM_DEMCR |= ARM_DEMCR_TRCENA;  //Might not be needed for Teensy 4.x
  ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;   //Might not be needed for Teensy 4.x
  Serial.begin(115200);
}

void loop() {
    if (intFlag == 1){
      if (clockCyclesFalling > clockCyclesRising)
      {
          clockCyclesElapsed = clockCyclesFalling - clockCyclesRising;
          
      }
      else //Handle the case where rollover occurrs between the samples. (2^32)LL forces 64 bit intermediate computation
      {
          clockCyclesElapsed = (clockCyclesFalling + 4294967296LL) - clockCyclesRising;
      }
      if ((clockCyclesElapsed <= 1570) || (clockCyclesElapsed >= 1590)) //Pulse too short (<2us) or too long (>4.5us)
      {
          intFlag = 0;
          attachInterrupt(digitalPinToInterrupt(PinInt1), isrServiceRising, RISING);
      }
      else //Pulse is a start bit (2us<x<4.5us) . Exact clock counts should be narrowed
      {
          intFlag = 0;
          //Serial.println(clockCyclesElapsed);
          delayNanoseconds(450);
          digitalWriteFast(PinOut1, 1);
          //delayMicroseconds(5);
          //digitalWriteFast(PinOut1, 0);
          myTimer.begin(isrPeriodic, 0.8);  //Does not trigger below 0.8us
          //Do periodic timer stuff here
      }
    }
}

void isrServiceRising()
{
  intFlag = 0; //in case the pulse measuring code in loop hasn't been serviced by the time the next interrupt occurs, clear the flag bit
  clockCyclesRising = ARM_DWT_CYCCNT;
  attachInterrupt(digitalPinToInterrupt(PinInt1), isrServiceFalling, FALLING);
}

void isrServiceFalling()
{
  clockCyclesFalling = ARM_DWT_CYCCNT;
  intFlag = 1;
  detachInterrupt(digitalPinToInterrupt(PinInt1));
}

void isrPeriodic()
{
digitalWriteFast(PinOut1, 0);
myTimer.end();
attachInterrupt(digitalPinToInterrupt(PinInt1), isrServiceRising, RISING);
}


----------



## bender1

Hi,
Your project is super impressive. I was just wondering if the encoders of the other joints on your robot are daisy chained to a serial bus between the arm base and controller?


----------



## macardoso

bender1 said:


> Hi,
> Your project is super impressive. I was just wondering if the encoders of the other joints on your robot are daisy chained to a serial bus between the arm base and controller


Hi Bender,

From what I can tell, the serial channels are entirely in parallel. Each motor/encoder gets its own channel back to the main controller.
Pinout from the maintenance manual. There are 6 instances of “motor encoder phase Rx”.




plus, at the baud rate of the serial channel, there isn’t enough dead time on the wire for even two encoders to share without interfering with eachother


----------



## bender1

Thanks. On the newer, but still old and obsolete,  rc5 controller they seemed to have changed to daisy chaining them together with what I assume to be rs485. The seem to be using some propriety panasonic encoder protocol too. Keep up the good work on your project!


----------



## macardoso

bender1 said:


> Thanks. On the newer, but still old and obsolete,  rc5 controller they seemed to have changed to daisy chaining them together with what I assume to be rs485. The seem to be using some propriety panasonic encoder protocol too. Keep up the good work on your project!


Huh cool! Thanks for sharing that. I have no experience with any Denso robots with the exception for the one I am messing around with right now. The motors I have are addressable (although not sure how address setting would even be achieved) but limited to 0-3, so not enough addresses for the whole robot. 

The interesting this is that Denso special ordered these Panasonic motors with non-standard encoders. Kinda strange.


----------



## macardoso

Still working on the encoder interface code, but running into a couple issues. I'll post an update soon.

I completed cleaning of Joint 3 gearbox. The wave generator from the harmonic drive was also starved of lubrication like joint 2, and was covered in mud brown deposits, however it was much less gritty.




I fully disassembled the wave generator and cleaned it with WD-40, alcohol, and dish soap. It took some work to remove the dried grease and grit from the nooks and crannies.




With this gearbox, the harmonic drive flex spline had two tapped holes which allowed me to use them to push the cup out. 




Once removed, I could clean the ring gear which you can see in the picture below. This can be removed, but there was no reason to do so as it can be cleaned in place with a tooth brush.




Below you can see the flex spline cup. Imagine machining this. It has extremely thin walls with precision spline teeth around the perimeter. The steel is also a special alloy with good fatigue resistance as this part flexes many billions of times during its lifespan. This component is the output of the gearbox. The teeth were fairly dirty and I was glad to have the opportunity to clean it. Wish I could have pulled the J2 cup, but there were no extraction holes. 




All cleaned up




And assembled with the clean wave generator. Rotating the input shaft creates a travelling wave along the perimeter of the spline teeth. 




I screwed up removing the motor mount thinking the motor mount holes were tapped through (hoping to use these to push the motor mounting plate off - it was stuck on with sealant). When I bottomed out the screws, it dented the rear surfaces outward. Whoops! I used a punch and hammer to peen the metal back to the original form, then cleaned it up with a fine stone. I hate messing stuff up, but I repaired this quite well. Picture is before the repair.




The gearbox was prepacked with the new low viscosity lithium grease.




And the motor was mounted again. A couple dozen pumps of grease through the nipple fully flushed the system. Gearbox sounds great and is very quiet.




Will keep going through each gearbox.

-Mike


----------



## macardoso

Back to some of the encoder interface board stuff.

I was able to get the microprocessor to line up its sampling of a periodic timer within the permissible 250ns. In fact, the sync is much more accurate than that, usually within 2-3ns. Measurement #3 is the sync value, target is 3.375us and the average is 3.38us, potentially within rounding error.

The yellow is the input signal, and the blue signal represents each moment the yellow signal is sampled (represented by the transitioning edge of the blue signal. The rising or falling edge of the blue signal needs to be perfectly synced in the brief period before the yellow signal transitions to get a good reading. The blue signal identifies the start bit and syncs, then takes 21 samples, wait for the stop bit to pass, and re-arm the trigger.




This works great, however turning on "Fast Capture" on the scope and display persistence, I could see the blue signal would occasionally glitch and trigger at the wrong time. This is no good. 




Took me a long time to actually capture a glitch. Seems like a 1 in 10000 occurrence, but using the scope's segmented memory and search functions, I was finally able to get a capture. It seems like in some rare cases, the periodic timer ends up waiting for a very long time, much longer than the prescribed delay. when this happens, the whole sequence gets off and takes several serial packet cycles before the signal can re-sync. 




I tried many things to get rid of these glitches but nothing seemed to work. This could be dealt with by verifying the CRC and throwing away these rare bad packets, but I would prefer a more stable solution.

I'm now a member on the Teensy microprocessor forum and there are many people much smarter than me there. They recommended the best way to approach this is to use the hardware clock cycle counter capture option. Basically this is a fully hardware implemented circuit that captures the exact clock count when an input changes from low to high or high to low. By comparing the difference between two samples, you can know the pulse width that was captured. This is done in hardware and really offloads the effort from the processor. I got a simple program working which prints out the width of each captured pulse, but does not trigger on the start bit. 



		C++:
	

#include "Arduino.h"

constexpr unsigned maxEdges = 14;
uint32_t  cap_index;
volatile uint16_t cap_vals[maxEdges];

IMXRT_TMR_CH_t& ch = IMXRT_TMR1.CH[2]; // TMR1_2 -> input pin 11

bool recording = false;

void onCapture()
{
    ch.SCTRL &= ~(TMR_SCTRL_IEF); // no need to check which flag was set since we only enabled IEF
    if (recording)
    {
        cap_vals[cap_index++] = ch.CAPT;  // store the captured value
        if (cap_index >= maxEdges)
        {
            recording = false;
            cap_index = 0;
        }
    }
    asm volatile("dsb"); // wait for clear  memory barrier
}

void initTimer()
{
    cap_vals[0] = 0;
    cap_index   = 0;

    *(portConfigRegister(11)) = 1;        // Alt1, use pin11 as input to TMR1_2
                                          //
    ch.CTRL  = 0;                         // stop timer
    ch.SCTRL = TMR_SCTRL_CAPTURE_MODE(3); // capture at rising and falling edges
    ch.SCTRL |= TMR_SCTRL_IEFIE;          // enable input edge flag interrupt
    ch.LOAD = 0;

    attachInterruptVector(IRQ_QTIMER1, onCapture);
    NVIC_ENABLE_IRQ(IRQ_QTIMER1);

    ch.CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 0) | TMR_CTRL_SCS(2); // source: peripheral clock, prescaler 0, use counter 2 input pin for capture
}

void setup()
{   
    initTimer();
    recording = true;
}

void loop()
{
    if (!recording)
    {
        for (unsigned i = 0; i < maxEdges - 1; i++)
        {
            uint16_t x;
            if (cap_vals[i + 1] > cap_vals[i])
            {
                x = (cap_vals[i + 1] - cap_vals[i]);
            }
            else
            {
                x = (uint16_t)0xFFFF - (cap_vals[i] - cap_vals[i + 1]);
            }
            Serial.printf("%.2f ", 1E6 * x / F_BUS_ACTUAL);
        }
        Serial.println();
    }
    recording = true;
}


I've been trying to get the program to not start a capture until a start bit is found, thus anchoring the printed data with a start bit first and one serial packet per line. Unfortunately, right now, I don't have that working. 

Will keep updates coming,

Mike


----------



## macardoso

Had another eBay seller of a NOS teach pendant with cable message me yesterday with the ohmed out cable! Some people are just awesome.




At first I was worried because none of the connections lined up. Then I realized from his other sketch that he got the DB15 pin order wrong. Once I transposed the pin numbers, things starting looking great!




Referencing both messages, I overlaid the wiring diagram and got a 1:1 match! This is awesome. I'm going to go ahead and make that cable next.




I was only able to find the 6m "extended" encoder feedback cable, and I opted to match that length when I bought the robot power cable. That could mean the robot could be located as much as 20' from the control box. I think I will match that length with the teach pendant cable as well, so you can always reach the robot with the teach pendant. The manual lists a 6m option for the teach pendant cable so I think this should be OK.


----------



## macardoso

Started making some cables.

A warm up was the ESTOP cable. This one used the mystery connector. It was a bit funny because it solders from the front (there is no metal inside the connector to solder to. This was actually kinda tricky to not get solder all over the outside of the contact pin.







And all done! I used some 4 conductor sensor cable (6m long) which has a bright yellow jacket that makes me think of safety  . I have an ESTOP box which I can put on the other end. Two conductors are soldered to pins and the other two are jumpered. This allows me to use two ESTOP contacts if I'd like for better safety.


----------



## macardoso

Next was the round connector for the teach pendant. The connector body is very short, so the exposed wires at the end of the jacket also needed to be very short. This made it quite difficult to get the soldering iron in there to work on it. Picture makes it looks easier than it was. I used some L-Com D-Sub 15 conductor cable with a foil shield and drain wire. I only needed 10 conductors so 5 were clipped. Like the rest of the cables, I chose to make this 6m long as well.




And this end plugged into the Teach Pendant.




The other end terminates in a DB-15 standard density connector. I chose to make the jumper connections on this end of the cable.




Some extra vises really helped with holding the cable since you need at least 3 hands to solder.




These photos show the black wire jumpers. These got tucked inside the plastic shell.







Worked against my cable drawing.




All done!


----------



## macardoso

Next I started on the motor power cable. This connector (MIL-DTL-1566) was much larger and quite a bit easier to solder than the last connectors, but the cable was also very stiff and hard to work with.




I got the ends of each conductor tinned and cut to length.




I also applied a small glob of rosin flux to each pin.




Since the wires could be stripped longer, I was able to add a small bit of heat shrink to each conductor. This keeps it tidy and prevents shorts, although I doubt it has 600V dielectric strength to insulate the drive PWM output.




I got one more row past this done before calling it a night. It is tedious but also quite enjoyable. I have to do the exact same thing on the other end of the cable.


----------



## Cadillac STS

This is a really great thread and I am glad you are doing it in detail like this.

I think at this point it is getting close to the scene in Iron Man 1 (Or maybe 2) where Tony Stark puts sensors on his own arm and that makes the robotic arm move like his own...


----------



## macardoso

Made some more progress on the cables. Motor power cable is done. The controller end was soldered much like the robot end.




All done! My careful selection of wire numbers to pins left the cable uncrossed at either end. This is important because there wasn't enough room to deal with crossed wires.




Some heat shrink completed the connection.




Beauty shot, stacked on top of the cables. All I have left now is the power cable, a grounding conductor between the control and the robot body, and the valve/end-of-arm-tooling (EoAT) connector. I justed ordered those connectors from eBay and Digikey. Not too expensive thankfully!




I chatted with the tech support guy from Denso again and he gave me some great news. Apparently the only data that is battery backed in the controller is the user programs and calibration parameters. All critical parameters related to the robot geometry and the actual control functions of the box are saved in EEPROM. This means that I don't need the parameters set or the floppy reader to get this working! He shared a simple procedure to wipe corrupted parameters and programs from the control once I boot it up. From there I should be able to run the calibration sequence, enter the RANG calibration parameters from a label on the robot, and get it running!

The control will need a new 3V battery. I bought one from Digikey for $5. I'll need to solder the wires and connector to it myself. This is a non-rechargeable battery. 




I also need to replace this board. Denso does not make them anymore so I plan to either re-populate or build a custom PCB to do the same thing as this one is. The batteries were bought from Digikey for $8 each and a new 5.5V super capacitor for $4.

It would be helpful to have spare boards and connectors for both batteries to facilitate the swap 2 years from now.










And here is a beauty shot of the entire control box again!




I need to pick up some wire to build the power cable and I need to get some electric service installed in my basement. A friend of mine has offered up a 240V input 208V output 2kVA transformer which will get this box powered.

I still need to ohm out all the cables to verify they are correct. Additionally, I want to do some sleuthing inside the control box to verify the motor power cable is straight-thru. I only have a pinout for the robot end of the cable. I expect it to be, but cannot be certain.


----------



## macardoso

I've been working on the coding of the feedback interface boards. As a reminder, these are NOT needed to run the robot with the original control, but they will be necessary if the robot is to be run by a Rockwell Automation servo drive.

I'll spare the nitty gritty details here since they are probably boring, but here is a link to another forum where I got a lot of help on the code: https://forum.pjrc.com/threads/54962-Interrupt-on-Rising-and-Falling-on-the-same-pin

The current implementation of the code (not written by me!) uses a hardware based clock cycle capture function to measure pulse width of the bit stream, pass that to a circular buffer using Direct Memory Addressing (DMA), and is decoded and printed to the serial port. The hardware capture and DMA make sure that all timing critical functions are handled in hardware and are free of processor latency. The decoding is done more slowly when the processor has time to service the requests.

My original code and the hardware cycle counter capture method without DMA both failed occasionally when some high priority processor interrupt took over and blocked reading the edges. The CRC still needs to be implemented, and this would help resolve that issue, but the DMA route does not seem to suffer from this issue.

I still need to read the quadrature signals from the encoder to increase the single turn resolution from 11 bits to 13 bits, borrow an Allen Bradley TLY motor with Tamagawa feedback from work and characterize its communication, then finally program the microcontroller to generate response packets to the drive that emulate the TLY motor. Lots of work to go, but having this part working is a big step forward.

Here is the code (Reminder, this is a Teensy 4.1 running Teensyduino firmware, so the implementation on another microcontroller will be different, especially the hardware and DMA calls):

Main function:


		C++:
	

#include "Arduino.h"
#include "decoder.h"

Manchester::Decoder decoder;
Manchester::TS5643Field old, result;

void setup()
{
    decoder.begin(2E6); // 500ns clock
}

void loop()
{
    while (!decoder.resultBuffer.isEmpty())
    {
        decoder.resultBuffer.pop(result);
        Serial.println(result);
        /*if (result.count != old.count + 1)
        {
            Serial.printf("Error %d, %d --------------------------------\n", old.count, result.count);
        }*/
        old = result;
    }
    delay(1); // do something else, make sure you don't spend too much time otherwise the edge buffer might overflow and you'll loose data
}

void yield()
{
    decoder.tick(); // tick the decoder from yield to get ticks even during delays and other time consuming tasks...
}


A non-interrupt blocking circular buffer implementation:


		C++:
	

#pragma once

#include <Arduino.h>

template <typename ET, size_t S>
class RingBuf
{
public:
    /* Constructor. Init mReadIndex to 0 and mSize to 0 */
    RingBuf();

    /* Push a data at the end of the buffer */
    bool push(const ET inElement);

    /* Pop the data at the beginning of the buffer */
    bool pop(ET& outElement);

    /* Return true if the buffer is full */
    bool isFull() const { return mSize == S; }

    /* Return true if the buffer is empty */
    bool isEmpty() const { return mSize == 0; }

    /* Reset the buffer  to an empty state */
    void clear() { mSize = 0; }

    /* return the size of the buffer */
    size_t size() const { return mSize; }

    /* return the maximum size of the buffer */
    size_t maxSize() const { return S; }

private:
    ET mBuffer[S];
    size_t mReadIndex;
    size_t mSize;

    size_t writeIndex();
};

template <typename ET, size_t S>
size_t RingBuf<ET, S>::writeIndex()
{
    size_t wi = mReadIndex + mSize;
    if (wi >= S) wi -= S;
    return wi;
}

template <typename ET, size_t S>
RingBuf<ET, S>::RingBuf()
    : mReadIndex(0), mSize(0)
{
}

template <typename ET, size_t S>
bool RingBuf<ET, S>::push(const ET inElement)
{
    if (isFull()) return false;
    mBuffer[writeIndex()] = inElement;
    mSize++;
    return true;
}

template <typename ET, size_t S>
bool RingBuf<ET, S>::pop(ET& outElement)
{
    if (isEmpty()) return false;
    outElement = mBuffer[mReadIndex];
    mReadIndex++;
    mSize--;
    if (mReadIndex == S) mReadIndex = 0;
    return true;
}


Header for the DMA edge capture:


		C++:
	

#pragma once

#include "DMAChannel.h"

namespace Manchester
{
    class EdgeProviderDMA
    {
     public:
        static void init();

        static uint16_t popTimestamp();
        static bool hasElements();

     protected:
        static uint8_t tail;
        static DMAChannel dmaChannel;
        static constexpr IMXRT_TMR_CH_t* ch = &IMXRT_TMR1.CH[2]; // TMR1 channel 2 -> input pin 11,
    };
}


Code for the DMA edge capture:


		C++:
	

#include "edgeproviderDMA.h"
#include "pins_Arduino.h"
#include <cstdlib>

namespace Manchester
{
    constexpr size_t bufSize = 256;                                         // DMA buffer for edge timestamps (512 bytes, 256 timestamps)
    uint16_t buf[bufSize] __attribute__((aligned(512)));                    // The DMA controller will replace the lowest n-bits of the address by a counter
                                                                            // to implement the circular buffer -> we need to align the start address of the buffer
    void EdgeProviderDMA::init()                                            // such that it corresponds to a countervalue of 0
    {                                                                       //
        *(portConfigRegister(11)) = 1;                                      // ALT1, use pin 11 as input to TMR1_2
                                                                            //
        ch->CTRL  = 0;                                                      // stop timer
        ch->SCTRL = TMR_SCTRL_CAPTURE_MODE(3);                              // both edges, enable edge interrupt
        ch->LOAD  = 0;                                                      // reload the counter with 0 at rollover (doesn't work without setting this explicitely)
        ch->DMA   = TMR_DMA_IEFDE;                                          // DMA on capture events
        ch->CTRL  = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 3) | TMR_CTRL_SCS(2); // start, source: peripheral clock, prescaler 3 (=> dt = 1/150Mhz * 8 = 53ns resolution, 2^15 * 53ns = 3.5ms max), use counter 2 input pin for capture
                                                                            //
        dmaChannel.begin();                                                 //
        dmaChannel.triggerAtHardwareEvent(DMAMUX_SOURCE_QTIMER1_READ2);     // trigger DMA by capture event on channel 2
        dmaChannel.source(ch->CAPT);                                        // DMA source = capture register (16 bit)
        dmaChannel.destinationCircular(buf, bufSize * sizeof(uint16_t));    // use a circular buffer as destination. Buffer size in bytes
        dmaChannel.enable();
    }

    uint16_t EdgeProviderDMA::popTimestamp()
    {
        return buf[tail++];
    }

    bool EdgeProviderDMA::hasElements()
    {
        return dmaChannel.destinationAddress() != (buf + tail);
    }

    DMAChannel EdgeProviderDMA::dmaChannel;
    uint8_t EdgeProviderDMA::tail = 0;

}


Header file for the bit stream decoder:


		C++:
	

#pragma once
#include "RingBuf.h"
#include "TS5643Field.h"

namespace Manchester
{
    union frame_t
    {
        struct
        {
            uint32_t modemAddress : 2;
            uint32_t payload : 15;
            uint32_t frameAddress : 1;
            uint32_t frameCRC : 3;
        } bits;
        uint32_t data;
    };

    using ResultBuffer = RingBuf<TS5643Field, 10000>; // Keep results

    class Decoder
    {
     public:
        void begin(float baudrate);
        void tick();
        ResultBuffer resultBuffer;

     protected:
        bool decode(uint16_t dt, uint32_t* f0, uint32_t* f1);
        bool initialized = false;

        uint32_t bitCnt;
        frame_t frame0, frame1;
        frame_t* currentFrame;
        TS5643Field received;
        bool edge;

        enum states {
            SYNCING,
            SYNCED,
        } state = states::SYNCING;
    };
}


Code for the Bitstream Decoder:


		C++:
	

#include "decoder.h"
#include "edgeproviderDMA.h"

namespace Manchester
{
    void Decoder::begin(float baudrate)
    {
        resultBuffer.clear();
        EdgeProviderDMA::init();
        state        = states::SYNCING;
        currentFrame = &frame0;
        initialized  = true;
    }

    void Decoder::tick()
    {
        if (!initialized) return;

        //static uint32_t oldCount     = 0;
        static uint16_t oldTimestamp = 0;

        while (EdgeProviderDMA::hasElements())
        {
            uint32_t payload_0, payload_1;
            uint16_t timestamp = EdgeProviderDMA::popTimestamp();
            uint16_t dt        = timestamp - oldTimestamp;
            oldTimestamp       = timestamp;

            if (decode(dt, &payload_0, &payload_1)) // If decoder returns true, the payloads of the first and second frame are valid
            {
                TS5643Field field;
                field.count = (payload_0 & 0x7FFF) | ((payload_1 & 0x1FF) << 15); // bit 0-14 in frame0 bit 15-23 in frame1
                field.BE_OS = payload_1 & 1 << 9;
                field.OF    = payload_1 & 1 << 10;
                field.OS    = payload_1 & 1 << 11;
                field.BA    = payload_1 & 1 << 12;
                field.PS    = payload_1 & 1 << 13;
                field.CE    = payload_1 & 1 << 14;

                // if (field.count != oldCount + 1)  // error detection
                // {
                //     digitalWriteFast(10, HIGH);
                // }
                // oldCount = field.count;
                resultBuffer.push(field);
                // digitalWriteFast(10, LOW);
            }
        }
    }

    bool Decoder::decode(uint16_t delta_t, uint32_t* payload_0, uint32_t* payload_1)
    {
        constexpr uint16_t T       = 500;                   // timing of a half bit
        constexpr uint16_t syncMin = 2625 - 100;            // min duration of sync pulse
        constexpr uint16_t syncMax = 2625 + 100;            // max duration of sync pulse
        static bool first          = true;                  // keep track of the 2T timing
                                                            //
        uint16_t dt = delta_t * 8.0f * 1E9f / F_BUS_ACTUAL; // time in ns since last timestamp
        edge        = !edge;                                // we detect both edges -> direction will necessarily toggle at each event

        switch (state)
        {
            case SYNCING:
                if (dt > syncMin && dt < syncMax)
                {
                    currentFrame->data = 0;
                    bitCnt             = 0;
                    first              = true;

                    state = SYNCED;
                    // Serial.println("Sync");
                    edge = 0;
                }
                break;

            case SYNCED:
                if (dt > T * 3.5 || dt < T * 0.5) // timing to much off, probably a break, need to resync
                {
                    Serial.printf("bad %d\n", dt);
                    state = SYNCING;
                    break;
                }

                // decode
                if (dt > T * 1.5) // dt = 2T
                {
                    currentFrame->data |= (!edge << bitCnt++);
                }
                else // dt = T
                {
                    if (!first)
                    {
                        currentFrame->data |= (!edge << bitCnt++);
                    }
                    first = !first;
                }

                if (bitCnt > 21) // got complete frame
                {
                    if (currentFrame == &frame0 && currentFrame->bits.frameAddress == 0)
                    {
                        currentFrame = &frame1;
                    }
                    else if (currentFrame == &frame1 && currentFrame->bits.frameAddress == 1)
                    {
                        currentFrame = &frame0;
                        *payload_0   = frame0.bits.payload;
                        *payload_1   = frame1.bits.payload;
                        state        = states::SYNCING;
                        digitalWriteFast(8, LOW); //
                        return true;
                    }
                    else
                    {
                        currentFrame = &frame0;
                        Serial.println("framesync");
                    }
                    state = states::SYNCING;
                }
                break;

            default:
                break;
        }
        digitalWriteFast(8, LOW); //
        return false;
    }
}


Header file for the TS5643 implementation:


		C++:
	

#pragma once
#include "Arduino.h"

namespace Manchester
{
    struct TS5643Field : Printable
    {
        uint32_t count; // counter value
        bool BE_OS;     // Battery error | Overspeed (ored)
        bool OF;        // Overflow
        bool OS;        // Overspeed
        bool BA;        // Battery alarm
        bool PS;        // Preload status
        bool CE;        // Count Error

        TS5643Field();
        void clear();
        size_t printTo(Print& p) const override;
    };
}


Code for the TS5643 implementation:


		C++:
	

#include "TS5643Field.h"

namespace Manchester
{
    TS5643Field::TS5643Field()
    {
        clear();
    }

    void TS5643Field::clear()
    {
        count = 0;
        BE_OS = LOW;
        OF    = LOW;
        OS    = LOW;
        BA    = LOW;
        PS    = LOW;
        CE    = LOW;
    }

    size_t TS5643Field::printTo(Print& p) const
    {
        return p.printf("cnt: %d, BE+OS:%d OF:%d OS:%d BA:%d PS:%d CE:%d", count, BE_OS, OF, OS, BA, PS, CE);
    }
}


And some sample encoder data coming out of the serial port:


		Code:
	

cnt: 2837, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2838, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2838, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2838, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2838, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2839, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2839, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2839, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2839, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2840, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2840, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2840, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2840, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2841, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2841, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2841, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2841, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2842, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2842, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2842, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2842, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2843, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2843, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2843, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2843, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2844, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2844, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2844, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2844, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0
cnt: 2845, BE+OS:0 OF:0 OS:0 BA:1 PS:0 CE:0


In the next version of this code, I will try to add a hardware quadrature encoder decoder, and compare that data to the serial transmissions. This cross checks against bad data or lost counts. Not sure which piece of data I will trust. This should save the positions to the tightly coupled memory on the chip for fast read/write access when it needs to generate a response to the servo drive.

I've also bought some extra hardware to let me wire in the serial channel from the drive as well as the quadrature encoder signals. This was all cheap from Digikey, but man is everything out of stock. It is crazy.


----------



## rabler

Yeah, those lost interrupt/race conditions will get you every time.  That's the real killer of coding at this level.  Debugging those types of interactions is a really pain.  Glad you found some help.


----------



## macardoso

A quick check last night informed me that the motor power cable is not 1:1. So that sucks.

I have to ohm out the connections at the controller and likely rewire the controller side of the power cable.


----------



## macardoso

rabler said:


> Yeah, those lost interrupt/race conditions will get you every time.  That's the real killer of coding at this level.  Debugging those types of interactions is a really pain.  Glad you found some help.


Yeah, I'm not a great programmer and this low level micro controller code is tough for me. Having fun with it though


----------



## rabler

macardoso said:


> Yeah, I'm not a great programmer and this low level micro controller code is tough for me. Having fun with it though


It's tough, you need a sense for it which is just a matter of time learning it.  But you have to ask yourself for every line of code, can this get messed up by an interrupt?    A = A + 1  is sensitive if there is an interrupt that can change the value of A.  The other thing you get into is timing and latency, how long can something go ignored (such as interrupts disabled, or processing a different interrupt) before it causes an issue?


----------



## macardoso

macardoso said:


> A quick check last night informed me that the motor power cable is not 1:1. So that sucks.
> 
> I have to ohm out the connections at the controller and likely rewire the controller side of the power cable.



So I was a bit premature in stating this. The controller has a non sequential pinning, but so does the robot. The cable seems to work out straight thru, which is good news, because that how I wired it.




The maintenance manual includes several pages of worksheets to verify continuity in the robot and helps check the pinning. With the robot cables connected, I am going through each of these worksheets and verifying the connections. So good so far on J2, J3, and J4. I'm also learning my way around the control box which will be necessary.




Finally, I was amazed, but the controller ROM backup battery still has 3.05V on it (nominal is 3V). There is a slim but not impossible chance that it has never died and the controller is still backed up. We will have to see once I can get it powered on.


----------



## gjrepesh

I am dabbling in Sherline CNC and find that challenging. Robotics seems so far above that. Curious, what is your background that you can dig into projects like this? What a challenge.


----------



## macardoso

gjrepesh said:


> I am dabbling in Sherline CNC and find that challenging. Robotics seems so far above that. Curious, what is your background that you can dig into projects like this? What a challenge.


I started with a Sherline CNC at the end of high school and graduated to a G0704 CNC which I built several control cabinets for over the years.

Studied mechanical and electrical engineering in college and went into industrial automation with a focus in motion control and AC servo technology. Was always enamored with industrial robots and started studying the math behind the motion control in my free time (very complicated stuff, really struggled to learn it). Unfortunately due to my mechanical and controls background, I was never happy with just looking at the math, a 3D model simulation, or a crappy robot using hobby servos. So I knew a place that sold robots and occasionally they come up cheap. The first one I found was a 4 axis SCARA and I bought it without knowing what I would get myself into. That one required me to use a PLC and design custom feedback interface boards to run it. It was cool but I always wanted a 6 axis one. This one eventually came up and I snatched it up. 

I have *hopefully* a bit of an easier time with this one because I can run it on the original control if nothing is broken. I may optionally also get it running on a Rockwell PLC with Rockwell servo drives (hence the feedback interface programming above) but I hope I don't have to.

So background in engineering, lots of professional experience in AC servos and motion control, and a hobby in robotics.

I've found robotics to have a significantly higher barrier to entry than CNC.


----------



## macardoso

Denso passed me two more files which I will share here. A list of Error Codes and a list of replacement part numbers.


----------



## macardoso

Got a big order from Digikey. The main items were the Lithium Thoinyl Chloride primary batteries for the controller memory backup and robot actuator encoder absolute position backup. 

I could have probably just replaced the batteries on the existing board, but the dimensions varied just a bit, and it was in my interest to have a few spare boards to facilitate swapping batteries in the future.

I was able to get some PCBs designed based on the original board in Autodesk Eagle in a couple hours. I'm super rusty in this software as I haven't used it in 2 years, but I was able to make custom footprints for all the components and layout a board pretty easily. My board will be a bit larger than the original board as there is enough space in the robot and the new batteries were each 0.5mm larger in diameter than the old ones. This stacked up and required a slightly larger board. A new 5.5V 1.0F supercapacitor was sourced as well, bringing the total cost for the board up to $45 (batteries. capacitor, mini-mate connector) plus the cost of the PCB ($31 for 10 boards, includes $20 shipping). 

View inside Eagle:



Example View, Black Soldermask, White Text, Gold Pads:



These should be here within 2 weeks or so. Need to get an electrician to install some 240V and 208V outlets in the basement.


----------



## macardoso

Took just a couple weeks to get my new PCBs shipped the cheapest method. Think 10 boards cost me $20 shipped. They are beautiful. 




Here is a mockup of the 5 battery cells. They are just slightly wider than the old batteries.




Transferred the wiring harness from the robot's original PCB to the new one. I have spare connectors, pins, and a crimping tool, so I will make 1 or 2 spare boards to facilitate a swap a few years from now. The supercapacitor is new (5.5V 1.0F yikes!) .

I'm holding off on soldering the batteries until the robot is ready to be powered on. There was some clear shrink wrap over the old battery board that I'll need to replace with something equivalent.




New board with batteries ready to be soldered on.




I have an electrician scheduled to install 240V and 120V outlets in my basement. I was going to do it myself, but the cost of the materials from Menards was almost as much as the electrician wanted for parts and labor. I still need to pick up the 240V to 208V transformer from a buddy back where I used to live. That will require both primary and secondary fusing, so I'll need a simple interconnect box to go with it. I'm thinking I''ll attach the transformer, interconnect fuse box, and 208V outlet to a plywood skid that I can hang on the wall next to one of the 240V outlets. Then the converter is portable as needed.

It took me a LOT of effort, but I finally got the correct connector for the end of arm tooling. I had originally purchased a DENSO original, but it was for the dust proof robot option only and did not fit this one. I could not locate the correct DENSO part for my robot, but I found a, now obsolete, connector made by DDK who supplied the connectors to DENSO. There are only something like 30 left in stock worldwide as far as I could tell. Not cheap either, but necessary to hook up end of arm tooling.







Need to keep cleaning all the gearboxes. Once power is available, I hope I can power the original control up and run the robot. There are a million and one things that could go wrong, but I am optimistic.


----------



## macardoso

Been stalled on this, but finally getting ready to take some steps forward.

I am picking up a 240V -> 208V buck transformer (1 phase 2 kVA) which will get my supply power down to the required 210V +/- 10% for the robot controller. An electrician is coming early next week to install 240V and 120V outlets in the basement for the lathe, mill, SCARA robot, Denso robot, and one spare hookup.

I got the SCARA robot lifted onto the table I have for it (it weighs about 140lbs and was a bear to get up there. Didn't feel like using the engine hoist. 




Fun shot with the two robots side by side.




I think the next steps will be to build a mobile carrier for the stepdown transformer and the associated primary and secondary fusing. Then build a power cable for the Denso robot controller. Finally, I should be able to (*hopefully*) power on the controller, replace the encoder battery, replace the controller battery, and start dealing with whatever error messages are displayed. There are a ton of unknowns here, but in the best case, I only need to zero the encoders, recalibrate the robot, and clear the controller memory.


----------



## macardoso

Picked up a basic 2 jaw parallel gripper for the robot. It was $20 on eBay so I figured why not. 




This particular gripper is very tiny, measuring an inch by an inch and a half. The jaws can stroke 1/8" and apply a maximum of 40lbs of clamping force. This will be perfect for lightweight gripping tasks.

Once things are running, I think I'm going to machine some tooling to allow the robot to do pick and place assembly with Lego pieces. Should be a good test of the dexterity and accuracy of the robot.


----------



## macardoso

Electrician comes tomorrow. Spent just a little bit of time over the weekend working on the transformer sled for the robot.

The transformer is an ACME 2kVA autotransformer. Pretty cool thing honestly, first time I have used one. Takes in a whole range of input voltages and spits out 16 or 32VAC. This can be tapped to add or subtract the 16 or 32VAC from the original supply. In my case I'm doing 240V - 32V = 208V which is within the robots 210 +/- 10%. The tapping of the transformer looks like below.







I'm setting this up to be able to plug into any 30A 240V outlet in my basement. Per NEC, since my supply breaker is larger than 250% of the primary current, I need both primary and secondary fusing on the transformer. I got my hands on a little 8x6 Hoffman enclosure to hold these. I had to make a subpanel from some sheet metal I had hanging around. My shop is set up pretty efficiently for making panels so I was able to pop this one out in about 1.5 hours. There are two banks of fuses, input @ 10A and output @ 15A, both time delay Class CC. There will be two pigtails with a NEMA L14-30P (input) and a NEMA L6-20R (output). Waiting for some cord grips to come in the mail which I'll use with some SO cord to wire between the box and the transformer. I also am in the process of making the plywood skid that will hold both of these and hang on the wall.




And the pair side by side as they'll be mounted.




I also got the J5 gearbox cleaned out and re-greased. This one was in pretty good shape, but now it has the compatible grease for what I have in the grease gun. I still need to do J6 (easy to access) and J1 (very hard to access). I might revisit pulling the flex spline from J2 since it was the one with the most grit in it - must've been used more than the others. The pictures are nothing special so I'm not going to bother sharing them.

Before I power this on, I need to do the following:

Verify all connectors inside the robot are secure
Finish ohming out the power connections to the motors (this verifies my DIY motor cable). I'm 2/3 done.
Verify the polarity of all (6) battery board connections. Getting them flipped will burn out the encoders!
Solder the lithium primary batteries to the battery board and install.
Verify I tightened the Denso servo drive module securely to the control box (I removed one for inspection)
Put some sort of filter paper over the fan intake and exhaust
Verify voltage on controller battery
Verify pinout of DIY teach pendant cable against sketches from eBay sellers. Verify no shorts between pins.
Verify supply voltage at 208V
Wire the input power cable. Triple check input voltage connections
Install ground conductor between robot and controller.
Pray to the good lord that the input MOVs don't blow up when I power it on and that I didn't screw anything else up.


----------



## macardoso

Made up a quick label for the inside of the door of that fuse box.

EDITED IMAGE


----------



## macardoso

Finished the transformer sled. Electricians got about halfway done yesterday. Hope they can finish today. They're doing a lot of work, glad I hired it out.

Made up a simple 3/4" thick plywood sled on the table saw and miter saw. My woodworking skills are garbage and table saws scare the bejesus out of me. I used a hole saw and a jigsaw to cut the handle. The outline was drawn in CAD and transferred to the board with a printout.

I didn't have a step drill big enough to cut the 3/4" and 1" trade size knockouts (1.125" and 1.375" respectively) and didn't want to buy the $80 tool. Instead I got 2 hole saws. This was a terrible idea and while they did cut holes, the edges were super jagged, oversized, and it scratched the crap out of the paint all around the hole. Not happy but it is done. 

McMaster Carr delivered some cord grips to me to fit these new knockout holes as well as the punched knockouts on the bottom of the transformer.

I wired the taps inside the transformer per the manufacturer data sheet, but I'm going to be nervous plugging it in.



I used a 5/8" spade drill to counter bore the back of the board for a washer and nut for 1/4" bolts. This way the back of the board is flat and smooth. Access holes were drilled to install the small cover screws for the bottom of the transformer once it was mounted.

The transformer was particularly annoying to mount since it didn't have mounting holes. I ended up fabricating a steel bracket with through holes for 1/4" bolts on the bottom. The transformer could be slid onto the bracket using the hanger on the rear. Once the transformer was on, I could screw 2 screws from the back into tapped holes at the top of the bracket to fix the bracket. There is one hole at the bottom of the transformer that I could bolt through and this rigidly locked the transformer to the board. 




Here is the finished wiring. I can hook this up to any 240V supply (up to 40A on the panel breaker) and get 208V on the output. The Class CC time delay fuses protect the transformer and secondary wiring.




Here is the finished sled. NEMA 14-30P plug on the input, which matches all my machine tools, and NEMA L6-20R inline receptacle on the output which matches the power cable for the robot.


----------



## rabler

You do great work, very impressive.


----------



## macardoso

rabler said:


> You do great work, very impressive.


Thanks, I really appreciate that. Everything takes me forever to get done, but I'm proud of most of it.


----------



## macardoso

Not much to share new, but I did lay out the whole robot system on the workbench. Fun to look at.

Added labels:
1) Transformer sled, 240V input, 208V output, 2.0kVA
2) Robot power cable, 3'
3) RC3-V6A Robot controller
4) PLC interface cables. (1) Input Cable, (2) Output Cables, (1) Valve Command Cable
5) Robot motor cable, 20'
6) Robot encoder cable, 20'
7) STOP cable, 20'
8) Pendant cable, 20'
9) Teach pendant
10) ESTOP console
11) VS-6354CM Robot
12) Robohand Gripper, RP-5
13) Compressor, regulator, filter, tubing (To be added)
14) End of arm tooling connector, 10 pin
15) Pneumatic fittings for end of arm tooling







Thank God I didn't pay that much for it!
















That's all for now. Next step is to finish me power on checklist and wait for the electricians to get their work done.


----------



## macardoso

With the whole system put together, I had a couple of thoughts about what I DON'T have to go with this robot.

I have the WINCAPS software for offline programming (not sure how this works) but it needs Windows 3.1, '95, '98, or might be compatible in Millenium Edition (ME). Windows XP, 7, 8, 10 are not supported. It needs 8MB of memory and 3MB of hard disk space . I could likely spin up an old windows Virtual Machine on my laptop.
I do not have an RS232 cable to connect between the offline programming computer and the RC3-V6A controller. The user manual shows the desired wiring, so it would be very easy to make one.
I do not have the floppy disk loader. This is a real bummer to be honest. This would let you save user programs and settings to floppy disks and reload them. Apparently these were not very popular and were not sold much in the US. As a result, the second hand market is barren. The cable and protocol are not described in the manual so without a working unit to reference, I'm not sure I could make a generic floppy disk drive work. Without this, my programming options are either to write the entire program on the teach pendant, or program them offline with the WINCAPS software. The robot controller has some internal memory for multiple programs, limited to:
Program Step memory limit: 8000 steps
Position data point memory limit: 1200 points (cartesian + joint angles)
The manual doesn't exactly tell you how many programs the controller can hold, but there are 7 inputs for program select, plus a parity check, so I would assume it can store at least 128 programs.

The RC3-V6A can connect to a printer over RS232 for the purposes of printing programs, variables, and positions. This uses the same port as the offline programming computer. Again, the cable specs are in the manual, so this would be easy to add. Would need to find a printer, or a virtual printer interface, that could support ASCII RS232 printing.
The RC3-V6A can connect to a uVision-15 robot vision system which includes a standalone control box, teach pendant, camera, and monitor. This is an entire separate system from the robot and I do not have the manuals. The robot manual makes a brief statement that the system can do position measurement, shape recognition, and part distinguishing. Pretty impressive for some late 90's tech. There is one control box on eBay for $99 and a teach pendant for $250, but no camera or monitor (all BNC coaxial). I don't really have any use for this, but would be interesting to play with if I already had the robot working


----------



## macardoso

Electricians are all done! Shop is back in business (sorta - lathe needs to be leveled and CNC needs assembly).  

Wrote a detailed checklist for starting up the robot. Don't want to rush and break it because I forgot something stupid. I'm mostly concerned about mis-wiring on things I've messed with.  Here is the checklist:

*DENSO VS-6354CM Robot Startup Checklist*

- Verify all connectors inside the robot are secure

J1
J2
J3
J4
J5
J6
- Finish ohming out the power connections to the motors, printed

J1
J2 (*DONE)*
J3 (*DONE)*
J4 (*DONE)*
J5
J6
- Verify the polarity of all (6) battery board connections, printed

J1
J2
J3
J4
J5
J6
- Solder the lithium primary batteries to the battery board and seal in plastic

- Solder the lithium primary battery for the controller to the connector, seal in plastic

- Verify I tightened the Denso servo drive module securely to the control box  (*DONE)*

- Put some sort of filter paper over the fan intake and exhaust  (*DONE)*

- Verify voltage on controller battery: _____*3.06*_____________VDC (3.0VDC Nominal) (*DONE)*

- Verify pinout of DIY teach pendant cable against sketches from eBay sellers. Verify no shorts between pins, printed (*DONE)*

- Electricians finish electric install (*DONE)*

Verify 120V at all outlets (*DONE)*
Verify 240V at all outlets (*DONE)*
Verify 120V to Neutral on both phases of 240V outlet (*DONE)*
Verify solid grounding at all outlets (*DONE)*
- Have electricians verify transformer wiring per manual (*DONE)*

- Disconnect transformer output from RC3-V6A. Energize transformer, verify supply voltage at 208V (*DONE)*

- Wire the input power cable. Triple check input voltage connections. (*DONE)*

- Disconnect power cable from RC3-V6A controller. Attach power cable to transformer. Energize transformer. Verify voltage between pins A & B ____*215*_______VAC (210 VAC +/- 10% permissible). Verify 0V on Pins C & D. Verify continuity between pin D and GND.  (*DONE)*

- Install ground conductor between robot and controller. 10 AWG minimum

- Wire STOP circuit to ESTOP box. (*DONE)*

- Pray to the good lord that the input MOVs don't blow up when I power it on and that I didn't screw anything else up.

- Assemble entire robot system and verify all connections secure

- Apply voltage to RC3-V6A per printed procedure. Power off immediately if the following are not met:

Verify the indicator lamp is illuminated
Verify the teach pendant screen displays “T-PENDANT Ready”
Verify the fans spin
- Execute the Encoder Battery Replacement Procedure, printed

- Execute the Controller Battery Replacement Procedure, printed

- Execute the Encoder Reset Procedure, printed

- Execute the CALSET Procedure, printed

- Verify the SETPRM Values (PLIM, NLIM, RANG) for all axes. RANG is not described in the manual, but should follow NLIM6 as you cycle through the list. These values are printed on the body of the robot. Verify the PLIM and NLIM values against the default table in the procedure, printed

- ONLY IF NECESSARY, complete the RC3 CLEAR DATA procedure, printed

- Perform the Set Date & Time Procedure, printed

- Address any error codes, if present. Error code manual printed


----------



## macardoso

Here's the electric install and a quick shop tour. The machines are in a sorry state right now. Each one deserves a few days to get set up and aligned. Each machine gets (1) 240V 4-wire 30A outlet and (4) 120V outlets. I have (4) machine stations along the wall, and (1) at the workbench.

Enco 110-2033 (12x36 lathe)



G0704 CNC mill



Seiko D-Tran TT-8800 SCARA robot (1999)



Overhead junction for power



Outlets on workbench wall. They didn't do the prettiest job here but it is OK. Maybe I'll do my own conduit at some point.



This will be where I do most of my testing of the Denso robot.


----------



## wachuko




----------



## macardoso

Well, this weekend was wildly successful with regards to the robot. Will likely require several posts to share everything so here we go.

I spent a chunk of Saturday afternoon working through the checklist I posted previously. A good chunk of the time was spent verifying the pinouts of all the cables and connectors against checklist in the robot service manual. I figured a few hours on this task would be well worth it versus burning out a motor thanks to some hacky wiring on my end.







Next up was to solder up the encoder backup battery board. This required some soldering of the lithium primary batteries and the 5V super capacitor. I didn't think much of this at first, other than knowing I needed to be careful of heat management during soldering. I soldered the capacitor first and then added the batteries one by one. I kept the soldering iron at max temp so I could melt the solder very quickly and move on. This is a trick I learned to minimize the total heat transfer into components. Better to be hot and fast than pretty hot and slow to melt. As I finished getting all the batteries on the board, I took a voltage measurement and only got 0.24VDC (should have been 3.68V). Exactly at that moment I also noticed the first couple batteries were getting hot! Something was shorting out and it made no sense to me at all! I ran outside with the battery in a panic waiting for it to burst into flames, then changed my mind and decided I wanted to try to save the $50 in batteries. So I ran downstairs and did a emergency desolder of the batteries. Thankfully everything cooled down.

I took two hours cleaning the board and investigating why it started to melt down. I still don't have a good answer to be honest, but maybe some excess solder got between the positive tab on the battery and the case (which is also the negative terminal). I eventually reassembled the board without changing anything and it was OK. The plastic wrapper on the batteries got pretty messed up from getting splashed with molten solder during my rushed desoldering job, so they were all individually wrapped in kapton tape, then once I confirmed the battery pack was working as expected, the whole pack got wrapped as well. Not pretty, but it is working. 




It spent two hours in a tool box to make sure it did not combust. I also triple checked the connections and polarity. Final voltage was 3.68VDC.




A careful check of the input power connections left me as confident as I could be in the installation. I am getting about 215VAC unloaded out of the transformer sled. I expect this will drop a bit once the robot is pulling some load on it. 

I sat on the phone with my dad as I went through literally every item I could think of going wrong with powering this on, and what I had done to ensure it would be OK. Finally said a little prayer and flipped the switch!

No boom! No smoke! The pilot light came to life, the fans kicked on, the teach pendant made two little chirps and displayed the most wonderful welcome screen, "T-PENDANT Ready".




I really had no idea whatsoever at this point if this would turn on at all. The fact that it just started up without a fuss was wonderful. I think it was last powered on in 2011, and had spent a fair bit of time in the cold, damp warehouse of HGR industrial surplus. 

To be continued...


----------



## macardoso

So at this point I was ecstatic. I knew if I could get this far, then there was a much better chance that things were in better shape than I had worried they might be in.  After power up, I was immediately greeted with some error codes. The teach pendant display is just a two line LCD display, so the information it provides is pretty minimal.

The first error I got was ERROR 771. The user manual had this explanation:







From my experience earlier working with the encoders on my bench, I know the encoder sets all status flags (including the overspeed flag) after the external backup battery source is disconnected. Since this robot had been without battery for the encoders all these years, this made sense to me. I jumped right into the encoder reset procedure in the manual.

Each motor, under the plastic covers, has a 2 pin red plastic connector coming off of the encoder connector. If a shorting jumper is installed in this location, 5V is applied to the encoder reset pin. Holding this condition after power on for 4 seconds clears all the errors and resets the multi-turn counter on the encoder. This was done one encoder at a time, starting with J1 and working my way up to J6. After each reset, the teach pendant would display a new error code, first ERROR 772, then 773, and finally 776.




This was completed without issue. I'm so grateful to Denso for providing the old manuals for this robot! I don't think I could have figured any of this out without them. Next was the CALSET procedure. This requires you to place the robot into a known configuration against the hard stops and run a procedure which the controller uses to learn the encoder positions at the ends of travel and relate them to the RANG calibration values which I'll explain in a minute.




The manual is pretty clear about the procedure, however whenever I got to step 5, I would get an ERROR 8 and the CALSET would terminate. It took me a minute to figure this out since ERROR 8 was an active ESTOP circuit, and I was able to verify all my circuits were closed and working properly.




Eventually I found the service manual has a chapter titled "Descriptions of Major Error Codes". In here, there was a mention to a function which is not clearly described in the user manual. Apparently the INPUT cable is not an optional component, and it has several signals which are needed to perform standard operations on the robot. Specifically in this case, the INPUT cable is part of the ESTOP circuit and needs a connection between pins 1 and 3. I had left these "optional" external interface cables disconnected during startup. I soldered the two tiny 28 AWG wires together and wrapped them in electrical tape. From there, I could complete the CALSET operation without any fuss.




I'll add at this point that the functions on the teach pendant are not very intuitive. Most keys have 2-3 functions which need to be selected using the shift key. The manual lacks a comprehensive description of all the functions on the teach pendant, so much of my knowledge of navigating the options has come from copying some example procedures from various parts of the manual and trying to modify what they are doing to my needs. In most cases, either nothing happens or it will throw an error code at me.

With CALSET done, I needed to go in and verify the 18 critical parameters for robot operation were loaded properly. These are PLIM (positive software joint angle limit), NLIM (negative software joint angle limit), and RANG (robot calibration data). Using a procedure from the manual, I was able to read all these values and set some of the PLIM and NLIM values back to default. These might be changed by an end user to make sure the robot can't run into an obstacle that is in its workspace (like a wall). The RANG values are unique numbers for each joint that are measured carefully at the factory when it was built. They represent the angle in degrees of the joint when it is pressed against the hard stop. The values are measured down to 3 or 4 decimal places. The robot combines these values, along with the encoder data saved during CALSET to perform the kinematic equations and locate the robot in 3D space. If these values (printed on a sticker on the robot itself) were to be lost, the robot would be nearly inoperable and could not properly perform any cartesian motion. Similarly, if the hardstops were to be moved, the same issue would occur. The RANG values in the controller matched those printed on the robot which confirms that this was the control box paired with this exact robot when it was running, and that it wasn't mistakenly swapped after it was discarded. That is a big issue with buying used robots.

After I got these done, the robot was clear of errors other than a RECPLACE BATT. message that would show up each time I turned the controller on. This is a preventative maintenance message that is based on the elapsed time since battery replacement (in my case, 9 years overdue), but is not an actual error message indicating low battery or depleted battery. When the connectors come for the controller battery, I will replace it.

Pressing the MOTOR ON button gave a resounding click of a contactor inside the controller pulling in, a relay in the controller clicking on, and the two brakes of the J2 and J3 motors releasing. The motors hummed to life with they typical whining of AC servo motors as the PWM voltage runs through the windings. I messed around with trying to move the motors but couldn't get anywhere. First thing I learned was that the deadman switch needed to be held to get it to do anything. Once I was holding that and pressed the jog button for J1, I was greeted with an ERROR 4 message. The manual explained that once per power on, the calibration operation needs to be run. This slightly bumps each motor forward and backward. This comes from a limitation in the Tamagawa encoders where full resolution is not available until the motor shaft has been moved 2 mechanical degrees after power on. Once each motor is moved slightly, the encoder resolution is increased x64.




At this point, I cleared the error, pressed [CAL] and [ENT] on the teach pendant. The motors hummed a little (the motion after the gearbox reduction is imperceptible) and the teach pendant displayed CAL OK. I tried moving the joint motors again and got no motion and no errors. From reading the manual earlier I remembered something about the robot starting up at 0% speed as a safety precaution. I found this section in the manual and entered [SP] and [100] on the teach pendant followed by [ENT]. The robot confirmed the speed was set to 10%. Any time the teach pendant is in MANUAL mode (rather than AUTO) the speed is multiplied by 10% for safety (and 5% if in TEACH CHECK) which in this case brought the speed down to 1% of maximum. From there I was able to hold the deadman switch and press J1+ and the joint started to move!

EDIT: Everything went well at this point up until jogging J4. It would only move in one direction and error on overtravel in the other no matter where is was positioned. Turns out that the CALSET procedure has some contradictory information between the image, text description, and CALSET procedure steps. I had done the CALSET against the wrong hard stop. Once corrected, the joints moved correctly.

To be continued!


----------



## macardoso

I quickly gained confidence and was jogging the robot at SP 100 (100% speed, times 10% during tech pendant operations). The robots software continuously monitors the position and will stop you with an ERROR whenever you exceed some limit (either joint angle, joint speed, or cartesian mathematical limit). This lets you move it around with reckless abandon (just kidding). But it is nice that you can't overtravel the robot and if you hit one of these limits, you just need to let go of the jog button, press [C] on the teach pendant to clear the error, and jog away in an unrestricted direction.

Here are the very first joint moves, running at 10% of maximum speed.






After gaining confidence with the joint moves, I placed the teach pendant in XY cartesian mode by pressing the [X-Y] button. This changes the jog buttons from moving each joint to moving the robot in XYZ space relative to the global world coordinate frame (X = forward and backward, Y = side to side, Z = up away from the table). Rotations about these "cardinal" axes are also permissible. 

Thanks to singularities, the robot cannot be jogged quite as easily in this mode. The joints cannot flip (e.g. wrist down to wrist up) like they can in joint mode, and motion near singularities results in errors as the robot pre-calculates that a joint will need to rotate extremely fast. This is nice that the robot is able to halt motion before the motor takes off. It seems hard to command the robot to do anything wrong, short of running it into an obstacle.

Here is a video of cartesian moves at 10% speed in a "normal" arm-forward, wrist-down configuration.






Rotations in cartesian mode are wicked cool. The position of the tool (in this case, the center point of the face of the tool body platter) is held fixed in 3D space, while the platter is rotated about the cardinal axes. Same configuration at 10% speed.






Finally, I placed the robot in tool frame cartesian mode. This is similar to normal cartesian mode except all the motions are relative to the moving coordinate frame attached to the tool. In X-Y cartesian mode, jogging in the Z- direction moves the tool down towards the table, in TOOL cartesian mode, jogging in Z- direction moves the tool forward along whatever vector it is currently pointing. This would make programming a gripper much easier, especially if what it needed to grab was not aligned with the global cartesian coordinate frame. 

This video was aimed at aligning the robot with the camera in the Z axis and performing translations and rotations in the TOOL frame cartesian space. Same configuration as above at 10% speed.


----------



## macardoso

As an aside the robot's motion in some places is not as smooth as I would have hoped. The motion gets slightly jerky with an amplitude of maybe 1/16". I have a feeling this is an issue with the J2 gearbox. This was the one which I could not remove during cleaning and was absolutely filthy with grit and grime. I flushed it with oil, but I think it is time I go back and try harder to pull the flex spline cup and give it a good cleaning and greasing. I can hear some grinding and crunching sounds as the robot moves and these seem correlated with the jerky motion.

Probably related, I was able to use the teach pendant to pull the diagnostics out of the robot. The current run time (with motors on) is 27268 hours. This is roughly 13 years of 40 hour work weeks! She is an old girl! 

Hoping a good cleaning and greasing is all that is needed to get it running better. I'm sure the entire robot has a whole lot more slop than a new unit as the gearboxes wear, but it will be perfect for messing around with at home.


----------



## macardoso

I could sit around and play with this thing in jog mode all day, but I started looking into writing programs. Again, I feel like a grandpa trying to navigate an iPhone, but I'm slowly picking up on how to get through the menus.

The robot needs to be in [MANUAL] mode to work with programs. Clicking [PRO] with allow you to enter the program number (e.g. [1]) and hitting [ENT] will open the program and display the title "PROGRAM 1". Clicking the [FWD] and [BACK] keys will scroll through the program steps.

Using the diagnostics functions on the teach pendant, I was able to see that the previous owner's programs were still loaded and were using 278/8000 program steps (also used by general purpose integer and floating point variables) and 562/1200 points (positions saved in joint/cartesian space).

Here is the full program 1 saved in the controller from the previous owner. No idea what it does yet.



		C++:
	

PROGRAM 1
0010 SUB1
0020 ACP A002
=  $      GO1
0030 SUB1
0040 MVS P,P0001
0050 LABL 1
0060 ISP 60
0070 ACC 20
0080 JI 3-2
0090 JMP 3
0100 LABL 2
0110 APR E
APR=80.0
0120 MVS E,P0021
0130 MVS E,P0022
0140 ISP 4
0150 E_MUL
0160 MVR P0001
     P0023,P0024
0170 ARV 5
0180 ON 1
0190 E_MULEND
0200 ISP 10
0210 MVR P
     P0025,P0026
0220 MVR P
     P0027,P0028
0230 ISP 3
0240 MVR P
     P0029,P0030
0250 ISP 10
0260 MVR P
     P0031,P0032
0270 MR E
     P0033,P0034
0280 OFF 1
0290 ISP 60
0300 DEP E
DEP=80.0
0310 SUB 1
0320 SUB 2
0330 JMP 5
0340 LABL 3
0350 JI 4-4
0360 JMP 5
0370 LABL 4
0380 ISP 60
0390 APR E
APR=80.0
0400 MVS E, P0041
0410 MVS E, P0042
0420 ISP 4
0430 E_MUL
0440 MVR P
     P0043,P0044
0450 ARV 5
0460 ON 1
0470 E_MULEND
0480 ISP 10
0490 MVR P
     P0045,P0046
0500 MVR P
     P0047,P0048
0510 ISP 3
0520 MVR P
     P0049,P0050
0530 ISP 10
0540 MVR P
     P0051,P0052
0550 MVR E
     P0053,P0054
0560 OFF 1
0570 ISP 60
0580 DEP E
DEP=80.0
0590 SUB 1
0600 SUB 3
0610 LABL 5
0620 ISP 60
0630 ACC 20
0640 END


EDIT: Added comments to each line using the comment character "//" (not supported within robot). Added description of each function from the programming manual.



		C++:
	

PROGRAM 1
0010 SUB1    //SUBROUTINE 1 CALL
0020 ACP A002    //9.5X NEW FEATURE, AREA COMPARE
=  $      GO1    //COMPARE CURRENT POSITION ($) TO THE AREA VARIABLE A002. IF WITHIN (=) GO TO LABEL 1
0030 SUB1    //SUBROUTINE 1 CALL
0040 MVS P,P0001
0050 LABL 1    //JUMP DESTINATION LABEL 1
0060 ISP 60    //SET SPEED 60%
0070 ACC 20    //SET ACCELERATION 20%
0080 JI 3-2    //JUMP TO LABEL 3 WHEN INPUT 2 IS ON
0090 JMP 3    //JUMP TO LABEL 3
0100 LABL 2    //JUMP DESTINATION LABEL 2
0110 APR E    //APPROACH WITH EXACT STOP, 80 MM
APR=80.0
0120 MVS E,P0021    //LINEAR CP MOVE WITH EXACT STOP, POSITION 0021
0130 MVS E,P0022    //LINEAR CP MOVE WITH EXACT STOP, POSITION 0021
0140 ISP 4    //SET SPEED 4%
0150 E_MUL    //EASY MULTI-TASK (EM MODE) DECLARATION, USED FOR ARV COMMAND
0160 MVR P    //ARC INTERPOLATION CP MOVE, CONSTANT VELOCITY PASS MOVEMENT
     P0023,P0024
0170 ARV 5    //9.5X NEW FEATURE, WAIT FOR PREVIOUS MOTION COMMAND TO REACH 5% COMPLETE BEFORE EXECUTING NEXT COMMAND
0180 ON 1    //OUTPUT 1 ON, TURNS ON @ 5% OF PREVIOUS MVR COMMAND COMPLETION
0190 E_MULEND    //EASY MULTI-TASK (EM MODE) END DECLARATION
0200 ISP 10
0210 MVR P    //ARC INTERPOLATION CP MOVE, CONSTANT VELOCITY PASS MOVEMENT
     P0025,P0026
0220 MVR P    //ARC INTERPOLATION CP MOVE, CONSTANT VELOCITY PASS MOVEMENT
     P0027,P0028
0230 ISP 3
0240 MVR P    //ARC INTERPOLATION CP MOVE, CONSTANT VELOCITY PASS MOVEMENT
     P0029,P0030
0250 ISP 10    //SET SPEED 10%
0260 MVR P    //ARC INTERPOLATION CP MOVE, CONSTANT VELOCITY PASS MOVEMENT
     P0031,P0032
0270 MVR E    //ARC INTERPOLATION CP MOVE, EXACT STOP
     P0033,P0034
0280 OFF 1    //OUTPUT 1 OFF
0290 ISP 60    //SET SPEED 60%
0300 DEP E    //DEPART WITH EXACT STOP, 80 MM
DEP=80.0
0310 SUB 1    //SUBROUTINE 1 CALL
0320 SUB 2    //SUBROUTINE 2 CALL
0330 JMP 5    //JUMP TO LABEL 5
0340 LABL 3    //JUMP DESTINATION LABEL 3
0350 JI 4-4    //JUMP TO LABEL 3 WHEN INPUT 4 IS ON
0360 JMP 5    //JUMP TO LABEL 5
0370 LABL 4    //JUMP DESTINATION LABEL 4
0380 ISP 60    //SET SPEED 60%
0390 APR E    //APPROACH WITH EXACT STOP, 80 MM
APR=80.0
0400 MVS E, P0041    //LINEAR CP MOVE WITH EXACT STOP, POSITION 0041
0410 MVS E, P0042    //LINEAR CP MOVE WITH EXACT STOP, POSITION 0042
0420 ISP 4    //SET SPEED 4%
0430 E_MUL    //EASY MULTI-TASK (EM MODE) DECLARATION, USED FOR ARV COMMAND
0440 MVR P    //ARC INTERPOLATION CP MOVE, CONSTANT VELOCITY PASS MOVEMENT
     P0043,P0044
0450 ARV 5    //9.5X NEW FEATURE, WAIT FOR PREVIOUS MOTION COMMAND TO REACH 5% COMPLETE BEFORE EXECUTING NEXT COMMAND
0460 ON 1    //OUTPUT 1 ON, TURNS ON @ 5% OF PREVIOUS MVR COMMAND COMPLETION
0470 E_MULEND    //EASY MULTI-TASK (EM MODE) END DECLARATION
0480 ISP 10
0490 MVR P    //ARC INTERPOLATION CP MOVE, CONSTANT VELOCITY PASS MOVEMENT
     P0045,P0046
0500 MVR P    //ARC INTERPOLATION CP MOVE, CONSTANT VELOCITY PASS MOVEMENT
     P0047,P0048
0510 ISP 3    //SET SPEED 3%
0520 MVR P    //ARC INTERPOLATION CP MOVE, CONSTANT VELOCITY PASS MOVEMENT
     P0049,P0050
0530 ISP 10    //SET SPEED 10%
0540 MVR P    //ARC INTERPOLATION CP MOVE, CONSTANT VELOCITY PASS MOVEMENT
     P0051,P0052
0550 MVR E     //ARC INTERPOLATION CP MOVE, EXACT STOP
     P0053,P0054
0560 OFF 1    //OUTPUT 1 OFF  
0570 ISP 60    //SET SPEED 60%
0580 DEP E    //DEPART WITH EXACT STOP, 80 MM
DEP=80.0
0590 SUB 1    //SUBROUTINE 1 CALL
0600 SUB 3    //SUBROUTINE 3 CALL
0610 LABL 5    //JUMP DESTINATION LABEL 5
0620 ISP 60    //SET SPEED 60%
0630 ACC 20    //SET ACCELERATION 20%
0640 END    //END OF PROGRAM


----------



## wachuko

Oh man!  This thing will be making sculptures in no time!!

Congratulations in the process so far!!!


----------



## brino

Fantastic progress Mike!

Congratulations.

Brian


----------



## rabler

Amazing perseverance and aptitude in getting this far!  Very few people would tackle something like this.


----------



## macardoso

Wrote a basic positioning program and was able to verify using Teach Check. Quickly wired up a switch for AUTO ENABLE on input pin 2. This is needed to switch the robot from MANUAL or TEACH CHECK to AUTO. No pictures because the wiring is ugly and I was excited to see this thing run!

AUTO runs the program as written at full speed.

Here is my simple program at 50% speed.






And here at full speed. Maybe not quite as fast as some of the most modern robots at trade shows, but it is scary fast when you are watching it in person!


----------



## macardoso

Wrote a quick program last night to send to the guy at Denso who helped me out so much.


----------



## macardoso

Got a pile of pneumatic fittings on order from AutomationDirect. That should let me connect my compressor to the robot and actuate the internal solenoid valves and the gripper I bought. The robot has all metric push to connect ports so I needed to get matching fittings. I also picked up speed control valves for the gripper so it has a soft close function. 




I'll need some sort of junction box for all the IO wiring that is needed. A 1U server rack sized box would be perfect, but those are $250 new. I intend to rack mount the controller under my workbench.




The J2 harmonic drive gearbox is still not sounding wonderful. I need to open it up again and remove the whole gearbox for cleaning. Looking at pictures online, I think I see how I can remove the whole thing. I would prefer to clean in place, but I'll do whatever I need to I guess. There is one for sale on eBay Korea, but it is $500 used, ouch.




I am likely going to start writing programs to test out all the different instructions. Once the pneumatics are set up and I can machine an adapter for the gripper, I'd like to see it assemble some Legos or another moderately complex task like that.


----------



## wachuko

macardoso said:


> Wrote a quick program last night to send to the guy at Denso who helped me out so much.



It is very cool that you did that.  I work in a Support environment and it is refreshing to get something like this.  When you are always working on resolving problems or dealing with customer's escalations, a positive note on a job well done, or appreciation of the help provide, goes a long way.


----------



## Cadillac STS

It is so awesome you are taking the time to post detailed updates on this!


----------



## macardoso

I took a little time yesterday to clean up my workspace and moved the control box under the workbench. I am now doing a poor installation by running the robot power and encoder cables in parallel, as well as bringing the encoder cable past the transformer. I noticed a significant increase in audible noise coming from the robot as well as a number of errors during the power on calibration. I can eventually get it to calibrate, but not usually on the first try anymore. This tells me the robot is susceptible to radiated noise and the motor cable and encoder cable shields aren't giving sufficient coverage. I have a few tricks I was to do, but at the end of the day, I'll need to be smart about the cable routing.

I also decided to dive back into the J2 gearbox. This time I was determined to get it apart for cleaning. I got the motor removed and was immediately shocked by how brown my new white grease was. Most got scooped out to access the bolts on the flexspline. I tried pulling it by hand again, but got nowhere. Then I put the motor/wave generator back on hoping that the wave generator would pull the flexspline out with it. This did not work either.

Looking at the assembly, I could see that this harmonic drive was a type that had an integral crossed roller bearing. Thus this was completely supporting the upper arm. Unlike the other gearboxes, this did not have threaded ejector holes to install screws into to push out the flexspline. This is why I struggled with it the first time.

I gave it some careful thought and made a bold choice to remove the 8 bolts holding the upper arm to the gearbox. This would give me access to the backside of the gearbox, and hopefully a way to remove the flexspline. I prepared a place to rest the arm once it was removed and took off the last remaining bolts. I used the same 8 bolts that held the arm on to thread deeper through their mounting holes and push the flexspline from the backside. Gently tightening the bolts pushed the cup straight out. There are 6 dowel pins that align the cup that required some care in how it was removed. These also contributed to the difficulty in removal earlier. After feeling how much pressure was needed on the bolts, there is no way I ever would have pulled this by hand. 

The upper arm was less heavy than expected and was easy to place next to the base.







The arm itself has a small centering boss and 8 through holes to mount it.




I was never able to clean back here and found the gearbox filled with mud brown/black old grease which was definitely gritty - not good.




I think this shot is pretty cool. The silvery and black outer ring is the aluminum casting of the robot. Then the entire steel chunk in the middle is the harmonic drive gearbox with integral output bearing. If you look at the center bore, you can see how thick that output flange is. Along the perimeter is a crossed roller bearing. Crossed roller bearings are designed for slow speeds, high loads, and extreme stiffness and accuracy. They are very expensive and reserved for high end motion control applications. There is a lot of drag from spinning this bearing alone. You can tell it is highly preloaded.




Here is a sample catalog image of this kind of bearing. The outer race is usually split and preload is achieved by squeezing the outer races together with bolts.




I removed all the old grease and scrubbed down all the teeth of the ring gear and flex spline with a toothbrush and various cleaning solutions. The flexspline also got a vigorous bath in WD40 and 99% isopropyl alcohol to get all the grit and old grease removed. I could see a substantial amount of wear on the flexspline teeth. It didn't show up on camera well, but the crests of the teeth were polished to a silvery sheen where all the other gearboxes appeared extremely matte.

Everything was regreased and prepared to be reassembled. I'll do that tonight. Can't afford to replace this gearbox, so I'm hoping that this cleaning will get it running smoother and give it some additional life.




The backside of the gearbox will get packed fully with grease before I put the flexspline back in.


----------



## macardoso

I should add that the post above was very risky in terms of messing up the robot calibration. The robot has very carefully measured angles from the factory that allow it to make accurate motion in cartesian space (straight lines, arcs, etc.). If I were to move a hardstop for example, the robot would never move correctly again.

These calibration values can be overwritten, but I do not have the inspection tools or knowledge to measure the joint angles at hardstop down to the ten thousandth of a degree as they have been done at the factory.

I felt this risk was justified due to the poor condition of the gearbox. I could actually hear it grinding as it moved. The motion of the end of the arm was also jerky whenever J2 had a contribution to the motion. I hope I have given the gearbox a good chance to enjoy its golden years.

In terms of reassembly, I did not adjust the hardstops so those should be OK. The gearbox has a tight fit to the robot base casting which should self center very accurately. The arm has a tight fit to that centering boss on the output flange which should also self center accurately. The angle of the arm to the gearbox flange does not matter as it will be accounted for in the new CALSET against the hardstop. The motor was disconnected from the battery, so an encoder reset procedure needs to be completed on J2 and a single axis CALSET done on the joint as well. Fingers crossed I did not mess anything up and this will have been a positive experience.


----------



## brino

Two comments:

1) Thanks for showing that cut-away view of the "crossed roller bearing"!
I had not heard the term or seen one before.... and any day I can learn something new it's a good day.

2) about the "bold choice" and "risky" operation......
It is very clear that this project is in very capable hands!
Your deep understanding and methodical approach is not only impressive, but it's made this thread thought provoking and enjoyable to read.
Keep up the great work!

Much respect!
Brian


----------



## macardoso

Gearbox is greased and back together. Took me two attempts since I forgot a plastic cover that has to be installed before the arm is bolted back on.

When I was figuring out how to remove the flex spline cup, I had loosened the 8 bolts holding the harmonic drive to the robot's casting. At this point I was not yet aware that the output bearing was integral to the harmonic drive (it is not in J3-5). The whole arm started to lean sideways as I loosened the last bolt. I did tighten everything back down, but I thought it might be prudent to double check that I did not marr the mounting surfaces of the casting.




This image is kinda cool. I think there might be (2) crossed roller bearings. There is an obvious split line down the middle of the text, but also two harder to see split lines above and below the text, making (4) total rings stacked. I think the hard to see split lines are the two halves of each crossed roller bearing compressed to generate preload. The excessive number of bolts along the perimeter are used to compress these rings.




Here is the housing where the harmonic drive mounts.




And the arm back together with the side cover removed.




I performed the encoder reset procedure and the single axis CALSET procedure. I was very happy to see the robot completing the programs I had already entered with near perfect precision to before. At most, there was a half mm deviation at the end of the arm which I think is to be expected. Robots in general are not meant to be particularly accurate in terms of positioning in the global absolute space, but they are exceptionally repeatable in moving to taught positions.

I wrote a simple 4 line program to cycle the J2 joint from end limit to end limit and let that cycle for several hours at 10% speed. The gearbox was initially very noisy but that settled down as the grease worked itself in. I may have overfilled the gearbox with grease a bit, but I left the bleed port open and it spat out a bit of excess. After 3 hours or so, I checked on it and the gearbox was nice and quiet, no grinding sounds.

The motion remains a bit jerky when J2 is contributing significantly to the motion, and I have a feeling that this is a function of the wear on the gearbox. A small amount of compliance in the gearbox amplifies both servo motor vibrations and bubbles/grease between teeth of the gearbox. View this 24" from the joint when the arm is fully outstretched and small arc-second/arc-minute sized vibrations become significant movements. This does not affect positioning accuracy and is not noticeable at anything above 25%. At the end of the day, this is a $40k machine that I picked up for $400 and it is only for hobby use, so whatever. I bet a gearbox swap would fix it if it really starts bothering me.

As I was messing around with the robot in manual jog mode late last night I kept hearing clicking from the J2 motor followed by erratic jerking of the joint and really nasty sounds. Didn't take me long to figure out that the J2 motor electromechanical brake was closing while the motor was running. I need to troubleshoot this, but I have a feeling it is from the 2 pin connector on the motor that I accidentally broke the retaining clip on. I have the connector taped shut, but I bet the contacts are making poor connection with all the mating cycles they just got. I have spare crimp contacts so I should pick up some connector bodies and replace the whole setup. I'm fairly confident the controller is still working OK since the J2 and J3 motors share the same circuit from the controller and the same conductor in the motor power cable, and J3 is working fine. 

My order of connectors for the controller battery came in today from eBay. I had to buy a full lot since these are discontinued and no major electronics company (Digikey, Mouser, Newark, etc.) carries them. The crimp contacts are coming from Mouser in the $3 shipping option. They might show up next year. Amusingly, if I stick to replacing the battery every two years and I never reuse the connectors, I'll have enough to last me until 2084. If I'm still alive   (now that's a depressing thought!).


----------



## macardoso

Drew up a quick mount for the gripper in CAD. I have a chunk of 41L40 that will be perfect for this. Unfortunately the lathe is not aligned and the CNC is not assembled. This will give me a kick to get those in order.


----------



## macardoso

macardoso said:


> Drew up a quick mount for the gripper in CAD.


Well this was a dumb design... Whenever you do something "quick" in CAD, it is usually a mess. I thought I was accounting for the dimensions of the gripper which would leave enough room to get an allen wrench on the mounting bolts to attach the platter to the robot, but the gripper corners are facing the bolt holes and as such, I cannot access them with the wrench.

I already did all the lathe work on this last night, so I'll have to see if I can salvage the design to be close to how it is now


----------



## macardoso

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.







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




Here are the crimped pins loaded into the connector.




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




Swap completed!




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.


----------



## macardoso

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.




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.







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.


----------



## rabler

Ha, seeing the Intel i960 on that board brings back memories.


----------



## macardoso

rabler said:


> 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?


----------



## rabler

macardoso said:


> 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.


----------



## macardoso

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.




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. 




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. 




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










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.




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




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.


----------



## macardoso

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.




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.




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:









						Euler angles - Wikipedia
					






					en.wikipedia.org
				












						Other Explicit Representation for the Orientation in Robotics: Roll-Pitch-Yaw Angles
					

In this lesson, we will talk about another explicit way to represent the orientation in robotics that we call Roll-Pitch-Yaw Angles.




					www.mecharithm.com
				






			http://eecs.qmul.ac.uk/~gslabaugh/publications/euler.pdf
		


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).




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).




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.




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.


----------



## macardoso

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.


----------



## mattthemuppet2

that is super awesome, what an adventure! My hat's off to you


----------



## macardoso

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.


----------



## rabler

macardoso said:


> 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.


What is it using for programming memory?  I remember one prof I worked with hacking his TRS-80, adding wires and piggyback SRAM chips, to greatly increase the program memory.  By that time the TRS-80 was already an antiquated beast, but it was his form of amusement.


----------



## macardoso

To make the most of the limited program sizes in the robot controller it is advantageous to use subroutines when possible. In short, subroutines are blocks of code that can be executed by a single line of code (e.g. SUB 31). Subroutines can have as much code as needed and can call other subroutines (known as nesting) up to 16 layers deep.

Subroutines can be very simple such as the following example to open a gripper:



		Code:
	

SUBROUTINE 32
0010 VON 6
0020 VOFF 5
0030 TIM 50
0040 END


Or they can be as complicated as needed. There are no parameters that can be passed into the subroutine from the subroutine call, but the subroutine can read and write global variables just like the main program. For example the main program might write the value 10.0 to Floating Point variable 1



		Code:
	

0010 S F0001=10.0


and the subroutine might copy that to Floating Point variable 2



		Code:
	

SUBROUTINE 33
0010 S F0002=F0001
0020 END


The power of this global variable access comes when you get into *indirect addressing*. Indirect addressing allows you to access the data in a variable based on the value of a different variable. In the simple example below, The value from Floating Point variable 2 is copied into Floating Point variable 1, and then later Floating Point variable 3 is copied into Floating Point variable 1, but they use the same subroutine



		Code:
	

PROGRAM 1
0010 S I0001=2
0020 SUB 1
0030 S I0001=3
0040 SUB 1
0050 END

SUBROUTINE 1
0010 S F0001=I0001.F
0020 END


In the example above, the integer variable "I0001" contains the value of index of the floating point array to be copied. In a traditional programming sense, I0001 is a pointer to the F000x variable.

Initially I0001 is set equal to 2. When the subroutine call is executed, the indirect reference "I0001.F" is resolved to "F0002" (floating point variable with the index equal to the value of I0001). Later in the program, the main routine redefines I0001=3, so the next execution of the subroutine, the indirect reference "I0001.F" is resolved to "F0003".

Based on these principles, I rewrote the previous program into a subroutine based program:



		Code:
	

PROGRAM 31
0010 S I0028=50  //Rapid Speed
0020 S I0029=20  //Reduced Speed
0030 TOOL 5  //Setup tool offset
0040 SUB 32
0050 ISP I0028  //Set speed
0060 MV E,J0100  //PTP move to safe location in the air
---------------------------------------------------First Place----------------
0070 S I0030=102
0080 S I0032=104
0090 SUB 30
---------------------------------------------------Second Place----------------
0100 S I0030=106
0110 S I0032=108
0120 SUB 30
---------------------------------------------------Third Place----------------
0130 S I0030=110
0140 S I0032=112
0150 SUB 30
---------------------------------------------------First Return----------------
0160 S I0030=104
0170 S I0032=102
0180 SUB 30
---------------------------------------------------Second Return----------------
0190 S I0030=108
0200 S I0032=106
0210 SUB 30
---------------------------------------------------Third Return----------------
0220 S I0030=112
0230 S I0032=110
0240 SUB 30
---------------------------------------------------End of Program----------------
0250 MV E,J0100 //PTP move to safe location in the air
0260 END  //END of program


----------------------Pick & Place w/ Approach Points Subroutine--------------------------
//This subroutine completes a full pick and place action
//Approach positions are used for each pick and place location
//Robot moves to approach points at full speed defined by FLOAT 30
//Robot moves from approach points to pick/drop points at reduced speed defined by FLOAT 31
//Robot moves to pick point defined by INTEGER 30. Pick approach point must be stored in the position variable immediately preceding the pick point (e.g. P0101 = pick approach position, P0102 = pick position)
//INTEGER 31 is used for intermediate calculation of pick approach position
//Robot moves to drop point defined by INTEGER 32. Drop approach point must be stored in the position variable immediately preceding the drop point (e.g. P0103 = drop approach position, P0104 = drop position)
//INTEGER 33 is used for intermediate calculation of pick approach position

SUBROUTINE 30

0010 ISP I0028  //Set full speed from global rapid speed variable
0020 S P0100=I0030.P  //Copy the pick point from the Position variable registers "P" at index defined by the value of I0030 to the working pick position P0100
0030 S I0031=I0030-1  //Subtract 1 from the pick position pointer
0040 S P0099=I0031.P  //Copy the pick approach point from the Position variable registers "P" at index defined by the value of I0031 to the working pick approach position P0099
0050 MVS E,P0099  //Move linear to pick approach point
0060 ISP I0029  //Set full speed from global reduced speed variable
0070 MVS E,P0100  //Move linear to pick point
0080 SUB 31  //Call Close Gripper subroutine
0090 MVS E,P0099  //Move linear to pick approach point
0100 ISP I0028  //Set full speed from global rapid speed variable
0110 S P0100=I0032.P  //Copy the pick point from the Position variable registers "P" at index defined by the value of I0030 to the working pick position P0100
0120 S I0033=I0032-1  //Subtract 1 from the pick position pointer
0130 S P0099=I0033.P  //Copy the pick approach point from the Position variable registers "P" at index defined by the value of I0031 to the working pick approach position P0099
0140 MVS E,P0099  //Move linear to pick approach point
0150 ISP I0029  //Set full speed from global reduced speed variable
0160 MVS E,P0100  //Move linear to pick point
0170 SUB 32  //Call Open Gripper subroutine
0180 MVS E,P0099  //Move linear to pick approach point
0190 ISP I0028  //Set full speed from global rapid speed variable
0200 END


----------------------Close Gripper Subroutine--------------------------
//This subroutine completes a gripper close action

SUBROUTINE 31

0010 VON 5
0020 VOFF 6
0030 TIM 50
0040 END


----------------------Open Gripper Subroutine--------------------------
//This subroutine completes a gripper close action

SUBROUTINE 32

0010 VON 6
0020 VOFF 5
0030 TIM 50
0040 END


----------------------Variable definitions--------------------------

I0028 = Rapid Speed (default 50)
I0029 = Reduced Speed (default 20)

I0030 = Pick Point Pointer
I0031 = Internal Calculation (Pick Approach Pointer)
I0032 = Drop Point Pointer
I0033 = Internal Calculation (Drop Approach Pointer)

J0100 = Safe clearance position
P0099 = Internal Calculation (Pick/Drop Approach Position)
P0100 = Internal Calculation (Pick/Drop Position)
P0101 = Approach point to pick location 1
P0102 = Pick location 1
P0103 = Approach point to drop location 1
P0104 = Drop location 1
P0105 = Approach point to pick location 2
P0106 = Pick location 2
P0107 = Approach point to drop location 2
P0108 = Drop location 2
P0109 = Approach point to pick location 3
P0110 = Pick location 3
P0111 = Approach point to drop location 3
P0112 = Drop location 3


This reduced the total number of lines of code from 127 to 58 and each addition pick/place of a brick only adds 3 lines of code rather than 20.

A couple limitations of this is that you cannot complete indirect references or math outside of a "SETI" command line (lines starting with "S"). This means that the following line of code is invalid since you cannot resolve "I0030.P" to P.xxxx in the same line of code that you are trying to execute a move from. 



		Code:
	

0010 MVS E,I0030.P


You are also not allowed to complete more than one math operation per "SETI" command line, so the following is invalid since you are trying to add 3 values together:



		Code:
	

0010 S I0001=I0002+I0003+2


This would be valid if written as:



		Code:
	

0010 S I0001=I0002+I0003
0020 S I0001=I0001+2


----------



## macardoso

rabler said:


> What is it using for programming memory?  I remember one prof I worked with hacking his TRS-80, adding wires and piggyback SRAM chips, to greatly increase the program memory.  By that time the TRS-80 was already an antiquated beast, but it was his form of amusement.


Not real sure to be honest. I can try to study the mother board. The control does mention the option to mount optional memory to increase the total available storage by ~20%.


----------



## Boswell

Looks great.  I wonder if there is a way to dynamically load/replace some of the program memory. for instance if a subroutine could load a new block of code. Essentially a simple paging system. A long shot, I realize.


----------



## macardoso

Boswell said:


> Looks great.  I wonder if there is a way to dynamically load/replace some of the program memory. for instance if a subroutine could load a new block of code. Essentially a simple paging system. A long shot, I realize.



Nothing can call another main program, but your main program could pretty much only call subroutines (which could be written to look like their own main programs). Probably not exactly what you were suggesting.


----------



## Boswell

macardoso said:


> Probably not exactly what you were suggesting


agreed. It would only be valuable if it can load from near-line / off-line memory as a way to increase the program & variable space.


----------



## rabler

macardoso said:


> Not real sure to be honest. I can try to study the mother board. The control does mention the option to mount optional memory to increase the total available storage by ~20%.


Not really an issue until you get around to writing really complex code.  Just a random thought.


----------



## macardoso

Morning all, I've been away from this site for quite a while as life has gotten quite busy in the last year (new house, new job, and baby on the way!), but I figured I'd give a quick sneak peek of a project I've been working on for about a month now...

This little setup will become our Halloween display this year! Robot will hand out candy by dropping baggies down a chute when a candy order button is pressed.




The robot control is wired into this big enclosure which is 99% empty but I grabbed it before we threw it away at work. It has a 24V PSU, safety relay, and a couple terminal blocks inside. The display will be protected by a laser area scanner (safety rated) to prevent kids from running up to the running robot (plus multiple ESTOP buttons).




Have quite a bit of work to go, but I'm getting there. mostly programming, teaching positions, building the chute supports, and decorating it. 7 days left...


----------



## wachuko

Congratulations on life!!  All great news!!!


And that Halloween project, sweet!   Be sure to get a video of it working with the kids!  So cool!


----------



## DavidR8

Congrats on the incoming babino!


----------



## brino

I want to trick-or-treat at your house!

Brian


----------

