Fixing Shared C and Pre-Rotate

808 views
Skip to first unread message

Jason von Nieda

unread,
Sep 16, 2018, 3:33:37 PM9/16/18
to ope...@googlegroups.com
This thread is a continuation of the discussion at https://groups.google.com/d/msgid/openpnp/95c5c850-0766-49bb-bdee-d8a3b2e3c4f2%40googlegroups.com?utm_medium=email&utm_source=footer

I wanted to start this to make sure I (and everyone else) understand the issues at a low level, and then see if my OffsetTransform or Mark's new PR fix one or both issues.

For reference, here's Mark's PR: https://github.com/openpnp/openpnp/pull/766

Here is an issue that was filed when the Shared C Pre-Rotate bug was first found: https://github.com/openpnp/openpnp/issues/599

So, there are two problems:

1. Shared C Movement: This is specific to GcodeDriver in that if you have > 1 nozzles sharing one motor GcodeDriver will ignore movements if it thinks the nozzle is already at that position. For example: N1.moveTo(0, 0, 0, 10) followed by N2.moveTo(0, 0, 0, 10) will not result in C10 being sent to the controller.

2. Shared C Pre-Rotate: This issue, as I understand it, is that OpenPnP performs the vision operation on each nozzle but it expects the nozzle to stay at the angle it was after the vision operation. When it places the part, it places it without sending further coordinates to the C axis. The problem is that if you have a shared C the "finished" nozzles have rotated during the vision operation for the "other" nozzles. So we need to have a way to store the final rotation and then rotate back to the before placing.

I believe this second one has to be a JobProcessor change. If I understand correctly, Marek's modification stores this rotation in the Z of the returned value since he doesn't need Z for placement, but that won't work, of course, for other machines. So we'll need to modify how that data is returned and find a place for the rotation value.

Given that, I think we should focus on a correct solution to the first problem first, and then I think the solution to the second one is fairly obvious. 

Marek: Can you confirm that I've described the problems correctly?

For #1: I think Mark's PR forcing variables to be sent solves elegantly, and my solution with the offset solves it less elegantly :) I'm not sure anything else is needed but a question remains: Is there any situation where having the motor at a given position is not the correct position for the same angle on multiple nozzles? In other words, is this always true? 
N1 C = 10 == Motor C = 10
N2 C = 10 == Motor C = 10
N3 C = 10 == Motor C = 10

If this is always true, then maybe I don't understand the problem, since if it's true then why does it matter that the motor doesn't move? I suspect the real issue is that that table is not always true, but if that's the case, could someone provide an example?

Thanks,
Jason



bert shivaan

unread,
Sep 16, 2018, 5:40:42 PM9/16/18
to ope...@googlegroups.com
It doesn't seem like #1 should be an issues at all IMHO. if N1,N2,N3 all need to be at C10, there should be no need to keep telling the motion controller that. No different than if Y doesn't change, why send the coordinate for the same Y?

Issue 2 seems like it would be problematic. If oPNP thinks the Nozzles are all at the rotation found during the pre-rotate check, then it would fail for sure during placement. Would it be difficult to record the C values pernozzle and send them during placement? (I know not what I ask so be nice :)

--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+unsubscribe@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/openpnp/CA%2BQw0jw_ntX1P%3DwDU2PUUpy9L08nkkh-77CkxFonRreiCuh1uw%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Marek T.

unread,
Sep 16, 2018, 7:12:38 PM9/16/18
to OpenPnP

W dniu niedziela, 16 września 2018 21:33:37 UTC+2 użytkownik Jason von Nieda napisał:


Here is an issue that was filed when the Shared C Pre-Rotate bug was first found: https://github.com/openpnp/openpnp/issues/599
So the issue 599 was reported by Paul. To use shared-C motor he had to modify the code. We are not sure how he made it on the moment when reported the bug. Pls find the discussion mentioned there was ended with two java files published by me, and the further discussion has broken.
Using my code I have never seen the problem with and without the prerotate.
 

So, there are two problems:

1. Shared C Movement: This is specific to GcodeDriver in that if you have > 1 nozzles sharing one motor GcodeDriver will ignore movements if it thinks the nozzle is already at that position. For example: N1.moveTo(0, 0, 0, 10) followed by N2.moveTo(0, 0, 0, 10) will not result in C10 being sent to the controller.
I don't remember now how it was is on regular code. But probably it is so.

2. Shared C Pre-Rotate: This issue, as I understand it, is that OpenPnP performs the vision operation on each nozzle but it expects the nozzle to stay at the angle it was after the vision operation. When it places the part, it places it without sending further coordinates to the C axis. The problem is that if you have a shared C the "finished" nozzles have rotated during the vision operation for the "other" nozzles. So we need to have a way to store the final rotation and then rotate back to the before placing.
2. I don't understand why pre-rotation is related to shared-C. It seems to me the required processes are:
- non C-shared motor without prerotation:
pick.part1, bottom.vision.allign1, adding C-corection1 related to the project - nozzle remains in final C1-position
pick.part2, bottom.vision.allign2, adding C-corection2 related to the project - nozzle remains in final C2-position
placement1
placement2
- non C-shared motor with prerotation:
pick.part1, adding C-corection related to the project1, bottom.vision.allign - nozzle remains in final C1-position
pick.part2, adding C-corection related to the project2, bottom.vision.allign - nozzle remains in final C2-position
placement1
placement2

- C-shared motor without prerotation:
pick.part1, bottom.vision.allign1, adding C-corection1 related to the project, store final position C1
pick.part2, bottom.vision.allign2 (changing at occasion rotation of N1), adding C-corection2 related to the project, store final position C2
recall C1, placement1
recall C2, placement2
- non C-shared motor with prerotation:
pick.part1, adding C-corection related to the project1, bottom.vision.allign, store final position C1
pick.part2, adding C-corection related to the project2 (changing at occasion rotation of N1), bottom.vision.allign, store final position C2
recall C1, placement1
recall C2, placement2
In both cases, if we have one C-motor, each next allignment destroys previously C-positioned nozzle N-1.
 

I believe this second one has to be a JobProcessor change. If I understand correctly, Marek's modification stores this rotation in the Z of the returned value since he doesn't need Z for placement, but that won't work, of course, for other machines. So we'll need to modify how that data is returned and find a place for the rotation value.
Correctly. The code is in discussion mentioned in issue #599 if you need it.
Additionally, for C-shared motor usable (in my oppinion) is changing the placement direction. Picking N1,N2,N3 , Placement N3,N2,N1. It eliminates one move from N3 of pick to N1 of placement. Not necessary but usable.

Jason von Nieda

unread,
Sep 17, 2018, 9:33:56 AM9/17/18
to ope...@googlegroups.com
Hi Marek,

I think the biggest question now is: Why is #1 a problem at all? If N1 C = 10 is the same as N2 C = 10, why does the move need to be sent? You've alluded to this being an issue; can you explain what the problem is?

Thanks,
Jason


--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.

To post to this group, send email to ope...@googlegroups.com.

Marek T.

unread,
Sep 17, 2018, 10:33:18 AM9/17/18
to OpenPnP
Hi Jason,

