terjeio / GRBL_MPG_DRO_BoosterPack

Tiva C BoosterPack for GRBL MPG/DRO
43 stars 20 forks source link

3 or 4 wheels #2

Closed jschoch closed 4 years ago

jschoch commented 5 years ago

I'm working on a similar project but with 3 or 4 wheels. STM32 can support 4 hardware quadrature pulse counters. Wondering if this is something you have considered? Also wondering how the physical interface is to use with your layout. Any lessons learned on the physical UI?

terjeio commented 5 years ago

Not sure what you mean, but I will try to answer. I have not considered using STM32 processors, I mainly work with Texas Instrument processors. However, I try to write my code in a layered manner so that hardware dependencies are implemented in separate files from the main application - as a HAL (Hardware Abstraction Layer). This allows for clean porting to different platforms. If you meant support for more than 2 wheels then I have not considered that but it should be fairly easy to add to my code. It could also be done by a single wheel and an axis selector switch.

Again, not sure what you mean by lessons learned from the physical UI - you mean the complete layout with the LCD, MPG wheels, menu navigator and buttons? If so then I am happy with it as it is aimed at controlling my small lathe. It would be nice to have a complete numerical keypad for data entry - but that would result in a much larger device. So I decided to use a MPG wheel in combination with the jog buttons and meny navigator for data entry to keep the size down. One issue on my todo list is to change the input fields for numerical values to right justified - I need to update the UI library for that. The LCD is touch sensitive and the UI library supports touch input, currently this is not enabled in my code, I will add that it later to see how it works out as an alternative to the menu navigator.

jschoch commented 5 years ago

This helps. I made a bad assumption you were using this for a mill style machine.

I want to have X, Y, Z, and Feed jog wheels all available. X would be "front", Y "right", Z "top", and "feed" left laid out on a cube.

I was also asking about your hardware input device layout, how you like it, and what lessons you learned designing it. Sounds like you are pleased with the physical input layout for a lathe. Could you use it for a mill?

terjeio commented 5 years ago

Could you use it for a mill?

Short answer: the physical design, no - the software yes.

For a mill I think I would reduce the design to a single MPG wheel and an axis selector switch - I believe this is the most common configuration for mills. But then your use-case may be different.

I like the jog buttons so I would add two for the Z-axis as I have done for my CO2-laser. The keyboard scanning code supports two-key rollover which I use for jogging X and Y simultaneously.

Perhaps a numeric keypad for data entry would be more useful than three MPG wheels? Depends on how advanced and easy-to-use one wants the software to be.

Whatever the physical design chosen I believe the core software can, IMO, be easily adapted to support it.

Using a MPG wheel for feed is perhaps an overkill, when in DRO mode I use the menu navigator for adjusting the spindle RPM, it could be used for feed as well. Be aware that when turning the MPG wheels I do not issue jog commands - I prefer to issue G1 commands with feed rate proportional to the turning speed to move the axes to the exact position as indicated by the wheel dial or the DRO. When turning the wheels the DRO position changes color to indicate target position is shown, not the current as reported by Grbl.

jschoch commented 5 years ago

I'm currently considering 2 jog modes.

The first will wait for a jog to complete before issuing another. If the wheel is still turning this should be low latency. I could queue some based on the available space and step size and then issue a jog cancel when the wheel stops turning. I'm not sure how responsive it will be operating in single steps. I would prefer to avoid crashes and I have had issues with a sender queuing up to many jogs. I planned on having a rapid key modifier which would set a larger step size while the "rapid" key is held. One problem I am seeing is that I can't tell if an "ok" from grbl is for the command I issued especially if the sender is polling with "?"

The 2nd mode I was considering was a set and go mode. You'd dial in the distance you wanted to move in ABS or INC mode and then hit a "go" key.

I was also considering a "yo yo" mode which would allow you to go to a virtual stop and then come back with or without a stepover. The feed dial could be also used to set the stepover in this mode. This would be nice for semi-manual milling. I've seen a few videos of shapers which seem to have automated stepover settings.

