jes notes Index Gallery . 4th axis Blog ideas Micro-machining CNC milling machine Paint colours CNC Router Shaft passers Software ideas Stepper motor clock Toy ideas Watchmaking

2024-02-13

Last modified: 2024-02-14 07:42:35

< 2024-02-12 2024-02-14 >

Busy board

I started making a busy board for Lucy today:

The vertically-arranged doorknobs are sprung differently (top one not at all, middle one springs out, bottom one springs in). The four holes to the right of that are blind, through, countersunk, and counter-bored. There are 3x M12 nuts pressed into the board, and an M12 bolt on a string that can be screwed into the nuts. And there's a steel plate that magnetic stuff can stick to.

I still need to make 3 gears to go at the bottom left, and they'll operate a crank that slides something back and forth in the horizontal slot.

And I still need to make 8 slidey pieces for the "TTTT" bit at top left, which is isomorphic to the Amphipods puzzle from https://adventofcode.com/2021/day/23

The board is an offcut of kitchen panelling, it is MDF with some very high-quality paint on it (possibly it is laminated plastic rather than paint?). It cuts very well with the CNC router, I used a 6mm 2-flute down-cutting bit at 11000 rpm, 1000 mm/min, 3mm depth of cut, full slotting. Leaves very crisp edges.

Jog control

Overnight I had some thoughts on this, related to what I committed in https://github.com/jes/pugsender/commit/7995ffb28076a3a3f2dc39bacb8f845187605e6d

One problem is that if you are continuous jogging X and then you start continuous jogging Y, your Y movement doesn't actually begin until the pipeline of pending X movements has drained. And if the jog is cancelled and restarted, the movement is not at 45 degrees because the X axis already had built up a distant target but Y hasn't.

So instead of keeping a separate Target and IncrementalTarget, I should instead only keep one target, the incremental target, and I should make continuous jogging use relative movements.

The only reason to use absolute movements at all is so that I can resume the movement properly after cancelling it (e.g. because another axis needed its movement cancelling, and Grbl only gives you global cancel).

So I think the JogCommand() function would only return the un-met incremental jog targets, and the ticker function in jog.go would send relative jogs for the axes that are meant to move continuously.

Actually, having written that out, I see now why it wouldn't work. The incremental jog movements would block the pipeline so that the continuous jogs don't start happening until the incremental jogs are complete. Drat.

OK, new idea then: whenever a jog is cancelled, if the axis's Target is a continuous target rather than an incremental one, then simply reset Target to LastPos, that way all jogged axes will accumulate target at the same rate, so multi-axis jogging should always be at the correct angles.

Communicating Sequential Processes

My Go code in Pugsender is trash at the moment. It has lots of race conditions, the logic is confusing to follow, and it doesn't work very well.

Apparently the way you should do concurrency in Go is with "Communicating Sequential Processes".

I plan to read https://go.dev/blog/codelab-share and https://go.dev/blog/codelab-share to learn to do a better job.

But before reading those: I can't yet see how I can use this sort of technique to mediate access to the serial port. One obvious improvement would be to make a dedicated "writer" goroutine, which receives lines to write from a channel and writes them to the serial port, instead of every thread just randomly calling Command() and writing to the serial port directly. But beyond that, I think I still need both the UI thread and the serial reader thread to be able to access the fields in the Grbl struct directly, I don't see how one of them could be passing the reference to the Grbl struct to the other, without blocking anything.

Well I read the first and skimmed the second and I'm still none the wiser. I think obviously make a dedicated "writer" goroutine, also stop it from leaking the "ticker"-based goroutines in the even of disconnection/reconnection. Otherwise, maybe separate out the connection stuff from the machine state stuff, and have it send the machine state over the channel that signals a status update, so that when the GUI thread is reading the machine state it is reading a different object?

Also, is there a way to use something like channels for "pub/sub"? If nothing is reading from the status update channel, I wouldn't want that to block the reader, and also I don't see why 2 things shouldn't be able to read status updates.

< 2024-02-12 2024-02-14 >