It was one year ago when we discussed about something related to this (#599). So I don't remember everything correctly, specially after that have fixed everything that was a pain with it.
Are you sure it's me who alluded it as issue? Not Paul a year ago, not Mark a day ago?
I'm not about to persist it was not me on some day, but really don't remember it :-(.

Not sure but it could be something about that the C is returned to 0deg after the finished each nozzle placement in some situation (not sure it depend on prerotation on/off).
However if required is C=10 and actually registered is just 10 - I can't see a reason to send it again.

Mark

unread,
Sep 17, 2018, 12:37:29 PM9/17/18
to ope...@googlegroups.com

> Are you sure it's me who alluded it as issue? Not Paul a year ago, not Mark a day ago?

 

It could have been me!

 

I was under  the impression that shared physical axes still have separate “virtual” axes (i.e. machine.xml <axis> elements /  Java “Axis” objects). So I consequently assumed each axis keeps track of the current coordinate separately and the coordinate change through another Axis that shares the physical actuator would be missed.

 

I said as much, here:

https://groups.google.com/d/msg/openpnp/ejIunan54N8/10-AF0JiCQAJ

 

I’m very sorry if this has caused a wild goose chase. :(

 

On the other hand, I’m quite convinced that my “mistaken” conception would actually be a cleaner solution and might fix shared axes J.

 

Make Axes into separate “virtual” axes inside OpenPNP so they separately keep track of the “virtual” axis coordinate (i.e. separately for each Nozzle).

 

Example:

 

Before:

<axis name="z" type="Z" home-coordinate="0.0">

   <head-mountable-ids class="java.util.HashSet">

      <string>N1</string>

      <string>N2</string>

   </head-mountable-ids>

   <transform class="org.openpnp.machine.reference.driver.GcodeDriver$CamTransform" cam-radius="24.0" cam-wheel-radius="9.5" cam-wheel-gap="2.0">

      <negated-head-mountable-id>N2</negated-head-mountable-id>

   </transform>

</axis>

 

After:

<axis name="z1" type="Z" home-coordinate="0.0">

   <head-mountable-ids class="java.util.HashSet">

      <string>N1</string>

   </head-mountable-ids>

</axis>

<axis name="z2" type="Z" home-coordinate="0.0">

   <head-mountable-ids class="java.util.HashSet">

      <string>N2</string>

   </head-mountable-ids>

   <transform class="org.openpnp.machine.reference.driver.GcodeDriver$CamTransform" cam-radius="24.0" cam-wheel-radius="9.5" cam-wheel-gap="2.0">

      <negated-head-mountable-id>N2</negated-head-mountable-id>

   </transform>

</axis>

 

Then add my PR to tolerate any missed “behind-the-back” shared actuator coordinate changes. As soon as the JobProcessor (or any caller) switches to a different Nozzle (or any HeadMountable), the correct virtual coordinate would be restored physically.

 

This should resolve any issues with pre-rotate and any other code that assumes axes (i.e. Nozzles) to retain their coordinates. I’ve seen it many times in the code that it does a selective moveTo() in some coordinates but not all (NaN semantics). This would then work reliably.

 

_Mark

 

Jason von Nieda

unread,
Sep 17, 2018, 12:45:15 PM9/17/18
to ope...@googlegroups.com
Hi Mark,

I'm afraid I don't understand how this proposed solution works for shared axes. Let's first make sure we're on the same page WRT machine configuration. Since we're talking about shared C, let's consider the following machine configuration:

* 2 nozzles: N1 and N2.
* 1 motor on Z, see-saw configuration. Z- lowers N1, Z+ lowers N2.
* 1 motor on C, gear or belt turns both nozzles when the motor turns.

In this configuration, with your "After" configuration, how does N1 know it's coordinate, or transform it's outbound coordinate?

Thanks,
Jason



--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.

Mark

unread,
Sep 17, 2018, 2:11:54 PM9/17/18
to ope...@googlegroups.com

Hi Jason,

 

> In this configuration, with your "After" configuration, how does N1 know it's coordinate, or transform it's outbound coordinate?

 

I’ll distinguish physical axes and virtual axes.

 

Physical axes are associated with the physical actuator/motor. The controller has a designator for it, i.e. “C”.

 

Virtual axes are the conceptual axes of the nozzles, as if they were separate. I.e. “c1”, “c2”

 

Now these virtual axes “time-share” the physical axis.  Whenever a moveTo() is called on a Nozzle (or any HeadMountable), the AxisMapping will assign the correct virtual axis to it. Because each virtual axis stores its own “current” coordinate, a the moveTo() is always implicitely restoring the previous position, even if it has not changed from the viewpoint of the virtual axis (assuming forced coordinate output, using my PR).

 

Transforms work as before. As today, the coordinate is always saved on the axis object in transformed form (“raw coordinate”).

 

Because we’re using the same axis designator (i.e. “C”) in the Gcode fragment, the actuator is actually shared without OpenPNP knowing or caring.

 

It’s a bit like multi-processing on a CPU: each process has its own set of CPU/FPU registers. If the multitasking scheduler switches to another process, it first has to reload the previous register contents. For the process this looks and feels as if it has the CPU alone.

 

The same would be achieved here. For the Nozzle it looks and feels as if it has the axis alone…

 

Writing this, I also have to think about the NaN semantics one more time. The forced output variables would probably have to be issued too, even if NaN is given (axis resolved to null). If you give the green-light I’ll change that in the PR.

 

What do you think?

 

 

_Mark

 

 

 

Von: ope...@googlegroups.com [mailto:ope...@googlegroups.com] Im Auftrag von Jason von Nieda
Gesendet: Montag, 17. September 2018 18:45
An: ope...@googlegroups.com
Betreff: Re: [OpenPnP] Re: Fixing Shared C and Pre-Rotate

 

Hi Mark,

 

I'm afraid I don't understand how this proposed solution works for shared axes. Let's first make sure we're on the same page WRT machine configuration. Since we're talking about shared C, let's consider the following machine configuration:

 

* 2 nozzles: N1 and N2.

* 1 motor on Z, see-saw configuration. Z- lowers N1, Z+ lowers N2.

* 1 motor on C, gear or belt turns both nozzles when the motor turns.

 

 

Thanks,

Jason

 

 

Jason von Nieda

unread,
Sep 17, 2018, 2:27:09 PM9/17/18
to ope...@googlegroups.com
Hi Mark,

It's still not clear how N1 knows it's current coordinate when something else changes it. I think what you are talking about works for something like shared C, where the moves are mirrored across all associated virtual axes, but for something like shared Z with the negated transform (like Peter's head) it doesn't work. Consider:

1. Z1 = 0, Z2 = 0, Z = 0
2. N1.moveTo(0, 0, -10, 0) -> Z-10
3. N2.z is now implicitly at +10 because of the transform. When OpenPnP reads it, it gets the correct value.
4. N2.moveTo(0, 0, +10, 0) -> Z+10
5. N1.z is now implicitly at -10 because of the transform.

In your suggested method, when Z1 changes, Z2 doesn't know about the change and vice-versa so OpenPnP will show invalid coordinates for that object and processes reading those values will get incorrect coordinates.

I think we need to take a step back here and determine if there is actually a problem to be solved or if we're just wasting our time. 

If there is an issue with shared C and motion can someone please describe the problem and provide an example of how it fails? Note I am talking about motion / GcodeDriver, not the known logic issue with JobProcessor not storing coordinates. After all this discussion I feel like maybe there is not actually an issue with motion / GcodeDriver.

Thanks,
Jason


Marek T.

unread,
Sep 17, 2018, 2:49:10 PM9/17/18
to OpenPnP
Jason, if it's out of discussion that restore of C before the placement is necessary to apply, then maybe fix it and I'll test the pure release if there exists the problem you're talking about. You can even prepare some simple 2-3 parts job that I could to run and give you 100% clear feedback if it's pnp well or not at all.

Jason von Nieda

unread,
Sep 17, 2018, 2:53:31 PM9/17/18
to ope...@googlegroups.com
Hi Marek,

Yep, I think that's a good idea. I agree 100% that #2 (restore C) is a real issue and it should have a reasonably simple fix. I'll see if I can get something together tonight and get it over to you.

Jason


On Mon, Sep 17, 2018 at 1:49 PM Marek T. <marek.tw...@gmail.com> wrote:
Jason, if it's out of discussion that restore of C before the placement is necessary to apply, then maybe fix it and I'll test the pure release if there exists the problem you're talking about. You can even prepare some simple 2-3 parts job that I could to run and give you 100% clear feedback if it's pnp well or not at all.

--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.

Marek T.

unread,
Sep 17, 2018, 3:43:20 PM9/17/18
to OpenPnP
But remember I won't check it properly for the Z controls as don't have that motors.

Mark

unread,
Sep 17, 2018, 4:22:36 PM9/17/18
to ope...@googlegroups.com

> I think we need to take a step back here and determine if there is actually a problem to be solved or if we're just wasting our time. 

> I agree 100% that #2 (restore C) is a real issue

 

 

I’m talking about this “#2 (restore C)” issue and nothing else. My proposal would address exactly that.

 

> In your suggested method, when Z1 changes, Z2 doesn't know about the change and vice-versa so OpenPnP will show invalid coordinates for that object …

 

I think you have to take one more step backwards. One needs to embrace the virtualization, otherwise it won’t make sense.

 

When a machine really has two physical axes, only one will be actuated when you move one Nozzle, right? Reading back the coordinate of the other axis will show it unchanged, right?

 

With the virtual axes this behavior is emulated.

 

Like with other forms of multitasking, there has to be a context-switch. If you switch to the other Nozzle by moveTo() and tell it to move only in X, its C will implicitly be restored (à “#2 restore C”) with my PR. Note that a moveTo() must always be issued before the nozzle position is in some way “used” physically, but that’s the same assumption as before (with shared axes) and it also comes “naturally”.

 

The subject of a virtualization need not know that it is virtualized. OpenPNP need not know, that one Z is see-sawing up when the other is lowered. It must just tell the controller what to do and let it worry about zero deltas.

 

> … and processes reading those values will get incorrect coordinates.

 

Not incorrect. The pre-rotate case is exactly the “model case” of why this behavior is the desired one! You want the Nozzle to reflect the last position explicitly commanded to moveTo() by the OpenPNP business logic. The physical position however is a “side effect” of machine “economics” and reading (transforming)  it back is incorrect in terms of the business logic.

 

Different way to explain – as a thinking experiment:

 

Do you agree that a machine with two physically separate axes would behave exactly the same way given the same sequence of moveTo() commands and the same sequence of read-backs?

 

Yes? Then how can this behavior be incorrect? J

_Mark

 

P.S. Of course all this only works with “benign” axis sharing such as harmlessly rotation other axes without a chance of it knocking down stuff or moving one Z out of harm’s way when the other is lowered below safe Z. Same as before!

 

 

SMdude

unread,
Sep 17, 2018, 5:36:02 PM9/17/18
to OpenPnP
Hi Jason,

From my understanding, this is the problem with shared C: Lets say we pick up 3 parts, 1 that gets rotated to 90deg, the next gets rotated to 180deg and the 3rd stays at 0.
first part pickup, second part pickup, 3rd part pickup. >move to camera rotate parts to expected angles.
First part gets rotated to 91deg(when this happened no.2 and 3 nozzles also rotated to 91deg).
Second part is currently rotated to 91deg, openepnp currently thinks it should be 0>move n2 to camera rotate part to expected angle(180deg) so this part is now at 270, but also N1 has had 180 added to it and is also at 270.
3rd part, currently at 270deg openpnp assumes it is 0

Openpnp assumes that each nozzle is in the state it was originally left, however, each nozzle has accumulated the moves of the other C axis as well.

What needs to happen is openpnp needs to log the rotational differences between each of the  C axis and as each part is placed apply the correct rotation to put the next C axis in its correct position. Basically, when placing parts it needs to unwind the C. I hope that makes sense, it is too early in the morning to think logic! :D

Cheers

Jason von Nieda

unread,
Sep 17, 2018, 5:41:10 PM9/17/18
to ope...@googlegroups.com
Hi Mark,

I understand you now, but this is a major departure from how OpenPnP has always worked, and I don't see a good reason to make such a large change to fix a very minor bug.

It breaks the contract that Locatable.getLocation() is always correct, which will break the DROs, at least. I agree with you that it results in correct movements, but it doesn't reflect reality, which is that when more than one Movable shares a motor, moving any of those objects moves the others.

When it comes down to it, the bug causing pre-rotate shared C problems is small and easily fixable. So, now that it's understood, I'll just fix it and not upend the universe :)

That being said, I think your PR for being able to force moves is still useful and I'm intending to merge it. It will fix https://github.com/openpnp/openpnp/issues/685 and it will also help with other controllers that require every axis in each command.

Thanks,
Jason


--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.

Jason von Nieda

unread,
Sep 17, 2018, 5:43:14 PM9/17/18
to ope...@googlegroups.com
Thanks - that lines up with my understanding too. It's clear now. I think we can get a fix in place pretty easily.

Jason

SMdude

unread,
Sep 17, 2018, 10:49:33 PM9/17/18
to OpenPnP
Hmmm, interesting :D
So, once this becomes a working thing, we could then use a standard smoothie to run a 4 nozzle machine by using shared C(use a driver for each C motor) and freeing up an axis for a second Z axis...

I like it! ;)

Jason von Nieda

unread,
Sep 18, 2018, 1:01:47 AM9/18/18
to ope...@googlegroups.com
Alright folks, I think I've got a solution in mind and I'd like to ask everyone interested to check my logic. Here are my notes as I worked through the code, and below that is my suggestion:

---------
There are three styles of alignment supported:

1. Basic Bottom Vision: The bottom vision system determines an X, Y, C offset.
   The offset is then applied before placement. This suffers from inaccuracy due
   to nozzle runout.
   
2. Pre-Rotate Bottom Vision: The expected final placement rotation is first
   calculated and then the part is imaged at that rotation. The offset from
   expected is calculated and the nozzle is then rotated to correct for that
   offset. The part is imaged again to calculate the X, Y offset. An offset is
   returned with NaN for C which tells OpenPnP not to move C from it's current
   position. In other words, at the end of the process the nozzle rotation
   is exactly what it should be at placement.
   
   This works fine for non-shared C, but for shared C the nozzle rotation is
   changed for the N+1 alignment and the previous rotatino of the nozzle is
   lost.
   
   To fix this we need to store the rotation after the process and restore it
   before placement.
   
3. Physical Rotation: The part is placed in a set of jaws that center and
   rotate it to the correct placement rotation. The part is then picked back
   up rotated with respect to nozzle rotation 0. It is then finally rotated
   to the boardLocation's rotation before placement.
   
   
So, the issue is that #2 and #3 conflict with one another. The code was
originally written for Physical Rotation, where the part still needed to be
rotated before placement, but with Pre-Rotate Bottom Vision the complete angle
is calculated and thus no further changes are required.

In addition, Pre-Rotate Bottom Vision makes extensive use of NaN in Locations,
which is going away, so that needs to be refactored anyway.

I think the easiest way to solve this and have it be extensible in the future
is to just let the alignment interface return a final placement location, similar
to what is calculated for Pre-Rotate Bottom Vision. We'd move the code that
calculates the final location for non-pre-rotate into ReferenceBottomVision.

This will break the external implementation of #3, but I belive there is only
one user using it and they can just copy/paste the one line of code into their
implementation.
---------

So, to restate the solution, here are the changes I'd make:

1. In JobProcessor.doPlace, take the code that handles the non-pre-rotate math and move it into ReferenceBottomVision.findOffsetsPostRotate.
2. In JobProcesor.doPlace, remove the code that handles the pre-rotate math. This is only used (as far as I know) by Matt Brocklehurst, so he will have to add this one line back in to his PartAlignment code.
3. In JobProcessor.doPlace, the entire  if (plannedPlacement.alignmentOffsets != null) { block just becomes placementLocation = plannedPlacement.alignmentOffsets;

So, in summary, PartAlignment.findOffsets effectively just returns the final placement Location including X, Y, Z, and C and during placement that location is used essentially unmodified. I'll probably rename findOffsets to something like getFinalPlacementLocation to keep it clear, too.

Does this make sense to everyone?

Thanks,
Jason


--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.

Brynn Rogers

unread,
Sep 18, 2018, 2:30:53 AM9/18/18
to OpenPnP


On Tuesday, September 18, 2018 at 12:01:47 AM UTC-5, Jason von Nieda wrote:
Alright folks, I think I've got a solution in mind and I'd like to ask everyone interested to check my logic. Here are my notes as I worked through the code, and below that is my suggestion:

---------
There are three styles of alignment supported:

1. Basic Bottom Vision: The bottom vision system determines an X, Y, C offset.
   The offset is then applied before placement. This suffers from inaccuracy due
   to nozzle 

Okay, I can't answer the questions you ask, but I have a new, sortof related one:

If Basic Bottom Vision suffers from runout error ( I presume because the nozzle Z is not perfectly perpindicular to X and Y)
Then couldn't you run a bottom vision calibration that steps through 360 degrees in steps and memorizes the nozzle offsets,
which could then be used to cancel out the runout, so that you now have basic bottom vision with runout correction, that doesn't need to take more than one image like in #1, as apposed to the two image step #2.

Brynn

Mark

unread,
Sep 18, 2018, 2:47:05 AM9/18/18
to ope...@googlegroups.com

Hi Jason,

 

> That being said, I think your PR for being able to force moves is still useful and I'm intending to merge it.

 

Thanks!

 

> I understand you now, but this is a major departure from how OpenPnP has always worked…

 

I see. The beauty of it is that after merging the PR, both ways will work thanks to the flexible architecture of OpenPNP. It just depends on how the machine.xml <axis> elements are structured (remember the “before” and “after”).

 

> It breaks the contract that Locatable.getLocation() is always correct, which will break the DROs, at least.

 

Well that’s again a question of whether you embrace the virtualization or not. When a user wants to specifically track one nozzle then he might as well be interested in the virtual, not the physical coordinates, especially when tracking the effective pre-rotated part angle.

 

Personally I don’t find the DRO to be very important. It’s the capture buttons that must work reliably. And again I think these should reliably capture the virtual coordinates of the nozzle in question, as adjusted at some time before capturing. If it ever matters in practice, i.e. if a user ever were to switch back and forth between nozzles before capturing, it would then again emulate a behavior like on a machine with real multiple axes.  

 

But like I said you don’t need to be “convinced”, as both ways will work, as users wish. J

 

_Mark

 

Von: ope...@googlegroups.com [mailto:ope...@googlegroups.com] Im Auftrag von Jason von Nieda
Gesendet: Montag, 17. Se
ptember 2018 23:41
An: ope...@googlegroups.com
Betreff: Re: [OpenPnP] Re: Fixing Shared C and Pre-Rotate

 

Hi Mark,

Mark

unread,
Sep 18, 2018, 9:18:07 AM9/18/18
to ope...@googlegroups.com

> Alright folks, I think I've got a solution in mind and I'd like to ask everyone interested to check my logic. Here are my notes as I worked through the code, and below that is my suggestion

 

Sounds good.

 

Not sure I understand case #3 … or more specifically why there remains a conflict once everything is universally handled inside the new getFinalPlacementLocation().

 

Assuming I understand the “jaws that center and  rotate it to the correct placement rotation” scenario correctly, couldn’t getFinalPlacementLocation() just equally return the proper final Location, in this case with C set to zero?

 

Perhaps rename it into “finalAppliedLocation” to make it clear that the “applied” location is just what remains to be done now that the part has already been centered and rotated by the jaws.

 

If I misunderstood the scenario, just dismiss this E-Mail as I don’t need an explanation. I just wanted you to quickly consider this.

 

_Mark

 

 

Jason von Nieda

unread,
Sep 18, 2018, 10:15:54 AM9/18/18
to ope...@googlegroups.com
There's no conflict after the change - the conflict is the reason for the change :)

You've got the rest right. 

Jason


--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.

Jason von Nieda

unread,
Sep 18, 2018, 10:18:15 AM9/18/18
to ope...@googlegroups.com
Yes, we call this Nozzle Calibration. OpenPnP has code for it but it doesn't work correctly / needs some work. Ultimately, though, most people are probably going to want to use pre-rotate as it completely eliminates all sources of runout at the time of placement. There's no real downside to is aside from the second move, and I question whether the second move is really necessary - but that's for another topic once we've got past this issue.

More info on nozzle calibration here, if you want it: https://github.com/openpnp/openpnp/issues/235

If you want to discuss it in depth, please create a new thread for it.

Thanks,
Jason


--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.

Marek T.

unread,
Sep 18, 2018, 11:18:17 AM9/18/18
to OpenPnP
Hi Jason,

Prerotate eliminates the problem of runouts only if you don't need to change the nozzles.
If you have only one axis, then you may keep the complete of different nozzles in some bank, every of them kept with some pointed rotation, and before the nozzle.changing always come back with C to 0.
But the problem of the runout is cumulated runout of the nozzle and the axes. In ptactice it's hard to have axes with 0 runout or have many axes with identical runouts.
So if you have 3-4-5 axis, you should have for them assigned 3-4-5 banks of the nozzle sets.

That's why nozzle.calibration is not something to be forgotten becasue we have prerotation.

Mark

unread,
Sep 18, 2018, 12:18:27 PM9/18/18
to ope...@googlegroups.com

> Prerotate eliminates the problem of runouts only if you don't need to change the nozzles.

 

I don’t think that’s right, Marek. Prerotate uses vision on each individual part and will compensate any runout of any nozzle tip.

 

Nozzle calibration would be very useful if you want to avoid bottom vision altogether for speed reasons. Nozzle calibration would have to be run after each nozzle tip change (I think this is already the case in current dormant code).

 

_Mark

 

Von: ope...@googlegroups.com [mailto:ope...@googlegroups.com] Im Auftrag von Marek T.
Gesendet: Dienstag, 18. September 2018 17:18
An: OpenPnP
Betreff: Re: [OpenPnP] Re: Fixing Shared C and Pre-Rotate

 

Hi Jason,

Marek T.

unread,
Sep 18, 2018, 12:38:33 PM9/18/18
to OpenPnP
Mark, you probably didn't understand me.

First, the prerotation does not compensate anything. It's "only" not allowing to the runout (it means harmful offset) could appear with rotation made after the bottom.vision. So it improve the placement.

But not the picking. If you have two nozzles 502, the one with runout 0.01 and second with 0.1 - then what the effect you will get?
If you have the set axis+nozzle0.01 calibrated to properly pick the part and then you mount this second one - you won't pick anything with and without the prerotation. First you have to perform calibration of the set.
The reasone to replace 0.01 into 0.1? Imagine you have three nozzles and you need 3x502. Without the calibration you have to address which 502 is for which nozzle.

Mark

unread,
Sep 18, 2018, 1:24:14 PM9/18/18
to ope...@googlegroups.com

> Mark, you probably didn't understand me.

 

I see…

 

If the runout is very large, i.e. the nozzle tip is so far off that the part is not “sucked up” properly, then yes I agree the picking is not helped by the pre-rotate and it would be helped by the nozzle tip calibration.

 

If the runout is smaller, so the part is still “sucked up” properly, but off-center, then pre-rotate will help.

 

However with the example 0.01-0.1mm runout, do you already have mispicks on 0402 parts? Or do you use even smaller parts?

 

_Mark

Marek T.

unread,
Sep 18, 2018, 1:37:15 PM9/18/18
to OpenPnP
0.1mm was extremal value to picture you the situation.
I have 502 with runouts 0.02-0.06, and some 506 with 0.3(!)mm.
And we have few 502 adressed for concrete axis (502-1 for axis-1, 502-2 for axis-2). Plus each nozzle have pointed 0 and C axes have homing. So we always mount the concrete nozzle on concrede axis with concrete C-position.
Damned play could be off if have nozzle.calibration...

Runout is not the problem for pnp if you just mount the nozzle,calibrate it - and don't change any more (or without, calibration if you change the feeder coordinates to the part could be picked).
We do 0402 with above adventures and restrictions.
Never tried 0201 but would like to try it some day :-).

Brynn Rogers

unread,
Sep 18, 2018, 2:00:51 PM9/18/18
to OpenPnP
Marek,   just a grammer correction:    you use the word concrete when I am pretty sure your actually mean concentric.

Marek T.

unread,
Sep 18, 2018, 2:11:48 PM9/18/18
to OpenPnP
Concentric? Absolutely not.
 Maybe "concrete" is not the word that could be used by native Englishman, but it was going about the nozzle that can be used only for one axis (and not other) and mounted at only required position (not any position).

Brynn Rogers

unread,
Sep 18, 2018, 3:04:18 PM9/18/18
to OpenPnP
Sorry,   Maybe 'Specific' would be the word your looking for.      I have a hard time understanding your posts but I want to because you clearly have good information - just not the best english.

Mark

unread,
Sep 18, 2018, 3:38:16 PM9/18/18
to ope...@googlegroups.com

> Sorry,   Maybe 'Specific' would be the word your looking for

 

Brynn, just out of curiosity (as a non-native English speaker), when you read “concrete” you understand the mineral cement building stuff, right?

https://en.wikipedia.org/wiki/Concrete

 

But at least in theory there is also the “specific” meaning:

https://en.oxforddictionaries.com/definition/concrete

 

In German there’s the same false friend: “konkret” means “specific”.

 

_Mark

 

Marek T.

unread,
Sep 18, 2018, 4:09:39 PM9/18/18
to OpenPnP
Strange that you understand anything what I say;). I was learning EN only one year and many many years ago...
You can only imagine what the hard time I have from time to time, when read some posts here made by people using English really not basic (not adressed to non-English people) but just common :-).
Interresting that never have problems to understand what Jason wants to express...

In Polish, same as German in this case,
"Konkret" means "specific". However funny google.translate, that I use occasionally, is also giving a choice that "concrete" means moreless the same as "specific".

W dniu wtorek, 18 września 2018 21:04:18 UTC+2 użytkownik Brynn Rogers napisał:
() just not the best english ()

Brynn Rogers

unread,
Sep 18, 2018, 4:11:54 PM9/18/18
to OpenPnP


On Tuesday, September 18, 2018 at 2:38:16 PM UTC-5, ma...@makr.zone wrote:

> Sorry,   Maybe 'Specific' would be the word your looking for

 

Brynn, just out of curiosity (as a non-native English speaker), when you read “concrete” you understand the mineral cement building stuff, right?

https://en.wikipedia.org/wiki/Concrete


Correct.
 

 

But at least in theory there is also the “specific” meaning:

https://en.oxforddictionaries.com/definition/concrete


Yes, but in 'engineering speak' it doesn't really get used that way.
 

In German there’s the same false friend: “konkret” means “specific”.


Is German your native tongue then?          

I didn't want to complain that your english wasn't perfect, I was just seeing concrete and trying to understand what you really meant, and my concentric guess was off the mark.
'Specific' seems to fit there better. 

 

_Mark

 

Brynn Rogers

unread,
Sep 18, 2018, 4:17:33 PM9/18/18
to OpenPnP

Plus I obviously mixed up Marek and Mark.   

My understanding of the OpenPnp stuff is still rudimentary.  So it is twice is bad - I need to understand what people say, and then I have to understand in OpenPnP context what that means.

Marek T.

unread,
Sep 18, 2018, 4:42:43 PM9/18/18
to OpenPnP
:-)