I prefer to issue G1 commands with feed rate proportional to the turning speed

Do you mean the lathe spindle speed or the speed of the encoder wheel? If the encoder wheel, how do you calculate this?

I'm just about ready to start testing a physical layout and your feedback may save from going down the wrong path.

terjeio commented 5 years ago

I use short key presses on the "Home key" in the center of the jog buttons to toggle between fast, slow and step mode jogging. In my GCode sender I use and as jog modifiers in a similar way. Since I have (IMO) fixed the jog cancel "bug" I issue "long" jog commands in fast and slow modes and relies on the jog cancel command to terminate a running jog movement. This means that I do not rely on any feedback other than the current state for the action taken.

For the G1 commands I rely on the speed of the MPG wheel to calculate the feed rate - I get the velocity from a register in the processor. The formula to calulate the feed rate can be found in the source code (canvas/dro.c and mpg.c). The way I handle the MPG input is in a way a "set and go" mode as you describe it - in an interactive way. The target position is displayed in the DRO while a wheel is turned - also the dial (or scale?) on the wheel may be used, there is a button for aligning this dial with the DRO display.

Perhaps this video snippet may shed some light on how it works?

jschoch commented 5 years ago

The colored position is the cumulative target? Did you consider displaying both current and target? If so why did you choose a single position display?

Sorry for the questions, let me know if you would prefer me to ask them in a different medium.

terjeio commented 5 years ago

The colored position is the cumulative target?

I guess you can say so, it is the absolute position where the controlled point (the tool) will stop if one stop turning the handwheel. It is still early days for me in terms of usage, so far I like to look at the DRO for approaching the target and then often the dial markings (or whatever they are called for) on the wheels for the final adjustment. I have started to write some canvases (or screens) for data entry for some simple tasks, I guess that is nice to have for better surface finish and, for a mill, stuff that is hard/impossible to do manually but not complicated enough to warrant making a proper Gcode program.

Did you consider displaying both current and target?

Could do but so far I did not feel I need it, it is also a question of available screen real estate and avoiding clutter in the display. Also at x1 mode the controlled point does not lag much behind - turning a MPG wheel is kind of similar to turning a physical handwheel (that is my design aim). That said, I am no machinist - I am an electronics engineer/programmer making CNC stuff as a hobby so what do I know... The nice thing about making my own design and writing the code is that I can change stuff to my liking :-)

If so why did you choose a single position display?

See above, may well change it later as the data is a few display calls away.

Having this discussion here is no problem for me, I - and others - may learn something from the discussion as well.

jschoch commented 5 years ago

I finally hooked up my hardware up to my cnc mill and wow does it have noise/bounce issues. I see you have a debounce timer, did you use any rc filters on your board? How'd your encoders do with respect to noise? My first attempt was with EC12 encoders which have 24 detents and the datasheet says they have max noise/bounce of 3ms. I also have some pretty nice optical encoders which are 600ppr and likely way overkill. I wonder how much better these will do compared to the mechanical encoders?

terjeio commented 5 years ago

MPG wheels: bounce (if any) not an issue, I guess the QEI module in the processor takes care of any since I have enabled filtering by calling QEIFilterEnable. I have not tried with filtering disabled.

Menu navigator encoder: bounces badly - added software debounce to fix that. RC-filters should help but I did not add them, slow opto-couplers can also act as debouncers. I have used MAX6816 for debouncing input to a CPLD in another project - a bit expensive but reliable, perhaps debounce duration is too long for an encoder? MAX6817 is the dual input version.

Optical encoders should IMO produce a clean signal, but may still cause bounce if the inputs are not schmitt triggered. Output from a optical encoder may in fact be considered analog if output is not preconditioned to be digital. Digital in this context meaning the output having a constant rise/fall time regardless of speed.

jschoch commented 5 years ago

thanks for the response again.

I'm way down the rabbit hole on this now. I thought it would be much simpler but i'm learning a lot.

