Skip to content
Snippets Groups Projects
Jake's avatar
Jake Read authored
e7a82629
History

Network Stepper Motor Coordination

Oddly enough, the first thing we want to do with networked hardware is probably one of the most difficult. This is because of the differences between timescales that the network operates on (a packet originating in a high-level program takes on the order of 1ms to arrive at it's destination) and the timescale that stepping needs to (typically) occur on. I.E. for a stepper motor having 32 microsteps, with 200 steps per revolution, on a 16-tooth pulley having 2mm pitch, to travel at 400mm/s (fast as heck), we'll see 80k steps/s, corresponding to an inter-step period of 125us, so 100us is a good design target. What's more, to achieve coordinated motion at the resolution of these steps, we'll also want steps happening at different network endpoints to happen within the same time-domain so, in order to do this effectively, we either need a clever algorithm and to be OK with some error, or we need some method for synchronizing clocks across the network.

Solving this problem is more or less what I'll be documenting through this project.

tiny-machine

big-machine

Current Progress

Works, now adding realtime clock syncronization.

Layers!

Here's a video of all of the layers chatting with eachother, where I'm sending serial commands to the network using a socket server and mods

video

screenshot

Beginner Acceleration Planning

The first thing I have to do before running network steppers is to write an algorithm for planning the motions that each motor will make. There are a number of ways to slice this pie, and now that I've run through it once I'm curious if what I did was the right answer. Mostly, my beef is that most algorithms assume that systems are pretty static and motion paths are decided well in advance. I.E. pausing, increasing speeds, accelerations, is difficult to do with most existing algorithms. It would be cool to have a more dynamic base for motion control.

How this works at the moment:

  • A Sequence Arrives (lists of points, and target speeds to be travelling between those points). These point->point segments, we call segments.
  • Using the Junction Deviation algorithm, we decide what are permissible exit and entry speeds to these segments. JD is a bit of a hack, and causes some instantaneous acceleration at junctions. It calculates permissible instantaneous acceleration using a method that 'pretends' the motors will in fact be deviating from the junction by some distance. Hence, the name.
  • Each segment then has a Max. Entry Speed, Max. Exit Speed, Total Length, and Cruise Speed (the target speed).
  • However, JD is not the whole story. We also need to determine if we can even reach those junction speeds during the length of a move. So we do a 'walk' of the queue of moves, assuming the end of the queue has an exit speed of zero. Then we work backwards, determining, with a full stop succeeding it, what the previous block's maximum exit speed is given acceleration limits. Etc. Now we have a series of moves with actual Entry and Exit Speeds, Lengths, and Cruise Speeds.
  • From here we can generate individual-axis' segments. Now we can write moves to individual steppers.

Networking Acceleration Planning

So, the algorithm we use for acceleration planning has a queue of moves at it's fundament. Basically, some lookahead has to go on. This is 'motion planning' after all. I yearn for something more dynamic, but here we are. It's almost working.

Now we have to have a scheme to deliver these segments of moves to the network. Because we'll have to link moves on potentially a 100us basis (i.e. the last step of one segment being only 100us before the first step of the next segment) and our network has a round-trip time of ~ 2ms we can't simply ping the planner at the end of each segment and ask for a new block. Welp. We need buffers.

So, each stepper motor has a queue of moves to make, I believe at the time of writing the queue is up to 32 moves long, but we typically don't need that many. So to start, we send ~ 4 moves to every motor, and when they finish one move, they reply, and we send another. This is akin to 'windowed transmission' as used in TCP/IP, but the window is around the time duration of the physics, not just the netwwork transport.

Here's a very rough cut of two axis of this just barely working.

videoo

Literal Corner Cases

  • Zero-length segments:
  • often, some axis will have moves to make, and others will not. I.E. an XY planar move with a 3-axis machine. In order to keep queues across stepper motors consistent, we need a mechanism to tell a motor to wait for a set length of time. This is implemented at the moment, and feels messy. This is part of why I think a better architecture probably exists... with some kind of global time-space.
  • Startup and Pause
  • near the end of the queue I start to see errors, probably something to do with the planner shrinking, but idk. need a better all around architecture / more organized code

A Rough Cut

Right now, this approach assumes that all clocks are identical, and that the first packets all arrive at the same time. Neither of these are true. There is also no error correction going on (anywhere) and I believe I have some decent sized bugs in my code (which is, due to the nature of the problem, splayed out across firmware, and a few mods, which are a bit of a pain to write). Going forward, I'll be bug-fixing (I think mostly these are in the maths for acceleration planning, as well as one firmware bug that causes some shaky first moves, I'm maybe not resetting a timer like I think I am).

Syncing Clocks

The algorithm works well enough for a few test cases. I'd like to add some clocking lines. To determine how well I can really do this I suppose I should measure the time it takes to get an interrupt on a clock line into and out of the system, i.e. the clock mirror that they'll run.

I should also read those papers, and try to write intelligently about this. What is the thing to demonstrate?

Stray Notes

The next things I want to do are to:

  • steps / mm: no affect?
  • steppers take axis by identifier, not array index
  • steppers should issue hello/reply after reset, to make sure they're actually resetting, not hung. in the future, cool to use clock line timeout to do this

A Better Path (get it?)

OK, I want a system that does a few things:

  • accomodates for future servo-type control
  • doesn't use hacks like wait-blocks

Starting from the assumption we're going to assert a global timespace, I think I can send:

  • 'starting at this time, with this speed, at this position, go to this position, at this exit speed, at this time' and basically fit splines on the v-t chart.