SMdude

unread,
Sep 18, 2018, 5:36:12 PM9/18/18
to OpenPnP
Hi Jason,

Just to clarify, the only reason most people opt to use prerotate is because normal bottom doesn't work with nozzles that have runout!
If you have perfect holders and perfect nozzles then we don't need nozzle calibration, but they are rarer than hens teeth :D
While you are working on how the machine calculates its coordinates, it might be worth revisiting nozzle cal as the machine really needs to base its position in x and y for the current nozzle rotation xy offsets. If this was done, the nozzle would always go to the correct pick location for small parts, the passives could all be placed with out vision at all, and then you can opt to just do bottom vision on just some parts, which if nozzle cal is working, we only need to do bottom vision, not prerotate.


Really there isn't much to map out with nozzle cal. There is no special shape that the nozzle will run. Just a circle with n radius, it should still be centered in C axis. Once the runout offset is known and the "0" point of that offset, the actual position can just be calculated.

Mick

Jason von Nieda

unread,
Sep 18, 2018, 5:39:28 PM9/18/18
to ope...@googlegroups.com
On Tue, Sep 18, 2018 at 4:36 PM SMdude <spiteri...@gmail.com> wrote:
Hi Jason,

Just to clarify, the only reason most people opt to use prerotate is because normal bottom doesn't work with nozzles that have runout!
If you have perfect holders and perfect nozzles then we don't need nozzle calibration, but they are rarer than hens teeth :D