Right now i'm stuck deciding how to handle state transitions. I think your code will calculate the delta to the target position and wait for that position to allow more input from the encoders. Did you consider issuing the jog and then watching the states transition Idle -> Jog -> Idle? I can see a possibility where I miss a transition and then never can accept new jog inputs.

I suppose the only reason not to calculate the target position is some small saving in that calculation, perhaps I need to track these transitions to fully utilize CMD_JOG_CANCEL, but now that i'm thinking though the state transition monitoring I can't see any good reason it would be better with open loop control. For closed loop there may be some reason you'd never get to the target position. Wondering what your thinking was on when to block additional jog inputs.

I also generalized your grblcomm stuff into an arduino library here: https://github.com/jschoch/grbl_chat

I'm quite the terrible c/c++ programmer so I apologize if i've made some mistakes. I have commented out the parseFeedSpeed function since it hangs on some inputs and perhaps strrchr is better but I've not had time to dig into it and I don't yet need feedspeed parsed out.

terjeio commented 5 years ago

I issue "normal" G1 commands when movement is commanded via the MPG wheels, not jog commands - so there is no jog cancel involved.

What may be hard to infer from my code is that it is completely event driven. The EventNullEvent trapped in canvasHandler() in dro.c will happen every 10mS, I use that to flag when the display should be updated and the mpg input should be checked. Currently the display update is set to 20 ticks (200ms) and mpg input to 10 ticks (100ms).

In my main() function you will see it ends with 3 calls in a while(true) loop, the those calls would go in the loop() function if the same approach was used for Arduino.

MPG_Move() thus gets called every 100ms, which gets MPG wheel positions from the QEI module and compares them to a local copy, if different the delta is computed and used for calculating the target position.

I do not rely on state transitions from grbl to handle MPG movement, as long as the wheels are turned I will issue G1 commands (every 100mS). A state change back to "normal" is when there was no change in MPG positions during the last 100mS period.

To be able to do this I need to set a reference position (current position from grbl, mpg_base), to update this I rely on a state change to Idle - see displayGrblData() where I call MPG_ResetPosition(). Also offset changes is taken care of as well as setting the reference position at startup.

How this could be adapted to issue jog commands instead in a good way I do not know. Do you just want to continue issuing jog commands until wheel movement stops and then issue a jog cancel? Or only cancel on a direction change?

As for the "bug" in parseFeedSpeed that is due to I change I have made to the real-time report, I have added a third parameter - the actual spindle speed. This one should work:

static void parseFeedSpeed (char *data)
{
    char *next;

    next = strchr(data, ',');
    *next++ = '\0';

    if(parseDecimal(&grbl_data.feed_rate, data))
        grbl_data.changed.feed = true;

    if(parseDecimal(&grbl_data.spindle.rpm_programmed, next))
        grbl_data.changed.rpm = true;

}

I hope this helps, if not just continue asking.

jschoch commented 5 years ago

thanks again, this is great feedback.

How this could be adapted to issue jog commands instead in a good way I do not know. Do you just > want to continue issuing jog commands until wheel movement stops and then issue a jog cancel? Or > only cancel on a direction change?

The two modes i'm considering are single step, and acceleration based "batch step". The latter might benefit from jog_cancel since I want to have the grbl planner accelerate based on the wheel velocity and time it has been turning. My idea was to mark the wheel turning with a flag when it starts turning and then if the wheel had been turning and stopped to issue the jog_cancel and to halt all other input to grbl. I see that folks try to just stop issuing more jog commands rather than trying to use CMD_JOG_CANCEL due to the potential race condition. I've not yet been able to get something that works smoothly and avoids odd states and I'm actually focused on getting the first cast working safely and atomically.

Right now I'm processing the encoder wheel updates very quickly (by mistake) and I likely am creating more problems for my self that way. The current version issues a "?" query after the jog and I notice that I can issue and receive "ok" for 2 or 3 jog commands before the state changes to a Jog state. reducing encoder wheel input polling time is a pretty easy way to get more control over things.

my next refactor will try to model things based on a finite state machine. I will pay closer attention to polling intervals and start to calculate target positions.