JoergS5 parallel five bar scara

  • I'm tinkering with a parallel scara and need a firmware.

    JoergS5 has a wonderful implementation at, documentation at

    Has anyone kept this up to date with newer RRF?

    It looks like an easy to task to get it done.

  • @bondus Hello, I will update it. Give me a bit time.

    My current plan is to implement multiple scara.

    Do you have improvement ideas to the current functionality?

  • Mr Joerg himself 🙂

    Updating looked easy, little has changed. Just one new parameters to a few methods. We will see if it works once I hook up the machine.

    Homing is a bit of a challenge.
    My proximal arms can swing over 180deg, but they can not go the backmost position at the same time, the distal arms will hit the center.
    I guess if I rotate the arm the same direction and have the homing sensors at asymmetrical points it should work. Just like your example for work mode 1. Mine is built to be in work mode 2.

    The machine is far from being a complete printer. I have to verify that 5 bar works fine first. It looks very good so far, light and stiff.
    0_1557428078028_v2 top - Copy.jpg

  • @bondus It's nice to have a companion and thank you for your image!

  • I got it compiling.

    But it restarts the board after I run the M669 command.
    I can see it executes the code it is supposed to, I sprinkled the code with debugPrintf().

    Unfortunately I don't know where it crashes. It seems to flush the UART buffer when it restarts and I get different outputs each time I run it. I'm lost 😞

    I used the same setup for another custom kinematics before, it worked like a charm.

  • Found the problem,

    FiveBarScaraKinematics::getInverse() calls FiveBarScaraKinematics::constraintsOk() which calls FiveBarScaraKinematics::getInverse(), etc, infinite recursion and stack overflow.

    The recursion would not be infinite if the coordinates to getInverse() are valid, the caching mechanism would break it.

    One step closer...

  • I got it moving ! Somewhat.

    There were some issues with the code:

    • The infinite recursion between getInverse() and constraintsOk(). It could be sorted by removing the call to constraintsOk() inside getInverse() and add an explicit call to constraintsOk() in CartesianToMotorSteps().

    • The parsing of the configuration option 'A' was wrong, the call to TryGetFloatArray stated 4 parameters, should be 6.

    • The parsing of the configuration option 'D' did not work properly. The call to getNumParameters() returned a very strange value (11) that should have been 2.

    I replaced it with :

    	bool dseen = false;
    	float distalLengths[4];
    	if(!gb.TryGetFloatArray('D', 4, distalLengths, reply, dseen) && dseen) {
    		distalL = distalLengths[0];
    		distalR = distalLengths[1];
    		cantL = distalLengths[2];
    		cantR = distalLengths[3];
    		seen = true;
    	} else {
    		dseen = false;
    		if(!gb.TryGetFloatArray('D', 2, distalLengths, reply, dseen) && dseen) {
    			distalL = distalLengths[0];
    			distalR = distalLengths[1];
    			cantL = 0.0;
    			cantR = 0.0;
    			seen = true;

    • In getForward()
      if(inter12[0] < inter12[3]) {
      should be
      if(inter12[1] < inter12[3]) {
      to match the comment on the line above

    The getInverse() transform is a bit weird, it works in some areas and then suddenly wants to point the arms in totally different directions. The steppers luckily protests such moves with a loud squeak. I'll lift out the transformation code to a separate test program to make testing easier.

    Almost there...

  • @bondus If you give me the code when tested, I can login into github (or I give you access rights, but then I need your account name). Sorry if I made errors in the program.

  • @joergs5 said in JoergS5 parallel five bar scara:

    @bondus If you give me the code when tested, I can login into github (or I give you access rights, but then I need your account name). Sorry if I made errors in the program.

    I bet it worked for you. Your plans are quite ambitious wanting to handle all working modes.

    I tracked down the odd selection of arm-angles to getTheta(). I think the logic in there is a bit too simple to handle all cases of work modes, locations of actuators and limitation of angles. It would takes some brain-time with pen and paper to figure out a good logic for that. I made it work for my be changing the range of getAbsoluteAngle() from 0 - 360 to -90 - 270.

    It's fascinating to see the arms air-printing at 240mm/s, with just 600mA to the steppers. Too bad I have no z-axis yet.

  • @bondus One paper which was useful to understand the work modes was called "DEVELOPMENT OF A FIVE-BAR PARALLEL ROBOT WITH LARGE WORKSPACE", one link to it is

    I wanted to restrict print area to a safe area, because printing outside will have other problems like lower resolution, variable speeds, instability of the mechanics. Crossing singularity to change work modes is an interesting task, however, e.g how Morgan tries it. I think it uses momentum to cross.

  • @bondus Thank you for sharing the video. I started to analyze movements with a wacom tablet, this could be interesting for you also. I want to use it to analyze precision of movements, ringing/vibrations and how stable the scara arms are in respect of Z direction (the pressure of the wacom pen).

  • @JoergS5, the DexTAR, I'll read that paper.

    I think swapping from work mode 1 to work mode 2, and back, should be fairly easy, you do not have to use momentum to get through the singularity. Same thing swapping from 1 to 3, assuming your proximal arms can pass through the center. Swapping from 2 to 3 would have the distal arms "dangling" and you must use momentum to get past in a predictable way.
    But the worst problem is probably to solve the motion planning in a good way. To know when it's a good idea swap. For 3D printing the only way I can see it being used is if you print multiple parts and swap mode between the different parts to reach different areas.

    Using a tablet to track movement is a good idea.
    I ordered some accelerometers/gyro modules yesterday. If I can get them to sample fast enough they should be good for measure ringing and vibrations, but not for positioning.

    This little arm is ridiculous. I can easily push it to 800mm/s without skipping steps. It starts dancing around on my desk, it's just attached to a small piece of alu extrusion, the whole thing weighs less than 2kg.

  • @bondus Gyro and accelerators is a really good idea!

  • @JoergS5 , Another little issue found, and solved.

    getQuadrant() must take x and y as float, not int.

    There were some corner cases where the rounding of the float to an int placed the coordinate in the wrong quadrant. Leading to a small error in the inverse transform. Once it popped over into the right quadrant the error went away.

    This could be seen when moving over such a border, the motors did a sudden move, just like they physically hit something.

    I am tempted to create a test environment for the code. A dummy RRF where you plop in the FiveBarScaraKinematics.cpp as is and it runs a number of test and simulations to make sure the kinematics works as intended. It is a very complicated kinematics. A simple GUI with a virtual arm would be very cool too.

  • @bondus you are right with the getQuadrant() method. I will correct it, thank you.

    The findings of you remind me that it would be better to use unit testing like I'm used from Java. I will try to install a testing framework to avoid those errors in the future.

  • @JoergS5, I got my prototype machine printing.
    And it's creating some pretty nice prints.

    I have struggled to accurately measure the angles of the arms at the endpoints. And if they are configured even a fraction of a degree wrong the resulting models are quite badly twisted. To make this kinematics more user friendly I think some kind of calibration method would be needed. It's much easier to measure a distance moved or the length of a printed part than to measure an angle. It could be as simple as to input the measured X and Y coordinates at the home position (relative to what was configured) and a tool computes the actual angles. Or as advanced as the klipper firmwares delta configuration,
    Unfortunately a z-probe does not help for this problem.

    Or I could have built my machine with better tolerances 🙂


    And some live action:

  • @bondus You have a nice printer and a good first result.

    You are ahead of me, I am not finished building the printer yet. So my ideas to improve are theoretical:

    • at the actuators, if you use gears, harmonic drives would be best, for zero backlash
    • you can stabilize the arms by creating parallelograms between the hinges
    • to measure the angles exactly, you can prolonge the arms. Additinally at the other side of the actuator (prolonge the arms to the other side)
    • define reference points on the head bed and calibrate the hotend to those points

    My current plan for the arms are CFK based crane-like arms: CFK has a good E-module, is light and has low (or even negative) heat expansion.

  • @bondus I rechecked your video, the only weakness I see is the left arm (left from the view of the actuators) where the arm can swing in vertical direction because it is only one, not two rods. Your construction with two ball bearings to stabilize vertically is very good IMHO.

  • administrators

    @bondus said in JoergS5 parallel five bar scara:

    I have struggled to accurately measure the angles of the arms at the endpoints. And if they are configured even a fraction of a degree wrong the resulting models are quite badly twisted. To make this kinematics more user friendly I think some kind of calibration method would be needed. It's much easier to measure a distance moved or the length of a printed part than to measure an angle.

    I had a similar issue when calibrating my single-arm SCARA printer. For an outline of how I solved it, see the Calibration section at Maybe it will give you some ideas.

  • @dc42, your "dab" idea is a good alternative to print a large calibration object. I just have to figure out a way to solve the equation. You had only two arms and one angle to adjust, we have four arms and two angles. A brute force numerical method should work fine assuming the initial values are reasonable. One more reason to make a dummy RRF to plug in the kinematics c++ file into.

    @JoergS5, the main weakness of my arms are the rotational stiffness of the U-beams. When the elbow is at 90° the z-forces to the hotend are applied as rotation on the inner arm. When the arm is closest to the base the y-forces on the hotend tip are rotating the arms. When the arm is extended x-forces to the hotend tip are rotating the arms. I can see this by moving the arm around and checking by hand how stiff it is and seeing where it flexes.
    If you do some mechanical simulations this should be very visible.
    For the selection of arm material/geometry this is important. A CF rod with all fibres in one direction might not be good for this application.

    I would love some harmonic drives. In my experience belted gears have pretty low backlash, but they are very limited in ratio. My current 1:6 gearing is too low (high?) for the size this arm turned out, it's almost down to 30 microsteps per mm at the bad areas. 1:30 or more would be a better gearing, the duet can run the steppers pretty fast.

    I use normal deep groove bearings at the base, they are at a sufficient distance from each other to convert z forces at the hotend to horizontal forces. The thrust bearings, with grooved washers, in the elbows are not ideal for this use. They have to take some lateral forces which they are not designed for, but preloaded they keep things very stable, and the lateral loads are pretty low.
    I should have put a large thrust bearing in the hotend joint too, there is one deep groove bearing there now. Cross roller bearings would be ideal in all joints, but $$$.

    @JoergS5, we should join sources. I am updated to latest RRF, but with some features not working as they should (such as IsReachable()). I could setup a RRF fork on github. Ideally it would be linked back to your fork, my git skills are not that advanced.

    wall of text 🙂

  • @bondus The source is meant to be part of the official source of @dc42 at the end. I suggest we wait until I could test the code with my hardware. This will take until July.

    I see two weaknesses in today's code which I wish would be clarified before publishing in the official RRF code:

    • the resolution of printing depends on the x-y coordinate. The should be a recommendation of a "good safe" print area. This needs to be tested
    • the movement speed varies with x-y coordinates. RRF segments the movement into small parts, so this may not be a problem, but I am not sure about that. I want to measure it to be sure (e.g. measure whether the filament extrustion is even enough).

    A final improvement would be to give instructions and help how to change work modes. A safe solution would be to add an additional actuator to cross the singularity areas.

  • @bondus For the hinges, I bought some ball bearings from POM material, to be light. But they have a lot of play. Another possibility is using Hylite, which is polypropylen and has low backlash and is light. One could produce the part from the plates

    You are right with CFK, one must use the correct ones, there are different ones with respect to fibre direction.

  • @JoergS5, I found one more little possible issue. I noticed one more "stepping function" issue when running the code on my PC, after some digging I found an abs() in getAbsoluteAngle(). According to the c standard abs using int. But it looks like that in RRF it actually resolves to using floats, odd. It's better to use a fabs() or fabsf(). I saw no difference in the prints.

    Another issue is that when you try to do a CartesianToMotorSteps() of a coordinate that is physically unreachable by the arms (too far away) it does not complain. constraintsOk() does not catch that since the resulting angles and coordinates from getInverse() are NaN. I added a bunch of isnan() to getInverse() to never cache nan values, that works fine.

    Hylite is a fascinating material. I guess you have seen, a hylite based delta printer. I backed the kickstarter.

    I managed to "port" the kinematics to my PC with some careful copy-paste, and implemented a small command line utility to output a resolution drawing as an SVG (the easiest way to draw things) . It's fun to play around with arm lengths and limits and see where you end up. This is what my machine looks like:

  • @bondus abs is int, so it is casting the float to int and assigning to float, casting again. It is better to use fabs.

    I found an alternative to harmonic drives: and a 3D thing: which may be useful

    Your PC program is nice. The paper analyzes safe print areas, the deviations of serial vs. parallel scara and gives some hints about stabilizing the arms.

  • I changed my microstepping from 16 to 128 and now my machine prints really nice. It has pretty good repeatability. Using a dial gauge to measure X or Y I can see that it returns within +-25um after moving around. Not bad for a printed machine.
    The main issue now is the wobbly Z. Even if it is light and moves fast it needs Z strength to push away imperfections from the lower layers. As it is now it uses imperfections as a kind of jump and they propagate up and along the layers. Producing waves on flat walls.
    It's also pretty undamped. It keeps vibrating almost a second after a hit.

    @JoergS5, running the kinematics on my PC and stretching it to the limits I can see that there are limitations and assumptions in the implementation. Inverse and forward transform do not always agree, and sometimes they returns very strange values.
    It would be nice if it could handle the theoretical free robot with no limitations and no collisions of the arms. For all working modes.
    I might go crazy on your code and make it behave in all corner cases...

Log in to reply