Yep, correct. To be honest, I think pre-rotate should be the default, and maybe even non-pre-rotate should be removed.
 
While you are working on how the machine calculates its coordinates, it might be worth revisiting nozzle cal as the machine really needs to base its position in x and y for the current nozzle rotation xy offsets. If this was done, the nozzle would always go to the correct pick location for small parts, the passives could all be placed with out vision at all, and then you can opt to just do bottom vision on just some parts, which if nozzle cal is working, we only need to do bottom vision, not prerotate.

Agreed. This is just something that needs some coding time. I wrote the initial version, then people said it didn't work due to some kind of rotation error. To me it seemed to work and it was never quite clear why it didn't, and I haven't had time to pick it back up. So, basically, it needs to be checked, tested, debugged and revisited.
 


Really there isn't much to map out with nozzle cal. There is no special shape that the nozzle will run. Just a circle with n radius, it should still be centered in C axis. Once the runout offset is known and the "0" point of that offset, the actual position can just be calculated.

Yep, agreed. Not much to it, but the complexities might lie in the design of OpenPnP rather than the more simple technical problem.

Jason
 

Mick

--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.

Marek T.

unread,
Sep 18, 2018, 6:12:16 PM9/18/18
to OpenPnP
Pity that you've removed it instead of mark with some warning like "experimental option"...

Mark

unread,
Sep 19, 2018, 2:42:29 AM9/19/18
to ope...@googlegroups.com

> Plus I obviously mixed up Marek and Mark.   

 

No the “concrete” comes from Marek alright. I was just asking out of curiosity.

 

> Is German your native tongue then?          

 

Swiss German actually (which is quite different). We learn German at school as our principle “official” language. That is in the mid&eastern part of Switzerland. We’ve got a French, an Italian plus a small Rhaeto-Romanic speaking part too.

 

Marek speaks Polish which seems to have similarities with German.

 

Yep, tower of Babel it is J

 

_m

 

 

 

Von: ope...@googlegroups.com [mailto:ope...@googlegroups.com] Im Auftrag von Brynn Rogers
Gesendet: Dienstag, 18. September 2018 22:12
An: OpenPnP
Betreff: Re: [OpenPnP] Re: Fixing Shared C and Pre-Rotate

 

--

You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.

Marek T.

unread,
Jan 22, 2019, 6:02:37 PM1/22/19
to OpenPnP
After long time...

I'm using sharedC with some fix made by CriS before the #766 was made by Mark and merged.
Generaly it works for me (also with prerotation) but since I started to play with Michael's nozzleCalibration experimental update I see some strange issue. And I'm not sure if it doesn't come from the foi that I have or other general mess I have in my customised code...

I came through the thread and the wiki, PR etc but didn't find final info that could make me sure. So I'd like to ask:
1. does the sharedC setup should work on actual Openpnp release without any customisation?
2  if YES for above, how should look axis maping for 3 nozzles with common sharedC motor?
3. should it work with pre-rotation or not (as PK reported) ?

Marek T.

unread,
Jan 22, 2019, 8:27:28 PM1/22/19
to OpenPnP
And move_to_command how should look if only C is shared but the rest "normal".
Should it be maybe:
G0 {X:X%.4f}{Y:Y%.4f}{RotationF:C%.4f}F{FeedRate:%.0f} ; MOVE_TO_COMMAND

?

Mark

unread,
Jan 23, 2019, 2:48:10 AM1/23/19
to ope...@googlegroups.com

Hi Marek

 

In my view it should work without modification if you use the „forced“ Variables. Including pre-rotation and the upcoming nozzle runout compensation!

 

But you need to modify the machine XML to have two Z and C Axes and then use Axis Mapping to map each Z/C axis to the respective nozzle. Plus force the MOVE_TO_COMMAND variables.

 

Depending on how the two C axes are coupled you may need an Axis Transform to negate the rotation (if e.g. the axis are coupled by pinion) or leave it out if they rotate the same way (e.g. coupled by belt). Which of the two C axes needs the transform (if any), also depends how the axes are mechanically coupled to the motor or how the motor phases are wired (i.e. which of the axes rotates the right way and which in reverse). The fragment below is just an example when the second axis needs to be negated

 

I leave the AxisTransform for the Z axis to you, assuming it is shared too and you already have the right transform. Just split that up into two axes. The fragment below is just an example:

 

        <axes class="java.util.ArrayList">

            <axis name="x" type="X" home-coordinate="210.0">

               <head-mountable-ids class="java.util.HashSet">

                  <string>*</string>

               </head-mountable-ids>

            </axis>

            <axis name="y" type="Y" home-coordinate="600.0">

               <head-mountable-ids class="java.util.HashSet">

                  <string>*</string>

               </head-mountable-ids>

            </axis>

            <axis name="z1" type="Z" home-coordinate="0.0">

               <head-mountable-ids class="java.util.HashSet">

                  <string>N1</string>

               </head-mountable-ids>

            </axis>

            <axis name="z2" type="Z" home-coordinate="0.0">

               <head-mountable-ids class="java.util.HashSet">

                  <string>N2</string>

               </head-mountable-ids>

               <transform class="org.openpnp.machine.reference.driver.GcodeDriver$NegatingTransform">

                  <negated-head-mountable-id>N2</negated-head-mountable-id>

               </transform>

            </axis>

            <axis name="c1" type="Rotation" home-coordinate="0.0">

               <head-mountable-ids class="java.util.HashSet">

                  <string>N1</string>

               </head-mountable-ids>

            </axis>

            <axis name="c2" type="Rotation" home-coordinate="0.0">

               <head-mountable-ids class="java.util.HashSet">

                  <string>N2</string>

               </head-mountable-ids>

               <transform class="org.openpnp.machine.reference.driver.GcodeDriver$NegatingTransform">

                  <negated-head-mountable-id>N2</negated-head-mountable-id>

               </transform>

            </axis>

         </axes>

 

Now you need to use the “forced variables” as you already have:

 

G0 {X:X%.4f}{Y:Y%.4f}{RotationF:C%.4f}F{FeedRate:%.0f} ; MOVE_TO_COMMAND

 

I see no reason to force the X, Y variables here.

 

Where is Z in this statement? Do you have a sub-driver for that?

 

You need to force Z too! This way you get asserted independent Z moves regardless of the sequence of nozzle Z moves inside OpenPNP (or what OpenPNP thinks their current position is). This was (or still is) an issue with pre-rotate, I think.

 

Disclaimer. All the above is just derived from theory. So I’m very thankful for you to do some real testing (my machine has just one nozzle). If all this turns out to work, we could finally document it on the Wiki.

 

_Mark

 

 

 

Von: ope...@googlegroups.com [mailto:ope...@googlegroups.com] Im Auftrag von Marek T.
Gesendet: Mittwoch, 23. Januar 2019 02:27
An: OpenPnP
Betreff: Re: [OpenPnP] Re: Fixing Shared C and Pre-Rotate

 

And move_to_command how should look if only C is shared but the rest "normal".

Marek T.

unread,
Jan 23, 2019, 3:22:38 AM1/23/19
to OpenPnP
Hi Mark,
Something confusing... :-)

1. Sorry for my ignorance, but what do home-coordinates 210 and 600 in your x/y and is this regarding C?! Or just it's the part of your setup regardless C?
2. I have 3 nozzle rotated with one motor into one direction. So understand I don't need transform section in C maping, right? What means ending s> in line
<<axis name="c1" type="Rotation" <s>> ? Just shortcut meaning "put the rest of maping"?
3. You have underlighted "two Z". Why just two? Again, because your setup and you have them two and Unrelated onto C driving?
4. Can you write me how should look gcode of rotation in move_to_comand? (RotationF...) ot (Rotation...), I'm asking about this F...

Marek T.

unread,
Jan 23, 2019, 4:04:24 AM1/23/19
to OpenPnP
Forgive me it looks I didn't read your answer with enough attention...

Tell me mainly about this F, how gcode variable should really look in case of Rotation.

And do I need anyhow touch to Z thinking about sharedC? Because you written about c negative transforms while in your sample there are transforms for z... Understand it's just because in your setup you need transforms for z not appointment to me regarding c, right?

Mark

unread,
Jan 23, 2019, 4:10:44 AM1/23/19
to ope...@googlegroups.com
--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/openpnp/!%26!AAAAAAAAAAAYAAAAAAAAAIksy9bq9upCo/PrMujuDwDCgAAAEAAAAO5F35t394pGoyjNdhaep8kBAAAAAA%3D%3D%40makr.zone.

ma...@makr.zone

unread,
Jan 23, 2019, 4:15:58 AM1/23/19
to OpenPnP

Hi Marek

 

> Sorry for my ignorance, but what do home-coordinates 210 and 600 in your x/y and is this regarding C?! Or just it's the part of your setup regardless C?

 

Just ignore that. It's just copied from my machine.xml

I just wanted to show an example in the context. It's not final code, you can copy&paste, it's just to explain.

 

> I have 3 nozzle rotated with one motor into one direction. So understand I don't need transform section in C maping, right?

 

Correct.

 

> 3. You have underlighted "two Z". Why just two?

 

If you have 3 (any number of) nozzles then everywhere I said "2" just substitute with "3". And add z3 and c3 axes to the xml.

 

> What means ending s> in line <<axis name="c1" type="Rotation" <s>> ?

 

I don't know why but Google groups has deleted the rest of my email online. By email it was relayed correctly back to me.

 

I sent it to your PM and attached it as a file here for reference. EDIT: But that down't work either.

 

I'll try to put my full answer online here. I think it also explains the rest of your questions.

 

_Mark

 

 

ma...@makr.zone

unread,
Jan 23, 2019, 4:20:57 AM1/23/19
to OpenPnP
Re-entered online, because Google groups eats my emails. Edited some things to make them more clear:

Hi Marek

 

In my view it should work without modification if you use the „forced“ Variables. Including pre-rotation and the upcoming nozzle runout compensation!

 

But you need to modify the machine XML to have two or three or any number of Z and C Axes and then use Axis Mapping to map each Z/C axis to the respective nozzle. Plus force the MOVE_TO_COMMAND variables.

 

Depending on how the C axes are coupled you may need an Axis Transform to negate the rotation (if e.g. the axis are coupled by pinion) or leave it out if they rotate the same way (e.g. coupled by belt). Which of the C axes needs the transform (if any), also depends how the axes are mechanically coupled to the motor or how the motor phases are wired (i.e. which of the axes rotates the right way and which in reverse). The fragment below is just an example with two Z and C axes, when the second of two axis needs to be negated. Just adapt this example for three ore more axes.

 

I leave the AxisTransform for the Z axis to you, assuming it is shared too and you already have the right transform. Just split that up into two axes. The fragment below is just an example:

 

        <axes class="java.util.ArrayList">

            <axis name="x" type="X" home-coordinate="0.0">

               <head-mountable-ids class="java.util.HashSet">

                  <string>*</string>

               </head-mountable-ids>

            </axis>

            <axis name="y" type="Y" home-coordinate="0.0">

ma...@makr.zone

unread,
Jan 23, 2019, 4:22:04 AM1/23/19
to OpenPnP
The f**er just doesn't work.

Hope you got the personal Email.

_Mark

Marek T.

unread,
Jan 23, 2019, 5:43:23 AM1/23/19
to OpenPnP
Mark I was on the highway. See mail on gmail. Trying.
*F* I've meant in gcode of move_to not in axis declaration.
I must remove my fixes and will try it, modifying job.procesor abot it just now.
Z I don't use motors in main driver.
Will come back soon.

Marek T.

unread,
Jan 23, 2019, 6:45:42 AM1/23/19
to OpenPnP
Mark,

I'm using Z of Smoothie to rotate shared axes. That's why Z is declared Rotation. Generally Z (in meaning nozzles up/down control) is not made with Smoothie (subdriver) but Driver only - and this works good for me.
I'm using two controllers. Main driver is used to control different actuators and also to check before the move whether the nozzles are up. The motion XYRotation is made within sub-controller (smoothie).
I'm not sure if following maping for driver and subdriver is good in this case? Transforms I don't need, everything rotated into one direction.



               <sub-drivers class="java.util.ArrayList"/>

               <axes class="java.util.ArrayList">
                  <axis name="x" type="X" home-coordinate="0.0">
                     <head-mountable-ids class="java.util.HashSet">
                        <string>*</string>
                     </head-mountable-ids>
                  </axis>
                  <axis name="y" type="Y" home-coordinate="0.0">
                     <head-mountable-ids class="java.util.HashSet">
                        <string>*</string>
                     </head-mountable-ids>
                  </axis>
                  <axis name="c" type="Z" home-coordinate="0.0">

                     <head-mountable-ids class="java.util.HashSet">
                        <string>N1</string>
                        <string>N2</string>
                        <string>N3</string>
                     </head-mountable-ids>
                  </axis>
                  <axis name="z1" type="Rotation" home-coordinate="0.0">

                     <head-mountable-ids class="java.util.HashSet">
                        <string>N1</string>
                     </head-mountable-ids>
                  </axis>
                  <axis name="z2" type="Rotation" home-coordinate="0.0">

                     <head-mountable-ids class="java.util.HashSet">
                        <string>N2</string>
                     </head-mountable-ids>
                  </axis>
                  <axis name="z3" type="Rotation" home-coordinate="0.0">
                     <head-mountable-ids class="java.util.HashSet">
                        <string>N3</string>
                     </head-mountable-ids>
                  </axis>
               </axes>
            </gcode-driver>
         </sub-drivers>

         <axes class="java.util.ArrayList">
            <axis name="x" type="X" home-coordinate="0.0">
               <head-mountable-ids class="java.util.HashSet">
                  <string>*</string>
               </head-mountable-ids>
            </axis>
            <axis name="y" type="Y" home-coordinate="0.0">
               <head-mountable-ids class="java.util.HashSet">
                  <string>*</string>
               </head-mountable-ids>
            </axis>
            <axis name="z1" type="Rotation" home-coordinate="0.0">

               <head-mountable-ids class="java.util.HashSet">
                  <string>N1</string>
               </head-mountable-ids>
            </axis>
            <axis name="z2" type="Rotation" home-coordinate="0.0">

               <head-mountable-ids class="java.util.HashSet">
                  <string>N2</string>
               </head-mountable-ids>
            </axis>
            <axis name="z3" type="Rotation" home-coordinate="0.0">
               <head-mountable-ids class="java.util.HashSet">
                  <string>N3</string>
               </head-mountable-ids>
            </axis>
         </axes>
      </driver>

?

Marek T.

unread,
Jan 23, 2019, 6:54:31 AM1/23/19
to OpenPnP
Without prerotation it works well.
With prerotation it generates a lot of extra rotations. You can see this i.e after
2019-01-23 12:30:01.119 Scripting TRACE: Scripting.on Job.Placement.Complete
and before
2019-01-23 12:30:02.509 ReferencePnpJobProcessor INFO: Job finished 1 parts in 13.2 sec. This is 272.9 pph.  Skipped %s parts.
all these rotations there are for nothing.
I don't know is it because of my maping or not. With and wothout the prerotation it looks the same. Generaly C-sharing works and prerotation works. Issue are these extra rotations near almost each (or each) xy movement. See log.
mark_log.txt

Marek T.

unread,
Jan 23, 2019, 6:56:17 AM1/23/19
to OpenPnP
Sorry - correction: with and without prerotation I get these extra rotations.

Jason von Nieda

unread,
Jan 23, 2019, 9:44:41 AM1/23/19
to ope...@googlegroups.com
Pre-rotate bottom vision still doesn't work, by default, with shared C. Maybe the forced variables fix that, but I haven't thought all the way through it. As far as I know that's the main issue with shared C.

Jason



--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.

Marek T.

unread,
Jan 23, 2019, 11:31:59 AM1/23/19
to OpenPnP
If I do a maping like MAP-A pre-rotation does not work. It means the placement angle is not restored before placing.
If I do MAP-B pre-rotation seems work but machine makes a lot of C homings while the job and this is not to use for me - it eats too much time in total.

MAP-A:
              <axis name="c" type="Rotation" home-coordinate="0.0">
               <head-mountable-ids class="java.util.HashSet">
                  <string>N1</string>
                  <string>N2</string>
                  <string>N3</string>
               </head-mountable-ids>
            </axis>
         </axes>
      </driver>

MAPB:
                   <axis name="c1" type="Rotation" home-coordinate="0.0">
                     <head-mountable-ids class="java.util.HashSet">
                        <string>N1</string>
                        </head-mountable-ids>
                  </axis>
               </axes>
            </gcode-driver>
         </sub-drivers>
                  <axis name="c2" type="Rotation" home-coordinate="0.0">
                     <head-mountable-ids class="java.util.HashSet">
                        <string>N2</string>
                     </head-mountable-ids>
                  </axis>
               </axes>
            </gcode-driver>
         </sub-drivers>
                  <axis name="c3" type="Rotation" home-coordinate="0.0">

Mark

unread,
Jan 23, 2019, 12:55:42 PM1/23/19
to ope...@googlegroups.com

Hi Marek

 

I fear the moveToSafeZ() on the head is the culprit for the unnecessary moves. It enumerates all HeadMountables attached to itself and moves them to safe Z. Now because the rotation axes are forced, even if Rotation is given as NaN (i.e. “do not change”), they are each output in sequence, in turn restoring their separately stored C resulting in these unnecessary rotations.

 

    @Override

    public void moveToSafeZ(double speed) throws Exception {

        for (Nozzle nozzle : nozzles) {

            nozzle.moveToSafeZ(speed);

        }

        for (Camera camera : cameras) {

            camera.moveToSafeZ(speed);

        }

        for (Actuator actuator : actuators) {

            actuator.moveToSafeZ(speed);

        }

        for (PasteDispenser dispenser : pasteDispensers) {

            dispenser.moveToSafeZ(speed);

        }

    }

https://github.com/openpnp/openpnp/blob/5131a7483863394f55ce70249cff3a145bfed80e/src/main/java/org/openpnp/spi/base/AbstractHead.java#L161

 

Unfortunately OpenPNP does not make a difference between

a)      “do not change because it doesn’t matter” such as in moveToSafeZ()

b)      “do not change to preserve the correct angle set before” such as with pre-rotate.

 

To work correctly with shared C axes we need to force-move the rotation axis in case of b) for pre-rotate and other situations where a nozzle has been rotated before.  

 

Sorry, this enumeration is a problem I did not anticipate. It works, yes, but it is slow. :-(

 

Somehow we need to be able to distinguish between a) and b).

 

@Jason, if I understand correctly then a moveToSafeZ() can be safely detected inside moveTo() when X, Y, C all are NaN and Z == hm.safeZ. I don’t see any other situation when a call to moveTo() has this signature.

 

Would it be an awful hack to deactivate the forced variables (except “ZF” of course) when this signature is detected?

 

The change would only affect machines that use forced variables in the first place so it would be benign for all the other machines. I would need to add a getSafeZ()to the HeadMountable interface, though. Is that a problem?

 

 

@Marek, regardless of the above I don’t fully understand your machine…

 

1.       How do you move the three Z axes individually?

2.       In the log I don’t see how the X and Y (and Z) is actually moved with COM5. How?

 

 

_Mark

 

 

 

 

Von: ope...@googlegroups.com [mailto:ope...@googlegroups.com] Im Auftrag von Marek T.
Gesendet: Mittwoch, 23. Januar 2019 12:46
An: OpenPnP
Betreff: Re: [OpenPnP] Re: Fixing Shared C and Pre-Rotate

 

Mark,

--

You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.

bert shivaan

unread,
Jan 23, 2019, 1:05:28 PM1/23/19
to ope...@googlegroups.com
Hi Mark, I am following this closely as I will need to have shared C if I get my machine up and running. Marek uses pneumatic actuators for his nozzle up and down as do I.

So he can move them by simply firing a valve.

I would live to see a way to disable the move to safe z globally through a check box or something in the job processor tab maybe. I have disabled it in my own version, but it is somewhat of a hack to be sure.

Marek T.

unread,
Jan 23, 2019, 1:25:24 PM1/23/19
to OpenPnP
Hi Mark,
As Bert said I control up/down nozzles by valves actuators. It is separated my controller not the same that controls xy and rotation (Smoothie).
Additionally I have a mechanism connecting z arrows with actuators. So if I press Z down below -3 it also fires for me valve actuator to true (nozzle down) and if arrow up above -2 it sets this actuator false (nozzle up). So I can control vertical nozzles move both using actuators on/off or arrows z up/down (in fact also actuators). Art of CriS.

Mark

unread,
Jan 24, 2019, 8:25:25 AM1/24/19
to ope...@googlegroups.com
Hi Marek

can you build OpenPNP yourself?

I would be very thankful if you could test this PR:
https://github.com/openpnp/openpnp/pull/809

It should fix the unnecessary moves.

_Mark


-----Ursprüngliche Nachricht-----
Von: ope...@googlegroups.com [mailto:ope...@googlegroups.com] Im Auftrag von Marek T.
Gesendet: Mittwoch, 23. Januar 2019 19:25
An: OpenPnP
Betreff: Re: [OpenPnP] Re: Fixing Shared C and Pre-Rotate

Hi Mark,
As Bert said I control up/down nozzles by valves actuators. It is separated my controller not the same that controls xy and rotation (Smoothie).
Additionally I have a mechanism connecting z arrows with actuators. So if I press Z down below -3 it also fires for me valve actuator to true (nozzle down) and if arrow up above -2 it sets this actuator false (nozzle up). So I can control vertical nozzles move both using actuators on/off or arrows z up/down (in fact also actuators). Art of CriS.

--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/openpnp/c8d2c2ec-35ee-442c-85aa-8bf01bd3683e%40googlegroups.com.

Marek T.

unread,
Jan 24, 2019, 9:11:05 AM1/24/19
to OpenPnP
Hi Mark,
Sure, no problem to build it but the test rather on Monday.
Tomorrow I have no access to machine for experiments as some urgent assembling we have to close tomorrow.

Jason von Nieda

unread,
Jan 24, 2019, 11:01:12 AM1/24/19
to ope...@googlegroups.com
Hi Mark and Marek,

I'd like to ask that you consider a different solution to this problem, for a couple reasons:

1. NaN / "don't move this axis" is going away: https://github.com/openpnp/openpnp/issues/255
2. This PR fixes a symptom, but not the problem. This is also true of the previous PR that added the forced variables.

The real issue is that pre-rotate bottom vision was not designed with shared C in mind. I analyzed this bug in https://groups.google.com/forum/#!msg/openpnp/9rb52Ip628c/rz-37M_4CwAJ and explained what needs to be done to fix it.

In short, we need to return the rotation value along with the bottom vision data so that the job processor has the opportunity to rotate back to where it needs to be if the angle has changed. If the job processor sends a rotation command to the motion controller and the motion controller is already at that position, no movement happens and pre-rotate still works fine for non shared C.

I'm not comfortable with a situation where OpenPnP doesn't know the position of an object. The system is designed with the concept that HeadMountable.getLocation() is always correct. I don't want to go further down the path of breaking that contract.

So, if you'd like to spend time fixing this problem, please consider spending that time fixing the bottom vision issue rather than the symptom.

Jason


--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.

Marek T.

unread,
Jan 24, 2019, 11:24:49 AM1/24/19
to OpenPnP
I am only the tester :-).

I have sharedC fixed and working for me (again as usually in my case, it is rather not solution being universal).
I came back to this thread only because of some other issue (not occuring on Michael.G machine) which forced me to move back with my customizations and to check wheter the patch of my sharedC is not the reason. This way I came to this point...

to I have and wanted to check all the possibilities can do this.

Mark

unread,
Jan 24, 2019, 3:22:36 PM1/24/19
to ope...@googlegroups.com

Hi Jason

 

I don’t want to question your judgment just to present my reasoning, here. Also English is a foreign language so if some of this doesn’t always sound very diplomatic, please bear with me. :-)

 

I agree that properly solving pre-rotate would certainly be a good thing. However I’ve looked at it some weeks ago and found no straight-forward solution. I guess it would have been solved a long time ago if it was very easy. :-]

 

But aside from pre-rotate are you sure this is the only issue here?

 

I for one use Z probing which will stop the probe at an unknown position. Unless Z-probing is implemented in OpenPNP (reading back current coordinates, including reverse transformations), this creates a situation where OpenPNP doesn’t know where the Machine is. The same is true for relative moves that I use for vacuum sensing, because a) I used Z-probing before so I don’t know where Z is at the moment and b) I need to retract the tip a tiny bit for a meaningful vacuum level reading (if the tip is still pressing down on the part it is not very meaningful, neither in the pick nor in the place). OpenPNP does not (to my knowledge) currently support that natively.

 

On the other hand the possibility to define custom Gcode (including through scripts) opens up these and many other possibilities and I strongly believe this is one of the features that make OpenPNP so great and so universal!

 

These examples are only for my machine. I can imagine there are many similar realistic demands that will create situations when a machine is not where OpenPNP thinks it is. I would argue that as long as OpenPNP does not implement and enforce safety features such as no-go areas, soft limits etc. there is no valid reason for OpenPNP to restrict or forbid these possibilities and artificially shackle itself by adhering to such a contract.

 

The important part here is that nobody is forced to use these possibilities. If you don’t use the “F” variables, nothing changes.

 

With https://github.com/openpnp/openpnp/issues/255 already open for two years, and so many places where NaN and/or getLocation() are used I fear the underlying issue is not going away soon.

 

Frankly I’m not even sure if it is really a good idea to get rid of the NaNs. Im my opinion it is a good thing to be able communicate if you don’t care about a coordinate. If you think about motion path blending in the future, partial-NaN waypoints could be very valuable for blending.

https://youtu.be/csFE-4XwaYE 

 

So I humbly ask for you to still consider merging the PR after Marek T. has tested it successfully.

 :-D

 

_Mark

 

 

Von: ope...@googlegroups.com [mailto:ope...@googlegroups.com] Im Auftrag von Jason von Nieda
Gesendet: Donnerstag, 24. Januar 2019 17:01
An: ope...@googlegroups.com
Betreff: Re: [OpenPnP] Re: Fixing Shared C and Pre-Rotate

 

Hi Mark and Marek,

Marek T.

unread,
Jan 24, 2019, 4:17:53 PM1/24/19
to OpenPnP
Hmmmm, this nozzle is interresting... do you know what is it?

Jason von Nieda

unread,
Jan 24, 2019, 10:48:52 PM1/24/19
to ope...@googlegroups.com
Hi Mark,


On Thu, Jan 24, 2019 at 2:22 PM Mark <ma...@makr.zone> wrote:

Hi Jason

 

I don’t want to question your judgment just to present my reasoning, here. Also English is a foreign language so if some of this doesn’t always sound very diplomatic, please bear with me. :-)

 

I agree that properly solving pre-rotate would certainly be a good thing. However I’ve looked at it some weeks ago and found no straight-forward solution. I guess it would have been solved a long time ago if it was very easy. :-]


I do think it's pretty easy to fix. It hasn't been fixed yet primarily because it only affects 1 user that I know of, and that user (Marek) already has a fix in place.

See the comments on https://github.com/openpnp/openpnp/commit/ed9b6d603d9d8a1dfc7f0cb816ef06cac7058ccb to see my thoughts on how it can be fixed.
 

 

But aside from pre-rotate are you sure this is the only issue here?

 

I for one use Z probing which will stop the probe at an unknown position. Unless Z-probing is implemented in OpenPNP (reading back current coordinates, including reverse transformations), this creates a situation where OpenPNP doesn’t know where the Machine is. The same is true for relative moves that I use for vacuum sensing, because a) I used Z-probing before so I don’t know where Z is at the moment and b) I need to retract the tip a tiny bit for a meaningful vacuum level reading (if the tip is still pressing down on the part it is not very meaningful, neither in the pick nor in the place). OpenPNP does not (to my knowledge) currently support that natively.


OpenPnP / GcodeDriver already has the ability to respond to out of band movements and already applies reverse transformations: https://github.com/openpnp/openpnp/wiki/GcodeDriver#position_report_regex

This system is supported end to end, so that DROs and all other state gets updated. You can use this very simply by adding an M114 to the end of your Gcode chain. This will update OpenPnP with the machine's current position: http://smoothieware.org/supported-g-codes

If this doesn't work for you, I'd like to know why so that we can look at improving the feature or fixing bugs in it.

 

On the other hand the possibility to define custom Gcode (including through scripts) opens up these and many other possibilities and I strongly believe this is one of the features that make OpenPNP so great and so universal!

 

These examples are only for my machine. I can imagine there are many similar realistic demands that will create situations when a machine is not where OpenPNP thinks it is. I would argue that as long as OpenPNP does not implement and enforce safety features such as no-go areas, soft limits etc. there is no valid reason for OpenPNP to restrict or forbid these possibilities and artificially shackle itself by adhering to such a contract.


Soft limits are 4th on my TODO list. See below :)

 

The important part here is that nobody is forced to use these possibilities. If you don’t use the “F” variables, nothing changes.

 

With https://github.com/openpnp/openpnp/issues/255 already open for two years, and so many places where NaN and/or getLocation() are used I fear the underlying issue is not going away soon.


It is in fact going away soon. Removing this NaN mess is currently third on my TODO list. In case you are curious, that list is:

OpenPnP Important Architectural Changes
---------------------------------------------------------
* Camera system path cleanup
    * Preview and capture are different
    * FPS more clearly defined
    * Get rid of "show multiple" entirely. Pick one, and that is the one that is calling capture.
    * Break all the combined properties panels in the config wizard into different panels.
* Camera lighting first class
    * How to handle per part lighting scenarios
    * Maybe add specific Lighting scripts?
    * And maybe a ScriptActuator?
* Remove NAN
* Machine extents
* Head offsets first class and out of driver
    * This lets us better handle extents
* Remove VisionProvider

NaN is really not used in very many places at all. I've already removed it from most of the areas of concern. The search you provided shows this. 2 of the 9 locations are just documenting the issue. Another 2 are in dead code. 1 is the exact bottom vision issue we're talking about. This leaves a small handful of changes and we'll be done.

 

Frankly I’m not even sure if it is really a good idea to get rid of the NaNs. Im my opinion it is a good thing to be able communicate if you don’t care about a coordinate. If you think about motion path blending in the future, partial-NaN waypoints could be very valuable for blending.

https://youtu.be/csFE-4XwaYE 


I don't really think there is any limitation here. There's effectively no difference between sending G0 X10 Y10, G0 X10 Y20 and G0 X10 Y10, G0 Y20 and the driver can choose not to send the additional coordinate if it knows it's already there. NaN was added as a shortcut in the very early days of OpenPnP before I had the ability to ask the driver what it's coordinates were. Keeping it adds complexity to every driver and makes the code harder to reason about.

 

So I humbly ask for you to still consider merging the PR after Marek T. has tested it successfully.

 :-D


Sorry, I won't merge this one. I firmly believe it's the wrong approach to fixing the issue. I'm not going to add more technical debt for the sake of a quick fix.

Again, if this is important to you, please consider spending your time fixing the real issue.

Thanks,
Jason

bert shivaan

unread,
Jan 24, 2019, 10:53:31 PM1/24/19
to ope...@googlegroups.com
i also have shared c for 6 nozzles. I hope to get running in the next month. For now my plan is just to use a single nozzle unless I don't need pre rotate

--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.

Marek T.

unread,
Jan 25, 2019, 2:11:10 AM1/25/19
to OpenPnP
Without prerotate forced variables works well for sharedC.
I can also give you the patch I have working with and without it, for your machine it will work too (is similar to my one). It's six lines to jobProcessor.

Mark

unread,
Jan 25, 2019, 3:23:00 AM1/25/19
to ope...@googlegroups.com

Thanks Jason for these insights. They explain a lot. I will certainly follow up on the M114.

 

I just disagree with one statement:

 

> There's effectively no difference between sending G0 X10 Y10, G0 X10 Y20 and G0 X10 Y10, G0 Y20 and the driver can choose not to send the additional coordinate if it knows it's already there.

 

Artificially over-defining the waypoints does hurt possible path blending. You can then not distinguish between waypoints where you really want e.g. C to be at 0° and those where you actually don’t care.

 

I think the problem becomes painfully clear when watching this video:

https://www.youtube.com/watch?v=nBnfRhdnPks

 

Yes the rotation speed could probably be increased for that machine, but still OpenPNP wastes precious time not rotating the nozzle while travelling to the feeder pickup location.

 

The simplest form of motion path blending (queuing motion path waypoints and optimizing them before actually sending them to the machine) could automatically improve that in the future if – and only if – the waypoint on top of the feeder, before rotation is applied, has a NaN for C.

 

And that’s just one example. It would work on all path segments in all combinations of multiple nozzles, shared axes, nozzle change needed or not, top/bottom vision or not, pre-rotation or not, etc. including future extensions and customizations. Rotation is the simplest to blend as it hardly has potential for collisions but there is also room for the other axes.

 

If you wanted to achieve the same level of optimization by hand-tuning fully deterministic motion (i.e. no NaNs) you would constantly have to anticipate the next N steps in advance! IMHO you will likely fail and make the code unreadable/unmaintainable while trying.

 

If you doubt such motion path blending can be achieved, I’d like to point to the heuristics I drafted to do exactly that:

https://groups.google.com/d/msg/openpnp/JfxgCxR2rGc/QFM1afHQEAAJ

It could even be improved by the

waitForMovesToComplete()

method you then suggested in reply to that.

 

It may take a while but I haven’t given up on all that yet :-)

 

_Mark

 

Von: ope...@googlegroups.com [mailto:ope...@googlegroups.com] Im Auftrag von Jason von Nieda
Gesendet: Freitag, 25. Januar 2019 04:49
An: ope...@googlegroups.com
Betreff: Re: [OpenPnP] Re: Fixing Shared C and Pre-Rotate

 

Hi Mark,

--

You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.

Jason von Nieda

unread,
Jan 25, 2019, 2:17:50 PM1/25/19
to ope...@googlegroups.com

> There's effectively no difference between sending G0 X10 Y10, G0 X10 Y20 and G0 X10 Y10, G0 Y20 and the driver can choose not to send the additional coordinate if

Artificially over-defining the waypoints does hurt possible path blending. You can then not distinguish between waypoints where you really want e.g. C to be at 0° and those where you actually don’t care.

 

I think the problem becomes painfully clear when watching this video:

https://www.youtube.com/watch?v=nBnfRhdnPks

 

Yes the rotation speed could probably be increased for that machine, but still OpenPNP wastes precious time not rotating the nozzle while travelling to the feeder pickup location.


I think what you are seeing here is rotation on a sub-driver, not "not rotating the nozzle while travelling to the feeder pickup location". OpenPnP does send rotation when traveling to a pick location: https://github.com/openpnp/openpnp/blob/develop/src/main/java/org/openpnp/machine/reference/ReferencePnpJobProcessor.java#L647

The issue here is that sub-driver commands are sent consecutively, rather than synchronously, and that is something I do think we can improve. Probably as simply as firing off the commands to the sub-drivers in a thread and waiting for each to complete before returning.

Jason

Marek T.

unread,
Jan 25, 2019, 3:11:17 PM1/25/19
to OpenPnP
Is this rotation not just driven from motor being extruder which is not synchronized by motion controller with axes XYZ but after them?

Jason von Nieda

unread,
Jan 25, 2019, 3:12:53 PM1/25/19
to ope...@googlegroups.com
Yes, could be that too. I'm not sure how Bernd's machine is set up. But in either case, rotation is sent to the driver. The driver or controller just isn't performing it simultaneously.

Jason


On Fri, Jan 25, 2019 at 2:11 PM Marek T. <marek.tw...@gmail.com> wrote:
Is this rotation not just driven from motor being extruder which is not synchronized by motion controller with axes XYZ but after them?

--
You received this message because you are subscribed to the Google Groups "OpenPnP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openpnp+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.

Marek T.

unread,
Jan 25, 2019, 3:31:07 PM1/25/19
to OpenPnP
In my setup where sharedC rotation is connected to Z output of Smoothie, XY and Rotation axes achieve final position in the same moment, with speed slowed down to the slowest motor properties (my sharedC).

I think it's quite typical setup that people use XY as synchronized axes and every C motors connected to extruders outputs which number in Smoothie is unlimited (this I'm not sure but think so).

Mark

unread,
Jan 26, 2019, 4:09:43 AM1/26/19
to ope...@googlegroups.com
> Is this rotation not just driven from motor being extruder which is not synchronized by motion controller with axes XYZ but after them?

No, extruders must very much be coordinated with other axes. Imagine what would happen otherwise while 3D printing :-)

> The issue here is that sub-driver commands are sent consecutively, rather than synchronously, and that is something I do think we can improve.

OK, I see. I assume there are many other cases but I lost my smoking gun.

I conclude you also do not agree in principle that being able to specify "don't care" waypoints could be a good thing after all.

_m

Marek T.

unread,
Jan 26, 2019, 6:05:51 AM1/26/19
to OpenPnP
"By default, Smoothie calculates distances only on the first three ( XYZ ) axes. You can change this behavior by setting the PAXIS compilation parameter".

So in your opinion (I'm not saying you're not right), by default Smoothie calculates distances for PAXIX axes group AND for all extruder outputs?

Mark

unread,
Jan 26, 2019, 7:38:08 AM1/26/19
to ope...@googlegroups.com

Hi Marek

 

the distance is only of concern in relation to how feedrates are calculated. You know the F parameter in a G0 / G1 command.

http://smoothieware.org/g1

 

If you tell it to use a F100 feedrate, it means 100mm/minute along the distance travelled in X, Y, Z.

https://en.wikipedia.org/wiki/Euclidean_distance

In this so-called Euclidean Distance the E (extrusion) should of course not be counted in the federate and that is the default for Smoothieare.

 

The same is true for the rotational axes we use for PNP and other machines use for rotating tools and/or the workpiece.

 

See NIST RS274NGC Interpreter - Version 3, Section 2.1.2.5 rule A:

 

    A. For motion involving one or more of the X, Y, and Z axes (with or without simultaneous

    rotational axis motion), the feed rate means length units per minute along the

    programmed XYZ path, as if the rotational axes were not moving.

 

    B. For motion of one rotational axis with X, Y, and Z axes not moving, the feed rate means

    degrees per minute rotation of the rotational axis.

 

    C. For motion of two or three rotational axes with X, Y, and Z axes not moving, the rate is

    applied as follows. Let dA, dB, and dC be the angles in degrees through which the A, B,

    and C axes, respectively, must move. Let D = . Conceptually, D is a

    measure of total angular motion, using the usual Euclidean metric. Let T be the amount

    of time required to move through D degrees at the current feed rate in degrees per

    minute. The rotational axes should be moved in coordinated linear motion so that the

    elapsed time from the start to the end of the motion is T plus any time required for

    acceleration or deceleration.

 

https://www.nist.gov/publications/nist-rs274ngc-interpreter-version-3

 

Now if for instance you have two physical axes Z1 and Z2 on your PNP machine, you must recompile the Smoothieware firmware with PAXIS=4 in order to have both Z axes counted in the Euclidean Distance. Otherwise feedrates might not be properly limited in moves where Z2 is moved together with X and/or Y. If you have only a small move in X together with a large move in Z2, the Z2 stepper might actually stall, because acceleration is then only calculated for the very small X move, not for the Z2 move, resulting in a very small motion time in which Z2 is overwhelmed. Actually a bug in Smoothieware, that I tried to fix without success.

 

Even without all the theory it is obvious that the extrusion rate and the nozzle speed in 3D space (federate) must be carefully coordinated. The extrusion controls how fast the material is extruded from the nozzle, i.e. how fast the molten plastic worm is pushed out of the nozzle. In order to have nice constant buildup of the layers, extrusion must be closely matched to the federate otherwise the worm would sometimes be blobbed together and sometime be stretched too thin.

 

_Mark

 

-----Ursprüngliche Nachricht-----
Von: ope...@googlegroups.com [mailto:ope...@googlegroups.com] Im Auftrag von Marek T.
Gesendet: Samstag, 26. Januar 2019 12:06
An: OpenPnP
Betreff: AW: [OpenPnP] Re: Fixing Shared C and Pre-Rotate

Reply all
Reply to author
Forward
0 new messages